Use helmet package for HTTP security headers
The `helmet` npm package sets multiple HTTP security headers via 14 smaller middlewares. Install with `app.use(helmet())` for default configuration. Helmet covers: Strict-Transport-Security, X-Frame-Options, X-XSS-Protection, Content-Security-Policy, X-Content-Type-Options, Cache-Control/Pragma, X-Download-Options, and X-Powered-By. Each can be customized individually.
Set Strict-Transport-Security header with helmet.hsts()
HTTP Strict Transport Security (HSTS) forces browsers to use HTTPS. Enable with `app.use(helmet.hsts())` for defaults or customize: `app.use(helmet.hsts({ maxAge: 123456, includeSubDomains: false }))`. The `maxAge` parameter sets seconds before the header expires. Reference OWASP HTTP Strict Transport Security Cheat Sheet for details.
Set X-Frame-Options header to prevent Clickjacking
Use `app.use(helmet.frameguard())` to set X-Frame-Options header (default: SAMEORIGIN), which prevents pages from being loaded in `<frame>` or `<iframe>` elements and mitigates Clickjacking attacks.
Disable X-XSS-Protection header to prevent XSS Auditor issues
The X-XSS-Protection header stops pages loading when detecting reflected XSS and is deprecated in modern browsers. Using it can introduce client-side security issues. Set it to `X-XSS-Protection: 0` to disable the XSS Auditor. Use `app.use(helmet.xssFilter())` which sets this header. For modern browsers, implement a strong Content-Security-Policy instead.
Content-Security-Policy directives with helmet.contentSecurityPolicy()
Configure CSP to reduce XSS and Clickjacking risks. Use `helmet.contentSecurityPolicy({ directives: { defaultSrc: ["'self'"], scriptSrc: ["'self'"], frameAncestors: ["'none'"], imgSrc: ["'self'", "'http://imgexample.com'"], styleSrc: ["'none'"] } })`. `defaultSrc` sets default for absent directives; `scriptSrc` helps prevent XSS; `frameAncestors` prevents Clickjacking. Validate policies with CSP Evaluator. Refer to OWASP Content Security Policy Cheat Sheet.
Set X-Content-Type-Options header to prevent MIME sniffing
Use `app.use(helmet.noSniff())` to set X-Content-Type-Options header, which prevents browsers from sniffing MIME types and overriding the Content-Type header set by the server.
Disable caching for sensitive pages with nocache package
Disable browser caching for pages containing sensitive user or application information. Use the `nocache` package: `app.use(nocache())` to set Cache-Control, Surrogate-Control, Pragma, and Expires headers appropriately. Do not disable caching globally as it severely impacts performance; only disable for sensitive pages.
Set X-Download-Options header to prevent IE file execution
Use `app.use(helmet.ieNoOpen())` to set X-Download-Options header with noopen directive, which prevents Internet Explorer from executing downloaded files in the site's context.
Remove or spoof X-Powered-By header to hide technology stack
Remove the X-Powered-By header which exposes server technology and causes information leakage. Use `app.use(helmet.hidePoweredBy())` to remove it. Alternatively, spoof the header: `app.use(helmet.hidePoweredBy({ setTo: 'PHP 4.2.0' }))` to mislead attackers about technologies used.
Pinning definition: associating host with expected X509 certificate or public key
Pinning is the process of associating a host with their expected X509 certificate or public key. Once a certificate or public key is known or seen for a host, it is associated or 'pinned' to the host. If more than one certificate or public key is acceptable, the program holds a pinset. The advertised credential must match one of the elements in the pinset.
When to pin: preloading at development time is preferred
A host or service's certificate or public key can be added at development time, upon first encountering it (Trust On First Use or TOFU), or in real time via an unpinned channel. Adding at development time is preferred since preloading the certificate or public key out-of-band usually means the attacker cannot taint the pin.
Pinning recommendation: almost never pin due to outage risk
There is almost no situation where you should consider pinning. The risk of outages almost always outweighs any security risks given advances in security. If you consider pinning, you should fully understand the threat model before proceeding.
When not to pin: control, updates, disruption, and certificate predictability
Do not pin if: you don't control both the client and server side of the connection; you can't update the pinset securely; updating the pinset is disruptive such as requiring application redeployment (unless you control redeployment like forced updates in a corporation); the certificate key pair cannot be predicted in advance before it is put into service; or it is not a native mobile application.
Interception proxies and pinning exceptions: don't allow-list them
Organizations using egress filtering for Data Loss Prevention (DLP) may encounter interception proxies. Do not offer to allow-list the interception proxy since it defeats security goals. Only add the interception proxy's public key to your pinset after being instructed to do so by the folks in Risk Acceptance.
Pinning implementation method: use OnConnect callback
To pin, reuse existing protocols and infrastructure but use them in a hardened manner. Take advantage of the OnConnect callback offered by a library, framework or platform. In the callback, verify the remote host's identity by validating its certificate or public key.
What to pin: leaf certificate with backup is recommended
Pinning a leaf certificate is recommended but must include backup, such as an intermediate CA or a pinset containing alternates. This provides 100% certainty that the app exclusively trusts the remote hosts it was designed to connect to while adding resiliency for failover or certificate rotation. Pinning the root CA is generally not recommended since it increases risk by trusting all its intermediate CAs. Pinning a specific issuing or intermediate CA reduces risk but the application will trust any other certificates issued by that CA.
Pinning options: certificate, whole key, or key parameters
You must choose if you want to pin the whole certificate or just its public key. If you chose the public key, you can pin the subjectPublicKeyInfo or one of the concrete types such as RSAPublicKey or DSAPublicKey. Pinning the subjectPublicKeyInfo is recommended because it has the public parameters such as {e,n} for an RSA public key and contextual information such as algorithm and OID.
Certificate pinning: benefits and downsides
Certificate pinning benefits: it might be easier to implement than other methods, especially in languages such as Cocoa/CocoaTouch and OpenSSL. Downsides: if the site rotates its certificate on a regular basis, the application would need to be updated regularly. If you do not control when the certificate is put into service, pinning will lead to an outage.
Public key pinning: benefits and downsides
Public key pinning benefits: it allows access to public key parameters such as {e,n} for an RSA public key and contextual information such as algorithm and OID. It is more flexible than certificate pinning since the pin can be calculated long before the certificate is issued. Downsides: it can be harder to work with keys versus certificates since you must extract the key from the certificate. Some service providers generate new keys upon renewal making pre-caching impossible.
Hash-based pinning: benefits and downsides
Hash-based pinning benefits: it is convenient to use; a digested certificate fingerprint is often available as a native API for many libraries; and the hash is small and fixed length. Downsides: no access to public key parameters or contextual information such as algorithm and OID which might be needed in certain use cases. If the site rotates its certificate regularly, the application would need to be updated regularly, leading to outages.
iOS pinning: App Transport Security Settings in Info.plist
Apple suggests pinning a CA public key by specifying it in Info.plist file under App Transport Security Settings. More details are available in the article 'Identity Pinning: How to configure server certificates for your app'.
iOS pinning: TrustKit library for SSL pinning
TrustKit is an open-source SSL pinning library for iOS and macOS available at https://github.com/datatheorem/TrustKit. It provides an easy-to-use API for implementing pinning and has been deployed in many apps.
iOS pinning: avoid implementing from scratch
Implementing pinning validation from scratch on iOS should be avoided, as implementation mistakes are extremely likely and usually lead to severe vulnerabilities. Customization of SSL validation can be found in the HTTPS Server Trust Evaluation technical note.
.Net pinning: ServicePointManager for pinning implementation
.Net pinning can be achieved by using ServicePointManager. Examples can be found in the OWASP Mobile Security Testing Guide.
OpenSSL pinning: two implementation locations
Pinning with OpenSSL can occur at two places: first is the user supplied verify_callback; second is after the connection is established via SSL_get_peer_certificate. Either method will allow you to access the peer's certificate.
OpenSSL pinning: connection failure and verification checks
With OpenSSL, you must fail the connection and tear down the socket on error. By design, a server that does not supply a certificate will result in X509_V_OK with a NULL certificate. To check the result of customary verification: (1) You must call SSL_get_verify_result and verify the return code is X509_V_OK; (2) You must call SSL_get_peer_certificate and verify the certificate is non-NULL.
Electron pinning: electron-ssl-pinning library
electron-ssl-pinning is an open-source SSL pinning library for Electron based applications available at https://github.com/dialogs/electron-ssl-pinning. It provides an easy-to-use API for implementing pinning and also provides a tool for fetching configuration based on needed hosts.
Electron pinning: certificate validation via setCertificateVerifyProc
For Electron applications, you can validate certificates by yourself using ses.setCertificateVerifyProc(proc).
Pinning user interaction: do not allow bypass warnings
If your threat model warrants pinning, understand that users will click past any warnings. Do not give the user an option to proceed and bypass the pin.
Rails session store default behavior
By default, Rails uses cookie-based session storage, which does not expire on the server. This can lead to replay attacks. Sensitive information should never be stored in sessions. Use database-based session storage instead: Project::Application.config.session_store :active_record_store
Rails force SSL configuration
Enable TLS in production by setting config.force_ssl = true in config/environments/production.rb. This forces all access over SSL, uses Strict-Transport-Security header, and ensures secure cookies.
Rails CSRF protection with protect_from_forgery
Enable CSRF protection in ApplicationController with protect_from_forgery directive. Exceptions can be specified with except keyword but should be reviewed carefully. Note: CSRF protection is not required if using token authentication only; it is still required for cookie-based authentication paths.
Rails CSRF protection not applied to GET requests
By default, Rails does not provide CSRF protection for HTTP GET requests.
Rails CORS with rack-cors gem
Configure CORS in Gemfile with 'gem rack-cors'. In config/application.rb, use config.middleware.use Rack::Cors block to allowlist origins and specify allowed headers and methods. Example: allow do origins 'someserver.example.com' resource %r{/users/\d+.json}, :headers => ['Origin', 'Accept', 'Content-Type'], :methods => [:post, :get] end
Rails default security headers configuration
Set default security headers using ActionDispatch::Response.default_headers hash. Example: {'X-Frame-Options' => 'SAMEORIGIN', 'X-Content-Type-Options' => 'nosniff', 'X-XSS-Protection' => '0'}. Individual headers can be set via response.headers hash in controllers.
Rails Strict-Transport-Security configuration
Set Strict-Transport-Security header by enabling config.force_ssl = true in an environment file like config/environments/production.rb. This is handled specially and not through the default_headers mechanism.
Rails secure_headers gem for header management
Use secure_headers library for automatic security header application with content security policy abstraction. It applies logic based on user agent to produce concise header set.
HTTPS mandatory for REST APIs
Secure REST services must only provide HTTPS endpoints. HTTPS protects authentication credentials in transit including passwords, API keys, and JSON Web Tokens. It also allows clients to authenticate the service and guarantees integrity of the transmitted data.
Mutual TLS for highly privileged services
Consider the use of mutually authenticated client-side certificates to provide additional protection for highly privileged web services.
JWT integrity protection required
Ensure JWTs are integrity protected by either a signature or a MAC. Do not allow unsecured JWTs with `{"alg":"none"}`. In general, signatures should be preferred over MACs for integrity protection of JWTs.
JWT verification algorithm must not come from header
A relying party must verify the integrity of the JWT based on its own configuration or hard-coded logic. It must not rely on the information of the JWT header to select the verification algorithm. This prevents algorithm confusion attacks.
JWT standard claims to verify
At least the following standard JWT claims should be verified: `iss` (issuer - is this a trusted issuer and expected owner of the signing key?), `aud` (audience - is the relying party in the target audience?), `exp` (expiration time - is the current time before the end of the validity period?), `nbf` (not before time - is the current time after the start of the validity period?).
JWT token revocation with jti claim
When an explicit session termination event occurs, a unique, server-issued identifier (the `jti` claim, optionally combined with `aud`) should be submitted to a denylist on the API which will invalidate that JWT for any requests until the expiration of the token. This prevents disconnect between the JWT and the current state of the user's session.
Response content type must not copy Accept header
Do NOT simply copy the `Accept` header to the `Content-type` header of the response. Reject the request (ideally with a `406 Not Acceptable` response) if the `Accept` header does not specifically contain one of the allowable types.
Content type header injection defense
Ensure sending intended content type headers in your response matching your body content (e.g. `application/json` and not `application/javascript`). Services including script code in responses must be especially careful to defend against header injection attacks.
Security headers for all API responses
The following headers should be included in all API responses that may be consumed by browser clients: `Cache-Control: no-store`, `Content-Security-Policy: frame-ancestors 'none'`, `Content-Type` (matching the response content), `Strict-Transport-Security`, and `X-Content-Type-Options: nosniff`. For compatibility with older browsers, also include `X-Frame-Options: DENY`.
Cache-Control no-store header purpose
The `Cache-Control: no-store` header directs caching done by browsers to not store any response that contains this header. A browser must make a new request every time the API is called to fetch the latest response. This header prevents sensitive information from being cached or stored.
Content-Security-Policy frame-ancestors for clickjacking defense
The `Content-Security-Policy: frame-ancestors 'none'` header specifies that the response cannot be framed in `<frame>`, `<iframe>`, `<embed>` or `<object>` elements. For API responses, providing `frame-ancestors 'none'` prevents any domain from framing the response. This header protects against drag-and-drop style clickjacking attacks.
Strict-Transport-Security header for HTTPS enforcement
The `Strict-Transport-Security` header instructs a browser that the domain should only be accessed using HTTPS, and that any future attempts to access it using HTTP should automatically be converted to HTTPS. This header ensures that API calls are made over HTTPS and protects against spoofed certificates.
X-Content-Type-Options nosniff prevents MIME sniffing
The `X-Content-Type-Options: nosniff` header instructs a browser to always use the MIME type declared in the `Content-Type` header rather than trying to determine the MIME type based on the file's content. This prevents browsers from performing MIME sniffing and inappropriately interpreting responses as HTML.
X-Frame-Options DENY for legacy browser compatibility
The `X-Frame-Options: DENY` header is a legacy header superseded by `Content-Security-Policy: frame-ancestors 'none'`. It is still recommended for compatibility with older browsers that do not support CSP Level 2. Providing `DENY` prevents any domain from framing the response.
TLS 1.2 for SAML message confidentiality and integrity
TLS 1.2 is the most common solution to guarantee message confidentiality and integrity at the transport layer in SAML implementations. This counters eavesdropping, theft of user authentication information, theft of bearer tokens, message deletion, message modification, and man-in-the-middle attacks.
XML digital signature for SAML message integrity
A digitally signed message with a certified key is the most common solution to guarantee message integrity and authentication in SAML. This counters man-in-the-middle attacks, forged assertions, and message modification attacks.
StaticKeySelector for single SAML signing key
When expecting only one signing key, use StaticKeySelector. Obtain the key directly from the identity provider, store it in a local file and ignore any KeyInfo elements in the document.
X509KeySelector for multiple SAML signing keys
When expecting more than one signing key, use X509KeySelector (the JKS variant). Obtain these keys directly from the identity providers, store them in local JKS and ignore any KeyInfo elements in the document.
SAML Response caching security considerations
For HTTP POST Binding in SAML, caching considerations are critical. If a SAML protocol message gets cached, it can subsequently be used as a Stolen Assertion or Replay attack.
IP filtering as SAML countermeasure
Prefer IP filtering when appropriate. For example, this countermeasure could prevent attacks if trusted partners are provided with separate endpoints and IP filters are set up for each endpoint. This counters stolen assertion and man-in-the-middle attacks.
Short SAML Response lifetime countermeasure
Prefer short lifetimes on the SAML Response. This counters stolen assertion attacks and browser state exposure attacks.
OneTimeUse for SAML Response
Prefer OneTimeUse on the SAML Response. This counters browser state exposure attacks and replay attacks.
IdP-initiated SSO login CSRF vulnerability
Unsolicited Response (IdP-initiated SSO) is inherently less secure by design due to lack of login CSRF protection. This limitation arises because the Service Provider has no opportunity to create a pre-login session or verify that the authentication request was intentionally initiated by the user.