server_name www.domain.com;
return 301 $scheme://domain.com$request_uri;
## If you force your web traffic to use HTTPS:
## 301 https://domain.com$request_uri;
...
> `try_files` is definitely a very useful thing. You can use `try_files` directive to check a file exists in a specified order.
> You should use `try_files` instead of `if` directive. It's definitely better way than using `if` for this action because `if` directive is extremely inefficient since it is evaluated every time for every request.
> The advantage of using `try_files` is that the behavior switches immediately with one command. I think the code is more readable also.
> `try_files` allows you: > > - to check if the file exists from a predefined list > - to check if the file exists from a specified directory > - to use an internal redirect if none of the files are found
- [⬆ Hardening](https://github.com/trimstray/nginx-admins-handbook#toc-hardening-2) - [Always keep Nginx up-to-date](https://github.com/dunwu/nginx-tutorial/blob/master/docs/nginx-configuration.md#beginner-always-keep-nginx-up-to-date) - [Run as an unprivileged user](https://github.com/dunwu/nginx-tutorial/blob/master/docs/nginx-configuration.md#beginner-run-as-an-unprivileged-user) - [Disable unnecessary modules](https://github.com/dunwu/nginx-tutorial/blob/master/docs/nginx-configuration.md#beginner-disable-unnecessary-modules) - [Protect sensitive resources](https://github.com/dunwu/nginx-tutorial/blob/master/docs/nginx-configuration.md#beginner-protect-sensitive-resources) - [Hide Nginx version number](https://github.com/dunwu/nginx-tutorial/blob/master/docs/nginx-configuration.md#beginner-hide-nginx-version-number) - [Hide Nginx server signature](https://github.com/dunwu/nginx-tutorial/blob/master/docs/nginx-configuration.md#beginner-hide-nginx-server-signature) - [Hide upstream proxy headers](https://github.com/dunwu/nginx-tutorial/blob/master/docs/nginx-configuration.md#beginner-hide-upstream-proxy-headers) - [Force all connections over TLS](https://github.com/dunwu/nginx-tutorial/blob/master/docs/nginx-configuration.md#beginner-force-all-connections-over-tls) - [Use only the latest supported OpenSSL version](https://github.com/dunwu/nginx-tutorial/blob/master/docs/nginx-configuration.md#beginner-use-only-the-latest-supported-openssl-version) - [Use min. 2048-bit private keys](https://github.com/dunwu/nginx-tutorial/blob/master/docs/nginx-configuration.md#beginner-use-min-2048-bit-private-keys) - [Keep only TLS 1.3 and TLS 1.2](https://github.com/dunwu/nginx-tutorial/blob/master/docs/nginx-configuration.md#beginner-keep-only-tls-13-and-tls-12) - [Use only strong ciphers](https://github.com/dunwu/nginx-tutorial/blob/master/docs/nginx-configuration.md#beginner-use-only-strong-ciphers) - [Use more secure ECDH Curve](https://github.com/dunwu/nginx-tutorial/blob/master/docs/nginx-configuration.md#beginner-use-more-secure-ecdh-curve) - [Use strong Key Exchange with Perfect Forward Secrecy](https://github.com/dunwu/nginx-tutorial/blob/master/docs/nginx-configuration.md#beginner-use-strong-key-exchange-with-perfect-forward-secrecy) - [Prevent Replay Attacks on Zero Round-Trip Time](https://github.com/dunwu/nginx-tutorial/blob/master/docs/nginx-configuration.md#beginner-prevent-replay-attacks-on-zero-round-trip-time) - [Defend against the BEAST attack](https://github.com/dunwu/nginx-tutorial/blob/master/docs/nginx-configuration.md#beginner-defend-against-the-beast-attack) - [Mitigation of CRIME/BREACH attacks](https://github.com/dunwu/nginx-tutorial/blob/master/docs/nginx-configuration.md#beginner-mitigation-of-crimebreach-attacks) - [HTTP Strict Transport Security](https://github.com/dunwu/nginx-tutorial/blob/master/docs/nginx-configuration.md#beginner-http-strict-transport-security) - [Reduce XSS risks (Content-Security-Policy)](https://github.com/dunwu/nginx-tutorial/blob/master/docs/nginx-configuration.md#beginner-reduce-xss-risks-content-security-policy) - [Control the behaviour of the Referer header (Referrer-Policy)](https://github.com/dunwu/nginx-tutorial/blob/master/docs/nginx-configuration.md#beginner-control-the-behaviour-of-the-referer-header-referrer-policy) - [Provide clickjacking protection (X-Frame-Options)](https://github.com/dunwu/nginx-tutorial/blob/master/docs/nginx-configuration.md#beginner-provide-clickjacking-protection-x-frame-options) - [Prevent some categories of XSS attacks (X-XSS-Protection)](https://github.com/dunwu/nginx-tutorial/blob/master/docs/nginx-configuration.md#beginner-prevent-some-categories-of-xss-attacks-x-xss-protection) - [Prevent Sniff Mimetype middleware (X-Content-Type-Options)](https://github.com/dunwu/nginx-tutorial/blob/master/docs/nginx-configuration.md#beginner-prevent-sniff-mimetype-middleware-x-content-type-options) - [Deny the use of browser features (Feature-Policy)](https://github.com/dunwu/nginx-tutorial/blob/master/docs/nginx-configuration.md#beginner-deny-the-use-of-browser-features-feature-policy) - [Reject unsafe HTTP methods](https://github.com/dunwu/nginx-tutorial/blob/master/docs/nginx-configuration.md#beginner-reject-unsafe-http-methods) - [Prevent caching of sensitive data](https://github.com/dunwu/nginx-tutorial/blob/master/docs/nginx-configuration.md#beginner-prevent-caching-of-sensitive-data) - [Control Buffer Overflow attacks](https://github.com/dunwu/nginx-tutorial/blob/master/docs/nginx-configuration.md#beginner-control-buffer-overflow-attacks) - [Mitigating Slow HTTP DoS attacks (Closing Slow Connections)](https://github.com/dunwu/nginx-tutorial/blob/master/docs/nginx-configuration.md#beginner-mitigating-slow-http-dos-attacks-closing-slow-connections)
In this chapter I will talk about some of the Nginx hardening approaches and security standards.
### 🔰 Always keep Nginx up-to-date
#### Rationale
> Nginx is a very secure and stable but vulnerabilities in the main binary itself do pop up from time to time. It's the main reason for keep Nginx up-to-date as hard as you can.
> A very safe way to plan the update is once a new stable version is released but for me the most common way to handle Nginx updates is to wait a few weeks after the stable release.
> Before update/upgrade Nginx remember about do it on the testing environment.
> Most modern GNU/Linux distros will not push the latest version of Nginx into their default package lists so maybe you should consider install it from sources.
#### External resources
- [Installing from prebuilt packages (from this handbook)](https://github.com/dunwu/nginx-tutorial/blob/master/docs/HELPERS.md#installing-from-prebuilt-packages) - [Installing from source (from this handbook)](https://github.com/dunwu/nginx-tutorial/blob/master/docs/HELPERS.md#installing-from-source)
### 🔰 Run as an unprivileged user
#### Rationale
> There is no real difference in security just by changing the process owner name. On the other hand in security, the principle of least privilege states that an entity should be given no more permission than necessary to accomplish its goals within a given system. This way only master process runs as root.
> This is the default Nginx behaviour, but remember to check it.
#### Example
Edit nginx.conf:
user nginx;
Set owner and group for root (app, default) directory:
- [Why does nginx starts process as root?](https://unix.stackexchange.com/questions/134301/why-does-nginx-starts-process-as-root)
### 🔰 Disable unnecessary modules
#### Rationale
> It is recommended to disable any modules which are not required as this will minimise the risk of any potential attacks by limiting the operations allowed by the web server.
> The best way to unload unused modules is use the `configure` option during installation. If you have static linking a shared module you should re-compile Nginx.
> Use only high quality modules and remember about that: > > *Unfortunately, many third‑party modules use blocking calls, and users (and sometimes even the developers of the modules) aren’t aware of the drawbacks. Blocking operations can ruin Nginx performance and must be avoided at all costs.*
#### Example
1) During installation:
./configure –without-http_autoindex_module
2) Comment modules in the configuration file e.g. modules.conf:
> Hidden directories and files should never be web accessible - sometimes critical data are published during application deploy. If you use control version system you should defninitely drop the access to the critical hidden directories like a `.git` or `.svn` to prevent expose source code of your application.
> Sensitive resources contains items that abusers can use to fully recreate the source code used by the site and look for bugs, vulnerabilities, and exposed passwords.
- [Hidden directories and files as a source of sensitive information about web application](https://github.com/bl4de/research/tree/master/hidden_directories_leaks)
### 🔰 Hide Nginx version number
#### Rationale
> Disclosing the version of Nginx running can be undesirable, particularly in environments sensitive to information disclosure.
But the "Official Apache Documentation (Apache Core Features)" (yep, it's not a joke...) say:
> *Setting ServerTokens to less than minimal is not recommended because it makes it more difficult to debug interoperational problems. Also note that disabling the Server: header does nothing at all to make your server more secure. The idea of "security through obscurity" is a myth and leads to a false sense of safety.*
- [Remove Version from Server Header Banner in nginx](https://geekflare.com/remove-server-header-banner-nginx/) - [Reduce or remove server headers](https://www.tunetheweb.com/security/http-security-headers/server-header/)
### 🔰 Hide Nginx server signature
#### Rationale
> One of the easiest first steps to undertake, is to prevent the web server from showing its used software via the server header. Certainly, there are several reasons why you would like to change the server header. It could be security, it could be redundant systems, load balancers etc.
> In my opinion there is no real reason or need to show this much information about your server. It is easy to look up particular vulnerabilities once you know the version number.
> You should compile Nginx from sources with `ngx_headers_more` to used `more_set_headers` directive or use a [nginx-remove-server-header.patch](https://gitlab.com/buik/nginx/blob/master/nginx-remove-server-header.patch).
- [Shhh... don’t let your response headers talk too loudly](https://www.troyhunt.com/shhh-dont-let-your-response-headers/) - [How to change (hide) the Nginx Server Signature?](https://stackoverflow.com/questions/24594971/how-to-changehide-the-nginx-server-signature)
### 🔰 Hide upstream proxy headers
#### Rationale
> Securing a server goes far beyond not showing what's running but I think less is more is better.
> When Nginx is used to proxy requests to an upstream server (such as a PHP-FPM instance), it can be beneficial to hide certain headers sent in the upstream response (e.g. the version of PHP running).
> TLS provides two main services. For one, it validates the identity of the server that the user is connecting to for the user. It also protects the transmission of sensitive information from the user to the server.
> In my opinion you should always use HTTPS instead of HTTP to protect your website, even if it doesn’t handle sensitive communications. The application can have many sensitive places that should be protected.
> Always put login page, registration forms, all subsequent authenticated pages, contact forms, and payment details forms in HTTPS to prevent injection and sniffing. Them must be accessed only over TLS to ensure your traffic is secure.
> If page is available over TLS, it must be composed completely of content which is transmitted over TLS. Requesting subresources using the insecure HTTP protocol weakens the security of the entire page and HTTPS protocol. Modern browsers should blocked or report all active mixed content delivered via HTTP on pages by default.
> Also remember to implement the [HTTP Strict Transport Security (HSTS)](https://github.com/dunwu/nginx-tutorial/blob/master/docs/nginx-configuration.md#beginner-http-strict-transport-security).
> We have currently the first free and open CA - [Let's Encrypt](https://letsencrypt.org/) - so generating and implementing certificates has never been so easy. It was created to provide free and easy-to-use TLS and SSL certificates.
- [Should we force user to HTTPS on website?](https://security.stackexchange.com/questions/23646/should-we-force-user-to-https-on-website) - [Force a user to HTTPS](https://security.stackexchange.com/questions/137542/force-a-user-to-https) - [Let's Encrypt Documentation](https://letsencrypt.org/docs/)
### 🔰 Use only the latest supported OpenSSL version
#### Rationale
> Before start see [Release Strategy Policies](https://www.openssl.org/policies/releasestrat.html) and [Changelog](https://www.openssl.org/news/changelog.html) on the OpenSSL website.
> Criteria for choosing OpenSSL version can vary and it depends all on your use.
> The latest versions of the major OpenSSL library are (may be changed): > > - the next version of OpenSSL will be 3.0.0 > - version 1.1.1 will be supported until 2023-09-11 (LTS) > - last minor version: 1.1.1c (May 23, 2019) > - version 1.1.0 will be supported until 2019-09-11 > - last minor version: 1.1.0k (May 28, 2018) > - version 1.0.2 will be supported until 2019-12-31 (LTS) > - last minor version: 1.0.2s (May 28, 2018) > - any other versions are no longer supported
> In my opinion the only safe way is based on the up-to-date and still supported version of the OpenSSL. And what's more, I recommend to hang on to the latest versions (e.g. 1.1.1).
> If your system repositories do not have the newest OpenSSL, you can do the [compilation](https://github.com/trimstray/nginx-admins-handbook#installing-from-source) process (see OpenSSL sub-section).
#### External resources
- [OpenSSL Official Website](https://www.openssl.org/) - [OpenSSL Official Blog](https://www.openssl.org/blog/) - [OpenSSL Official Newslog](https://www.openssl.org/news/newslog.html)
### 🔰 Use min. 2048-bit private keys
#### Rationale
> Advisories recommend 2048 for now. Security experts are projecting that 2048 bits will be sufficient for commercial use until around the year 2030 (as per NIST).
> The latest version of FIPS-186 also say the U.S. Federal Government generate (and use) digital signatures with 1024, 2048, or 3072 bit key lengths.
> Generally there is no compelling reason to choose 4096 bit keys over 2048 provided you use sane expiration intervals.
> If you want to get **A+ with 100%s on SSL Lab** (for Key Exchange) you should definitely use 4096 bit private keys. That's the main reason why you should use them.
> Longer keys take more time to generate and require more CPU and power when used for encrypting and decrypting, also the SSL handshake at the start of each connection will be slower. It also has a small impact on the client side (e.g. browsers).
> You can test above on your server with `openssl speed rsa` but remember: in OpenSSL speed tests you see difference on block cipher speed, while in real life most cpu time is spent on asymmetric algorithms during ssl handshake. On the other hand, modern processors are capable of executing at least 1k of RSA 1024-bit signs per second on a single core, so this isn't usually an issue.
> Use of alternative solution: [ECC Certificate Signing Request (CSR)](https://en.wikipedia.org/wiki/Elliptic-curve_cryptography) - `ECDSA` certificates contain an `ECC` public key. `ECC` keys are better than `RSA & DSA` keys in that the `ECC` algorithm is harder to break.
The "SSL/TLS Deployment Best Practices" book say:
> *The cryptographic handshake, which is used to establish secure connections, is an operation whose cost is highly influenced by private key size. Using a key that is too short is insecure, but using a key that is too long will result in "too much" security and slow operation. For most web sites, using RSA keys stronger than 2048 bits and ECDSA keys stronger than 256 bits is a waste of CPU power and might impair user experience. Similarly, there is little benefit to increasing the strength of the ephemeral key exchange beyond 2048 bits for DHE and 256 bits for ECDHE.*
Konstantin Ryabitsev (Reddit):
> *Generally speaking, if we ever find ourselves in a world where 2048-bit keys are no longer good enough, it won't be because of improvements in brute-force capabilities of current computers, but because RSA will be made obsolete as a technology due to revolutionary computing advances. If that ever happens, 3072 or 4096 bits won't make much of a difference anyway. This is why anything above 2048 bits is generally regarded as a sort of feel-good hedging theatre.*
**My recommendation:**
> Use 2048-bit key instead of 4096-bit at this moment.
- [Key Management Guidelines by NIST](https://csrc.nist.gov/Projects/Key-Management/Key-Management-Guidelines) - [Recommendation for Transitioning the Use of Cryptographic Algorithms and Key Lengths](https://csrc.nist.gov/publications/detail/sp/800-131a/archive/2011-01-13) - [FIPS PUB 186-4 - Digital Signature Standard (DSS)](http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf) [pdf] - [Cryptographic Key Length Recommendations](https://www.keylength.com/) - [So you're making an RSA key for an HTTPS certificate. What key size do you use?](https://certsimple.com/blog/measuring-ssl-rsa-keys) - [RSA Key Sizes: 2048 or 4096 bits?](https://danielpocock.com/rsa-key-sizes-2048-or-4096-bits/) - [Create a self-signed ECC certificate](https://msol.io/blog/tech/create-a-self-signed-ecc-certificate/)
### 🔰 Keep only TLS 1.3 and TLS 1.2
#### Rationale
> It is recommended to run TLS 1.2/1.3 and fully disable SSLv2, SSLv3, TLS 1.0 and TLS 1.1 that have protocol weaknesses and uses older cipher suites (do not provide any modern ciper modes).
> TLS 1.0 and TLS 1.1 must not be used (see [Deprecating TLSv1.0 and TLSv1.1](https://tools.ietf.org/id/draft-moriarty-tls-oldversions-diediedie-00.html)) and were superceded by TLS 1.2, which has now itself been superceded by TLS 1.3. They are also actively being deprecated in accordance with guidance from government agencies (e.g. NIST SP 80052r2) and industry consortia such as the Payment Card Industry Association (PCI) [PCI-TLS1].
> TLS 1.2 and TLS 1.3 are both without security issues. Only these versions provides modern cryptographic algorithms. TLS 1.3 is a new TLS version that will power a faster and more secure web for the next few years. What's more, TLS 1.3 comes without a ton of stuff (was removed): renegotiation, compression, and many legacy algorithms: `DSA`, `RC4`, `SHA1`, `MD5`, `CBC` MAC-then-Encrypt ciphers. TLS 1.0 and TLS 1.1 protocols will be removed from browsers at the beginning of 2020.
> TLS 1.2 does require careful configuration to ensure obsolete cipher suites with identified vulnerabilities are not used in conjunction with it. TLS 1.3 removes the need to make these decisions. TLS 1.3 version also improves TLS 1.2 security, privace and performance issues.
> Before enabling specific protocol version, you should check which ciphers are supported by the protocol. So if you turn on TLS 1.2 and TLS 1.3 both remember about [the correct (and strong)](https://github.com/dunwu/nginx-tutorial/blob/master/docs/nginx-configuration.md#beginner-use-only-strong-ciphers) ciphers to handle them. Otherwise, they will not be anyway works without supported ciphers (no TLS handshake will succeed).
> I think the best way to deploy secure configuration is: enable TLS 1.2 without any `CBC` Ciphers (is safe enough) only TLS 1.3 is safer because of its handling improvement and the exclusion of everything that went obsolete since TLS 1.2 came up.
> If you told Nginx to use TLS 1.3, it will use TLS 1.3 only where is available. Nginx supports TLS 1.3 since version 1.13.0 (released in April 2017), when built against OpenSSL 1.1.1 or more.
> For TLS 1.3, think about using [`ssl_early_data`](https://github.com/dunwu/nginx-tutorial/blob/master/docs/nginx-configuration.md#beginner-prevent-replay-attacks-on-zero-round-trip-time) to allow TLS 1.3 0-RTT handshakes.
**My recommendation:**
> Use only [TLSv1.3 and TLSv1.2](https://github.com/dunwu/nginx-tutorial/blob/master/docs/nginx-configuration.md#keep-only-tls1.2-tls13).
- [The Transport Layer Security (TLS) Protocol Version 1.2](https://www.ietf.org/rfc/rfc5246.txt) - [The Transport Layer Security (TLS) Protocol Version 1.3](https://tools.ietf.org/html/draft-ietf-tls-tls13-18) - [TLS1.2 - Every byte explained and reproduced](https://tls12.ulfheim.net/) - [TLS1.3 - Every byte explained and reproduced](https://tls13.ulfheim.net/) - [TLS1.3 - OpenSSLWiki](https://wiki.openssl.org/index.php/TLS1.3) - [TLS v1.2 handshake overview](https://medium.com/@ethicalevil/tls-handshake-protocol-overview-a39e8eee2cf5) - [An Overview of TLS 1.3 - Faster and More Secure](https://kinsta.com/blog/tls-1-3/) - [A Detailed Look at RFC 8446 (a.k.a. TLS 1.3)](https://blog.cloudflare.com/rfc-8446-aka-tls-1-3/) - [Differences between TLS 1.2 and TLS 1.3](https://www.wolfssl.com/differences-between-tls-1-2-and-tls-1-3/) - [TLS 1.3 in a nutshell](https://assured.se/2018/08/29/tls-1-3-in-a-nut-shell/) - [TLS 1.3 is here to stay](https://www.ssl.com/article/tls-1-3-is-here-to-stay/) - [How to enable TLS 1.3 on Nginx](https://ma.ttias.be/enable-tls-1-3-nginx/) - [How to deploy modern TLS in 2019?](https://blog.probely.com/how-to-deploy-modern-tls-in-2018-1b9a9cafc454) - [Deploying TLS 1.3: the great, the good and the bad](https://media.ccc.de/v/33c3-8348-deploying_tls_1_3_the_great_the_good_and_the_bad) - [Downgrade Attack on TLS 1.3 and Vulnerabilities in Major TLS Libraries](https://www.nccgroup.trust/us/about-us/newsroom-and-events/blog/2019/february/downgrade-attack-on-tls-1.3-and-vulnerabilities-in-major-tls-libraries/) - [Phase two of our TLS 1.0 and 1.1 deprecation plan](https://www.fastly.com/blog/phase-two-our-tls-10-and-11-deprecation-plan) - [Deprecating TLS 1.0 and 1.1 - Enhancing Security for Everyone](https://www.keycdn.com/blog/deprecating-tls-1-0-and-1-1) - [TLS/SSL Explained – Examples of a TLS Vulnerability and Attack, Final Part](https://www.acunetix.com/blog/articles/tls-vulnerabilities-attacks-final-part/) - [This POODLE bites: exploiting the SSL 3.0 fallback](https://security.googleblog.com/2014/10/this-poodle-bites-exploiting-ssl-30.html) - [Are You Ready for 30 June 2018? Saying Goodbye to SSL/early TLS](https://blog.pcisecuritystandards.org/are-you-ready-for-30-june-2018-sayin-goodbye-to-ssl-early-tls) - [Deprecating TLSv1.0 and TLSv1.1](https://tools.ietf.org/id/draft-moriarty-tls-oldversions-diediedie-00.html)
### 🔰 Use only strong ciphers
#### Rationale
> This parameter changes quite often, the recommended configuration for today may be out of date tomorrow.
> To check ciphers supported by OpenSSL on your server: `openssl ciphers -s -v`, `openssl ciphers -s -v ECDHE` or `openssl ciphers -s -v DHE`.
> For more security use only strong and not vulnerable cipher suites. Place `ECDHE` and `DHE` suites at the top of your list. The order is important because `ECDHE` suites are faster, you want to use them whenever clients supports them. Ephemeral `DHE/ECDHE` are recommended and support Perfect Forward Secrecy.
> For backward compatibility software components you should use less restrictive ciphers. Not only that you have to enable at least one special `AES128` cipher for HTTP/2 support regarding to [RFC7540: TLS 1.2 Cipher Suites](https://tools.ietf.org/html/rfc7540#section-9.2.2), you also have to allow `prime256` elliptic curves which reduces the score for key exchange by another 10% even if a secure server preferred order is set.
> Also modern cipher suites (e.g. from Mozilla recommendations) suffers from compatibility troubles mainly because drops `SHA-1`. But be careful if you want to use ciphers with `HMAC-SHA-1` - there's a perfectly good [explanation](https://crypto.stackexchange.com/a/26518) why.
> If you want to get **A+ with 100%s on SSL Lab** (for Cipher Strength) you should definitely disable `128-bit` ciphers. That's the main reason why you should not use them.
> In my opinion `128-bit` symmetric encryption doesn’t less secure. Moreover, there are about 30% faster and still secure. For example TLS 1.3 use `TLS_AES_128_GCM_SHA256 (0x1301)` (for TLS-compliant applications).
> It is not possible to control ciphers for TLS 1.3 without support from client to use new API for TLS 1.3 cipher suites. Nginx isn't able to influence that so at this moment it's always on (also if you disable potentially weak cipher from Nginx). On the other hand the ciphers in TLSv1.3 have been restricted to only a handful of completely secure ciphers by leading crypto experts.
> For TLS 1.2 you should consider disable weak ciphers without forward secrecy like ciphers with `CBC` algorithm. Using them also reduces the final grade because they don't use ephemeral keys. In my opinion you should use ciphers with `AEAD` (TLS 1.3 supports only these suites) encryption because they don't have any known weaknesses.
> Recently new vulnerabilities like Zombie POODLE, GOLDENDOODLE, 0-Length OpenSSL and Sleeping POODLE were published for websites that use `CBC` (Cipher Block Chaining) block cipher modes. These vulnerabilities are applicable only if the server uses TLS 1.2 or TLS 1.1 or TLS 1.0 with `CBC` cipher modes. Look at [Zombie POODLE, GOLDENDOODLE, & How TLSv1.3 Can Save Us All](https://i.blackhat.com/asia-19/Fri-March-29/bh-asia-Young-Zombie-Poodle-Goldendoodle-and-How-TLSv13-Can-Save-Us-All.pdf) presentation from Black Hat Asia 2019.
> Disable TLS cipher modes (all ciphers that start with `TLS_RSA_WITH_*`) that use RSA encryption because they are vulnerable to [ROBOT](https://robotattack.org/) attack. Not all servers that support RSA key exchange are vulnerable, but it is recommended to disable RSA key exchange ciphers as it does not support forward secrecy.
> You should also absolutely disable weak ciphers regardless of the TLS version do you use, like those with `DSS`, `DSA`, `DES/3DES`, `RC4`, `MD5`, `SHA1`, `null`, anon in the name.
> We have a nice online tool for testing compatibility cipher suites with user agents: [CryptCheck](https://cryptcheck.fr/suite/). I think it will be very helpful for you.
**My recommendation:**
> Use only [TLSv1.3 and TLSv1.2](https://github.com/dunwu/nginx-tutorial/blob/master/docs/nginx-configuration.md#keep-only-tls1.2-tls13) with below cipher suites:
This will also give a baseline for comparison with [Mozilla SSL Configuration Generator](https://mozilla.github.io/server-side-tls/ssl-config-generator/):
- [RFC 7525 - TLS Recommendations](https://tools.ietf.org/html/rfc7525) - [TLS Cipher Suites](https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-4) - [SSL/TLS: How to choose your cipher suite](https://technology.amis.nl/2017/07/04/ssltls-choose-cipher-suite/) - [HTTP/2 and ECDSA Cipher Suites](https://sparanoid.com/note/http2-and-ecdsa-cipher-suites/) - [Which SSL/TLS Protocol Versions and Cipher Suites Should I Use?](https://www.securityevaluators.com/ssl-tls-protocol-versions-cipher-suites-use/) - [Recommendations for a cipher string by OWASP](https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/TLS_Cipher_String_Cheat_Sheet.md) - [Recommendations for TLS/SSL Cipher Hardening by Acunetix](https://www.acunetix.com/blog/articles/tls-ssl-cipher-hardening/) - [Mozilla’s Modern compatibility suite](https://wiki.mozilla.org/Security/Server_Side_TLS#Modern_compatibility) - [Why use Ephemeral Diffie-Hellman](https://tls.mbed.org/kb/cryptography/ephemeral-diffie-hellman) - [Cipher Suite Breakdown](https://blogs.technet.microsoft.com/askpfeplat/2017/12/26/cipher-suite-breakdown/) - [Zombie POODLE and GOLDENDOODLE Vulnerabilities](https://blog.qualys.com/technology/2019/04/22/zombie-poodle-and-goldendoodle-vulnerabilities) - [OpenSSL IANA Mapping](https://testssl.sh/openssl-iana.mapping.html) - [Goodbye TLS_RSA](https://lightshipsec.com/goodbye-tls_rsa/)
### 🔰 Use more secure ECDH Curve
#### Rationale
> In my opinion your main source of knowledge should be [The SafeCurves web site](https://safecurves.cr.yp.to/). This site reports security assessments of various specific curves.
> For a SSL server certificate, an "elliptic curve" certificate will be used only with digital signatures (`ECDSA` algorithm). Nginx provides directive to specifies a curve for `ECDHE` ciphers.
> `x25519` is a more secure (also with SafeCurves requirements) but slightly less compatible option. I think to maximise interoperability with existing browsers and servers, stick to `P-256 prime256v1` and `P-384 secp384r1` curves. Of course there's tons of different opinions about `P-256` and `P-384` curves.
> NSA Suite B says that NSA uses curves `P-256` and `P-384` (in OpenSSL, they are designated as, respectively, `prime256v1` and `secp384r1`). There is nothing wrong with `P-521`, except that it is, in practice, useless. Arguably, `P-384` is also useless, because the more efficient `P-256` curve already provides security that cannot be broken through accumulation of computing power.
> Bernstein and Lange believe that the NIST curves are not optimal and there are better (more secure) curves that work just as fast, e.g. `x25519`.
> Keep an eye also on this: > > *Secure implementations of the standard curves are theoretically possible but very hard.* > > The SafeCurves say: > > - `NIST P-224`, `NIST P-256` and `NIST P-384` are UNSAFE > > From the curves described here only `x25519` is a curve meets all SafeCurves requirements.
> I think you can use `P-256` to minimise trouble. If you feel that your manhood is threatened by using a 256-bit curve where a 384-bit curve is available, then use `P-384`: it will increases your computational and network costs.
> If you use TLS 1.3 you should enable `prime256v1` signature algorithm. Without this SSL Lab reports `TLS_AES_128_GCM_SHA256 (0x1301)` signature as weak.
> If you do not set `ssl_ecdh_curve`, then Nginx will use its default settings, e.g. Chrome will prefer `x25519`, but it is **not recommended** because you can not control default settings (seems to be `P-256`) from the Nginx.
> Explicitly set `ssl_ecdh_curve X25519:prime256v1:secp521r1:secp384r1;` **decreases the Key Exchange SSL Labs rating**.
> Definitely do not use the `secp112r1`, `secp112r2`, `secp128r1`, `secp128r2`, `secp160k1`, `secp160r1`, `secp160r2`, `secp192k1` curves. They have a too small size for security application according to NIST recommendation.
**My recommendation:**
> Use only [TLSv1.3 and TLSv1.2](https://github.com/dunwu/nginx-tutorial/blob/master/docs/nginx-configuration.md#keep-only-tls1.2-tls13) and [only strong ciphers](https://github.com/dunwu/nginx-tutorial/blob/master/docs/nginx-configuration.md#use-only-strong-ciphers) with above curves:
- [Elliptic Curves for Security](https://tools.ietf.org/html/rfc7748) - [Standards for Efficient Cryptography Group](http://www.secg.org/) - [SafeCurves: choosing safe curves for elliptic-curve cryptography](https://safecurves.cr.yp.to/) - [A note on high-security general-purpose elliptic curves](https://eprint.iacr.org/2013/647) - [P-521 is pretty nice prime](https://blog.cr.yp.to/20140323-ecdsa.html) - [Safe ECC curves for HTTPS are coming sooner than you think](https://certsimple.com/blog/safe-curves-and-openssl) - [Cryptographic Key Length Recommendations](https://www.keylength.com/) - [Testing for Weak SSL/TLS Ciphers, Insufficient Transport Layer Protection (OTG-CRYPST-001)](https://www.owasp.org/index.php/Testing_for_Weak_SSL/TLS_Ciphers,_Insufficient_Transport_Layer_Protection_(OTG-CRYPST-001)) - [Elliptic Curve performance: NIST vs Brainpool](https://tls.mbed.org/kb/cryptography/elliptic-curve-performance-nist-vs-brainpool) - [Which elliptic curve should I use?](https://security.stackexchange.com/questions/78621/which-elliptic-curve-should-i-use/91562) - [Elliptic Curve Cryptography for those who are afraid of maths](http://www.lapsedordinary.net/files/ECC_BSidesLDN_2015.pdf)
### 🔰 Use strong Key Exchange with Perfect Forward Secrecy
#### Rationale
> To use a signature based authentication you need some kind of DH exchange (fixed or ephemeral/temporary), to exchange the session key. If you use it, Nginx will use the default Ephemeral Diffie-Hellman (`DHE`) paramaters to define how performs the Diffie-Hellman (DH) key-exchange. This uses a weak key (by default: `1024 bit`) that gets lower scores.
> You should always use the Elliptic Curve Diffie Hellman Ephemeral (`ECDHE`). Due to increasing concern about pervasive surveillance, key exchanges that provide Forward Secrecy are recommended, see for example [RFC 7525](https://tools.ietf.org/html/rfc7525#section-6.3).
> For greater compatibility but still for security in key exchange, you should prefer the latter E (ephemeral) over the former E (EC). There is recommended configuration: `ECDHE` > `DHE` (with min. `2048 bit` size) > `ECDH`. With this if the initial handshake fails, another handshake will be initiated using `DHE`.
> `DHE` is slower than `ECDHE`. If you are concerned about performance, prioritize `ECDHE-ECDSA` over `DHE`. OWASP estimates that the TLS handshake with `DHE` hinders the CPU by a factor of 2.4 compared to `ECDHE`.
> Diffie-Hellman requires some set-up parameters to begin with. Parameters from `ssl_dhparam` (which are generated with `openssl dhparam ...`) define how OpenSSL performs the Diffie-Hellman (DH) key-exchange. They include a field prime `p` and a generator `g`. The purpose of the availability to customize these parameter is to allow everyone to use own parameters for this. This can be used to prevent being affected from the Logjam attack.
> Modern clients prefer `ECDHE` instead other variants and if your Nginx accepts this preference then the handshake will not use the DH param at all since it will not do a `DHE` key exchange but an `ECDHE` key exchange. Thus, if no plain `DH/DHE` ciphers are configured at your server but only Eliptic curve DH (e.g. `ECDHE`) then you don't need to set your own `ssl_dhparam` directive. Enabling `DHE` requires us to take care of our DH primes (a.k.a. `dhparams`) and to trust in `DHE`.
> Elliptic curve Diffie-Hellman is a modified Diffie-Hellman exchange which uses Elliptic curve cryptography instead of the traditional RSA-style large primes. So while I'm not sure what parameters it may need (if any), I don't think it needs the kind you're generating (`ECDH` is based on curves, not primes, so I don't think the traditional DH params will do you any good).
> Cipher suites using `DHE` key exchange in OpenSSL require `tmp_DH` parameters, which the `ssl_dhparam` directive provides. The same is true for `DH_anon` key exchange, but in practice nobody uses those. The OpenSSL wiki page for Diffie Hellman Parameters it says: *To use perfect forward secrecy cipher suites, you must set up Diffie-Hellman parameters (on the server side).* Look also at [SSL_CTX_set_tmp_dh_callback](https://www.openssl.org/docs/man1.0.2/man3/SSL_CTX_set_tmp_dh.html).
> If you use `ECDH/ECDHE` key exchange please see [Use more secure ECDH Curve](https://github.com/dunwu/nginx-tutorial/blob/master/docs/nginx-configuration.md#beginner-use-more-secure-ecdh-curve) rule.
> Default key size in OpenSSL is `1024 bits` - it's vulnerable and breakable. For the best security configuration use your own DH Group (min. `2048 bit`) or use known safe ones pre-defined DH groups (it's recommended) from the [Mozilla](https://wiki.mozilla.org/Security/Server_Side_TLS#ffdhe4096).
> The `2048 bit` is generally expected to be safe and is already very far into the "cannot break it zone". However years ago people expected 1024 bit to be safe so if you are after long term resistance You would go up to `4096 bit` (for both RSA keys and DH parameters). It's also important if you want to get 100% on Key Exchange of the SSL Labs test.
> You should remember that the `4096 bit` modulus will make DH computations slower and won’t actually improve security.
There is [good explanation](https://security.stackexchange.com/questions/47204/dh-parameters-recommended-size/47207#47207) about DH parameters recommended size:
> *Current recommendations from various bodies (including NIST) call for a `2048-bit` modulus for DH. Known DH-breaking algorithms would have a cost so ludicrously high that they could not be run to completion with known Earth-based technology. See this site for pointers on that subject.*
> *You don't want to overdo the size because the computational usage cost rises relatively sharply with prime size (somewhere between quadratic and cubic, depending on some implementation details) but a `2048-bit` DH ought to be fine (a basic low-end PC can do several hundreds of `2048-bit` DH per second).*
Look also at this answer by [Matt Palmer](https://www.hezmatt.org/~mpalmer/blog/):
> *Indeed, characterising `2048 bit` DH parameters as "weak as hell" is quite misleading. There are no known feasible cryptographic attacks against arbitrary strong 2048 bit DH groups. To protect against future disclosure of a session key due to breaking DH, sure, you want your DH parameters to be as long as is practical, but since `1024 bit` DH is only just getting feasible, `2048 bits` should be OK for most purposes for a while yet.*
**My recommendation:**
> If you use only TLS 1.3 - `ssl_dhparam` is not required (not used). Also, if you use `ECDHE/ECDH` - `ssl_dhparam` is not required (not used). If you use `DHE/DH` - `ssl_dhparam` with DH parameters is required (min. `2048 bit`). By default no parameters are set, and therefore `DHE` ciphers will not be used.
- [Weak Diffie-Hellman and the Logjam Attack](https://weakdh.org/) - [Guide to Deploying Diffie-Hellman for TLS](https://weakdh.org/sysadmin.html) - [Pre-defined DHE groups](https://wiki.mozilla.org/Security/Server_Side_TLS#ffdhe4096) - [Instructs OpenSSL to produce "DSA-like" DH parameters](https://security.stackexchange.com/questions/95178/diffie-hellman-parameters-still-calculating-after-24-hours/95184#95184) - [OpenSSL generate different types of self signed certificate](https://security.stackexchange.com/questions/44251/openssl-generate-different-types-of-self-signed-certificate) - [Public Diffie-Hellman Parameter Service/Tool](https://2ton.com.au/dhtool/) - [Vincent Bernat's SSL/TLS & Perfect Forward Secrecy](http://vincent.bernat.im/en/blog/2011-ssl-perfect-forward-secrecy.html) - [RSA and ECDSA performance](https://securitypitfalls.wordpress.com/2014/10/06/rsa-and-ecdsa-performance/) - [SSL/TLS: How to choose your cipher suite](https://technology.amis.nl/2017/07/04/ssltls-choose-cipher-suite/) - [Diffie-Hellman and its TLS/SSL usage](https://security.stackexchange.com/questions/41205/diffie-hellman-and-its-tls-ssl-usage)
### 🔰 Prevent Replay Attacks on Zero Round-Trip Time
#### Rationale
> This rules is only important for TLS 1.3. By default enabling TLS 1.3 will not enable 0-RTT support. After all, you should be fully aware of all the potential exposure factors and related risks with the use of this option.
> 0-RTT Handshakes is part of the replacement of TLS Session Resumption and was inspired by the QUIC Protocol.
> 0-RTT creates a significant security risk. With 0-RTT, a threat actor can intercept an encrypted client message and resend it to the server, tricking the server into improperly extending trust to the threat actor and thus potentially granting the threat actor access to sensitive data.
> On the other hand, including 0-RTT (Zero Round Trip Time Resumption) results in a significant increase in efficiency and connection times. TLS 1.3 has a faster handshake that completes in 1-RTT. Additionally, it has a particular session resumption mode where, under certain conditions, it is possible to send data to the server on the first flight (0-RTT).
> For example, Cloudflare only supports 0-RTT for [GET requests with no query parameters](https://new.blog.cloudflare.com/introducing-0-rtt/) in an attempt to limit the attack surface. Moreover, in order to improve identify connection resumption attempts, they relay this information to the origin by adding an extra header to 0-RTT requests. This header uniquely identifies the request, so if one gets repeated, the origin will know it's a replay attack (the application needs to track values received from that and reject duplicates on non-idempotent endpoints).
> To protect against such attacks at the application layer, the `$ssl_early_data` variable should be used. You'll also need to ensure that the `Early-Data` header is passed to your application. `$ssl_early_data` returns 1 if TLS 1.3 early data is used and the handshake is not complete.
> However, as part of the upgrade, you should disable 0-RTT until you can audit your application for this class of vulnerability.
> In order to send early-data, client and server [must support PSK exchange mode](https://tools.ietf.org/html/rfc8446#section-2.3) (session cookies).
> In addition, I would like to recommend [this](https://news.ycombinator.com/item?id=16667036) great discussion about TLS 1.3 and 0-RTT.
If you are unsure to enable 0-RTT, look what Cloudflare say about it:
> *Generally speaking, 0-RTT is safe for most web sites and applications. If your web application does strange things and you’re concerned about its replay safety, consider not using 0-RTT until you can be certain that there are no negative effects. [...] TLS 1.3 is a big step forward for web performance and security. By combining TLS 1.3 with 0-RTT, the performance gains are even more dramatic.*
#### Example
Test 0-RTT with OpenSSL:
1)
_host=”example.com”
cat > req.in << EOF HEAD / HTTP/1.1 Host: $_host Connection: close EOF
- [Security Review of TLS1.3 0-RTT](https://github.com/tlswg/tls13-spec/issues/1001) - [Introducing Zero Round Trip Time Resumption (0-RTT)](https://new.blog.cloudflare.com/introducing-0-rtt/) - [What Application Developers Need To Know About TLS Early Data (0RTT)](https://blog.trailofbits.com/2019/03/25/what-application-developers-need-to-know-about-tls-early-data-0rtt/) - [Replay Attacks on Zero Round-Trip Time: The Case of the TLS 1.3 Handshake Candidates](https://eprint.iacr.org/2017/082.pdf) - [0-RTT and Anti-Replay](https://tools.ietf.org/html/rfc8446#section-8) - [Using Early Data in HTTP (2017)](https://tools.ietf.org/id/draft-thomson-http-replay-00.html_) - [Using Early Data in HTTP (2018)](https://tools.ietf.org/html/draft-ietf-httpbis-replay-04) - [0-RTT Handshakes](https://ldapwiki.com/wiki/0-RTT Handshakes)
### 🔰 Defend against the BEAST attack
#### Rationale
> Generally the BEAST attack relies on a weakness in the way `CBC` mode is used in SSL/TLS.
> More specifically, to successfully perform the BEAST attack, there are some conditions which needs to be met: > > - vulnerable version of SSL must be used using a block cipher (`CBC` in particular) > - JavaScript or a Java applet injection - should be in the same origin of the web site > - data sniffing of the network connection must be possible
> To prevent possible use BEAST attacks you should enable server-side protection, which causes the server ciphers should be preferred over the client ciphers, and completely excluded TLS 1.0 from your protocol stack.
- [An Illustrated Guide to the BEAST Attack](https://commandlinefanatic.com/cgi-bin/showarticle.cgi?article=art027) - [Is BEAST still a threat?](https://blog.ivanristic.com/2013/09/is-beast-still-a-threat.html) - [Beat the BEAST with TLS 1.1/1.2 and More](https://blogs.cisco.com/security/beat-the-beast-with-tls) - [Use only strong ciphers (from this handbook)](https://github.com/dunwu/nginx-tutorial/blob/master/docs/nginx-configuration.md#beginner-use-only-strong-ciphers)
### 🔰 Mitigation of CRIME/BREACH attacks
#### Rationale
> Disable HTTP compression or compress only zero sensitive content.
> You should probably never use TLS compression. Some user agents (at least Chrome) will disable it anyways. Disabling SSL/TLS compression stops the attack very effectively. A deployment of HTTP/2 over TLS 1.2 must disable TLS compression (please see [RFC 7540: 9.2. Use of TLS Features](https://tools.ietf.org/html/rfc7540#section-9.2)).
> CRIME exploits SSL/TLS compression which is disabled since nginx 1.3.2. BREACH exploits HTTP compression
> Some attacks are possible (e.g. the real BREACH attack is a complicated) because of gzip (HTTP compression not TLS compression) being enabled on SSL requests. In most cases, the best action is to simply disable gzip for SSL.
> Compression is not the only requirement for the attack to be done so using it does not mean that the attack will succeed. Generally you should consider whether having an accidental performance drop on HTTPS sites is better than HTTPS sites being accidentally vulnerable.
> You shouldn't use HTTP compression on private responses when using TLS.
> I would gonna to prioritise security over performance but compression can be (I think) okay to HTTP compress publicly available static content like css or js and HTML content with zero sensitive info (like an "About Us" page).
> Remember: by default, Nginx doesn't compress image files using its per-request gzip module.
> Gzip static module is better, for 2 reasons: > > - you don't have to gzip for each request > - you can use a higher gzip level
> You should put the `gzip_static on;` inside the blocks that configure static files, but if you’re only running one site, it’s safe to just put it in the http block.
#### Example
Disable dynamic HTTP compression:
gzip off;
Enable dynamic HTTP compression for specific location context:
- [Is HTTP compression safe?](https://security.stackexchange.com/questions/20406/is-http-compression-safe) - [HTTP compression continues to put encrypted communications at risk](https://www.pcworld.com/article/3051675/http-compression-continues-to-put-encrypted-communications-at-risk.html) - [SSL/TLS attacks: Part 2 – CRIME Attack](http://niiconsulting.com/checkmate/2013/12/ssltls-attacks-part-2-crime-attack/) - [Defending against the BREACH Attack](https://blog.qualys.com/ssllabs/2013/08/07/defending-against-the-breach-attack) - [To avoid BREACH, can we use gzip on non-token responses?](https://security.stackexchange.com/questions/172581/to-avoid-breach-can-we-use-gzip-on-non-token-responses) - [Don't Worry About BREACH](https://blog.ircmaxell.com/2013/08/dont-worry-about-breach.html) - [Module ngx_http_gzip_static_module](http://nginx.org/en/docs/http/ngx_http_gzip_static_module.html) - [Offline Compression with Nginx](https://theartofmachinery.com/2016/06/06/nginx_gzip_static.html)
### 🔰 HTTP Strict Transport Security
#### Rationale
> Generally HSTS is a way for websites to tell browsers that the connection should only ever be encrypted. This prevents MITM attacks, downgrade attacks, sending plain text cookies and session ids.
> The header indicates for how long a browser should unconditionally refuse to take part in unsecured HTTP connection for a specific domain.
> When a browser knows that a domain has enabled HSTS, it does two things: > > - always uses an `https://` connection, even when clicking on an `http://` link or after typing a domain into the location bar without specifying a protocol > - removes the ability for users to click through warnings about invalid certificates
> I recommend to set the `max-age` to a big value like `31536000` (12 months) or `63072000` (24 months).
> There are a few simple best practices for HSTS (from [The Importance of a Proper HTTP Strict Transport Security Implementation on Your Web Server](https://blog.qualys.com/securitylabs/2016/03/28/the-importance-of-a-proper-http-strict-transport-security-implementation-on-your-web-server)): > > - The strongest protection is to ensure that all requested resources use only TLS with a well-formed HSTS header. Qualys recommends providing an HSTS header on all HTTPS resources in the target domain > - It is advisable to assign the max-age directive’s value to be greater than `10368000` seconds (120 days) and ideally to `31536000` (one year). Websites should aim to ramp up the max-age value to ensure heightened security for a long duration for the current domain and/or subdomains > - [RFC 6797](https://tools.ietf.org/html/rfc6797), section 14.4 advocates that a web application must aim to add the `includeSubDomain` directive in the policy definition whenever possible. The directive’s presence ensures the HSTS policy is applied to the domain of the issuing host and all of its subdomains, e.g. `example.com` and `www.example.com` > - The application should never send an HSTS header over a plaintext HTTP header, as doing so makes the connection vulnerable to SSL stripping attacks > - It is not recommended to provide an HSTS policy via the http-equiv attribute of a meta tag. According to HSTS RFC 6797, user agents don’t heed `http-equiv="Strict-Transport-Security"` attribute on `<meta>` elements on the received content`
> To meet the HSTS preload list standard a root domain needs to return a `strict-transport-security` header that includes both the `includeSubDomains` and `preload` directives and has a minimum `max-age` of one year. Your site must also serve a valid SSL certificate on the root domain and all subdomains, as well as redirect all HTTP requests to HTTPS on the same host.
> You had better be pretty sure that your website is indeed all HTTPS before you turn this on because HSTS adds complexity to your rollback strategy. Google recommend enabling HSTS this way: > > 1. Roll out your HTTPS pages without HSTS first > 2. Start sending HSTS headers with a short `max-age`. Monitor your traffic both from users and other clients, and also dependents' performance, such as ads > 3. Slowly increase the HSTS `max-age` > 4. If HSTS doesn't affect your users and search engines negatively, you can, if you wish, ask your site to be added to the HSTS preload list used by most major browsers
- [Strict-Transport-Security](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security) - [Security HTTP Headers - Strict-Transport-Security](https://zinoui.com/blog/security-http-headers#strict-transport-security) - [HTTP Strict Transport Security](https://https.cio.gov/hsts/) - [HTTP Strict Transport Security Cheat Sheet](https://www.owasp.org/index.php/HTTP_Strict_Transport_Security_Cheat_Sheet) - [HSTS Cheat Sheet](https://scotthelme.co.uk/hsts-cheat-sheet/) - [HSTS Preload and Subdomains](https://textslashplain.com/2018/04/09/hsts-preload-and-subdomains/) - [HTTP Strict Transport Security (HSTS) and Nginx](https://www.nginx.com/blog/http-strict-transport-security-hsts-and-nginx/) - [Is HSTS as a proper substitute for HTTP-to-HTTPS redirects?](https://www.reddit.com/r/bigseo/comments/8zw45d/is_hsts_as_a_proper_substitute_for_httptohttps/) - [How to configure HSTS on www and other subdomains](https://www.danielmorell.com/blog/how-to-configure-hsts-on-www-and-other-subdomains) - [HSTS: Is includeSubDomains on main domain sufficient?](https://serverfault.com/questions/927336/hsts-is-includesubdomains-on-main-domain-sufficient) - [The HSTS preload list eligibility](https://www.danielmorell.com/blog/how-to-configure-hsts-on-www-and-other-subdomains) - [Check HSTS preload status and eligibility](https://hstspreload.org/) - [HSTS Deployment Recommendations](https://hstspreload.org/#deployment-recommendations) - [How does HSTS handle mixed content?](https://serverfault.com/questions/927145/how-does-hsts-handle-mixed-content)
### 🔰 Reduce XSS risks (Content-Security-Policy)
#### Rationale
> CSP reduce the risk and impact of XSS attacks in modern browsers.
> Whitelisting known-good resource origins, refusing to execute potentially dangerous inline scripts, and banning the use of eval are all effective mechanisms for mitigating cross-site scripting attacks.
> The inclusion of CSP policies significantly impedes successful XSS attacks, UI Redressing (Clickjacking), malicious use of frames or CSS injections.
> CSP is a good defence-in-depth measure to make exploitation of an accidental lapse in that less likely.
> The default policy that starts building a header is: block everything. By modifying the CSP value, the programmer loosens restrictions for specific groups of resources (e.g. separately for scripts, images, etc.).
> Before enable this header you should discuss with developers about it. They probably going to have to update your application to remove any inline script and style, and make some additional modifications there.
> Strict policies will significantly increase security, and higher code quality will reduce the overall number of errors. CSP can never replace secure code - new restrictions help reduce the effects of attacks (such as XSS), but they are not mechanisms to prevent them!
> You should always validate CSP before implement: [CSP Evaluator](https://csp-evaluator.withgoogle.com/) and [Content Security Policy (CSP) Validator](https://cspvalidator.org/).
> For generate a policy: https://report-uri.com/home/generate. Remember, however, that these types of tools may become outdated or have errors.
#### Example
This policy allows images, scripts, AJAX, and CSS from the same origin, and does not allow any other resources to load:
### 🔰 Provide clickjacking protection (X-Frame-Options)
#### Rationale
> Helps to protect your visitors against clickjacking attacks. It is recommended that you use the `x-frame-options` header on pages which should not be allowed to render a page in a frame.
### 🔰 Deny the use of browser features (Feature-Policy)
#### Rationale
> This header protects your site from third parties using APIs that have security and privacy implications, and also from your own team adding outdated APIs or poorly optimised images.
> Set of methods support by a resource. An ordinary web server supports the `HEAD`, `GET` and `POST` methods to retrieve static and dynamic content. Other (e.g. `OPTIONS`, `TRACE`) methods should not be supported on public web servers, as they increase the attack surface.
> This policy should be implemented by the application architect, however, I know from experience that this does not always happen.
> Don' to cache or persist sensitive data. As browsers have different default behaviour for caching HTTPS content, pages containing sensitive information should include a `Cache-Control` header to ensure that the contents are not cached.
> One option is to add anticaching headers to relevant HTTP/1.1 and HTTP/2 responses, e.g. `Cache-Control: no-cache, no-store` and `Expires: 0`.
> To cover various browser implementations the full set of headers to prevent content being cached should be: >
- [RFC 2616 - Hypertext Transfer Protocol (HTTP/1.1): Standards Track](https://tools.ietf.org/html/rfc2616) - [RFC 7234 - Hypertext Transfer Protocol (HTTP/1.1): Caching](https://tools.ietf.org/html/rfc7234) - [HTTP Cache Headers - A Complete Guide](https://www.keycdn.com/blog/http-cache-headers) - [Caching best practices & max-age gotchas](https://jakearchibald.com/2016/caching-best-practices/) - [Increasing Application Performance with HTTP Cache Headers](https://devcenter.heroku.com/articles/increasing-application-performance-with-http-cache-headers) - [HTTP Caching](https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/http-caching)
### 🔰 Control Buffer Overflow attacks
#### Rationale
> Buffer overflow attacks are made possible by writing data to a buffer and exceeding that buffers’ boundary and overwriting memory fragments of a process. To prevent this in Nginx we can set buffer size limitations for all clients.
### 🔰 Mitigating Slow HTTP DoS attacks (Closing Slow Connections)
#### Rationale
> Close connections that are writing data too infrequently, which can represent an attempt to keep connections open as long as possible.
> You can close connections that are writing data too infrequently, which can represent an attempt to keep connections open as long as possible (thus reducing the server’s ability to accept new connections).
- [Mitigating DDoS Attacks with Nginx and Nginx Plus](https://www.nginx.com/blog/mitigating-ddos-attacks-with-nginx-and-nginx-plus/) - [SCG WS nginx](https://www.owasp.org/index.php/SCG_WS_nginx) - [How to Protect Against Slow HTTP Attacks](https://blog.qualys.com/securitylabs/2011/11/02/how-to-protect-against-slow-http-attacks) - [Effectively Using and Detecting The Slowloris HTTP DoS Tool](https://ma.ttias.be/effectively-using-detecting-the-slowloris-http-dos-tool/)
## 反向代理
### 使用与后端协议兼容的 pass 指令
> All `proxy_*` directives are related to the backends that use the specific backend protocol.
> You should use `proxy_pass` only for HTTP servers working on the backend layer (set also the `http://` protocol before referencing the HTTP backend) and other `*_pass` directives only for non-HTTP backend servers (like a uWSGI or FastCGI).
> Directives such as `uwsgi_pass`, `fastcgi_pass`, or `scgi_pass` are designed specifically for non-HTTP apps and you should use them instead of the `proxy_pass` (non-HTTP talking).
> For example: `uwsgi_pass` uses an uwsgi protocol. `proxy_pass` uses normal HTTP to talking with uWSGI server. uWSGI docs claims that uwsgi protocol is better, faster and can benefit from all of uWSGI special features. You can send to uWSGI information what type of data you are sending and what uWSGI plugin should be invoked to generate response. With http (`proxy_pass`) you won't get that.
示例:
❌ 错误配置
server {
location /app/ {
## For this, you should use uwsgi_pass directive.
proxy_pass 192.168.154.102:4000; ## backend layer: uWSGI Python app.
}
…
}
1 2 3 4 5
⭕ 正确配置
server {
location /app/ {
proxy_pass http://192.168.154.102:80; ## backend layer: OpenResty as a front for app.
> 区别: > > - `$host` 包含“按此优先顺序:请求行中的主机名,或“主机”请求标头字段中的主机名,或与请求匹配的服务器名” > - 如果请求中包含HTTP主机标头字段,则 `$http_host` 包含该内容(始终等于HTTP_HOST请求标头) > - `$server_name` contains the `server_name` of the virtual host which processed the request, as it was defined in the Nginx configuration. If a server contains multiple server names, only the first one will be present in this variable
> `http_host`, moreover, is better than `$host:$server_port` because it uses the port as present in the URL, unlike `$server_port` which uses the port that Nginx listens on.
> In the light of the latest httpoxy vulnerabilities, there is really a need for a full example, how to use `HTTP_X_FORWARDED_FOR` properly. In short, the load balancer sets the 'most recent' part of the header. In my opinion, for security reasons, the proxy servers must be specified by the administrator manually.
> `X-Forwarded-For` is the custom HTTP header that carries along the original IP address of a client so the app at the other end knows what it is. Otherwise it would only see the proxy IP address, and that makes some apps angry.
> The `X-Forwarded-For` depends on the proxy server, which should actually pass the IP address of the client connecting to it. Where a connection passes through a chain of proxy servers, `X-Forwarded-For` can give a comma-separated list of IP addresses with the first being the furthest downstream (that is, the user). Because of this, servers behind proxy servers need to know which of them are trustworthy.
> The proxy used can set this header to anything it wants to, and therefore you can't trust its value. Most proxies do set the correct value though. This header is mostly used by caching proxies, and in those cases you're in control of the proxy and can thus verify that is gives you the correct information. In all other cases its value should be considered untrustworthy.
> Some systems also use `X-Forwarded-For` to enforce access control. A good number of applications rely on knowing the actual IP address of a client to help prevent fraud and enable access.
> Value of the `X-Forwarded-For` header field can be set at the client's side - this can also be termed as `X-Forwarded-For` spoofing. However, when the web request is made via a proxy server, the proxy server modifies the `X-Forwarded-For` field by appending the IP address of the client (user). This will result in 2 comma separated IP addresses in the `X-Forwarded-For` field.
> A reverse proxy is not source IP address transparent. This is a pain when you need the client source IP address to be correct in the logs of the backend servers. I think the best solution of this problem is configure the load balancer to add/modify an `X-Forwarded-For` header with the source IP of the client and forward it to the backend in the correct form.
> Unfortunately, on the proxy side we are not able to solve this problem (all solutions can be spoofable), it is important that this header is correctly interpreted by application servers. Doing so ensures that the apps or downstream services have accurate information on which to make their decisions, including those regarding access and authorization.
There is also an interesing idea what to do in this situation:
> *To prevent this we must distrust that header by default and follow the IP address breadcrumbs backwards from our server. First we need to make sure the `REMOTE_ADDR` is someone we trust to have appended a proper value to the end of `X-Forwarded-For`. If so then we need to make sure we trust the `X-Forwarded-For` IP to have appended the proper IP before it, so on and so forth. Until, finally we get to an IP we don’t trust and at that point we have to assume that’s the IP of our user.* - it comes from [Proxies & IP Spoofing](https://xyu.io/2013/07/04/proxies-ip-spoofing/) by [Xiao Yu](https://github.com/xyu).
#### Example
The whole purpose that it exists is to do the appending behavior:
- [Prevent X-Forwarded-For Spoofing or Manipulation](https://totaluptime.com/kb/prevent-x-forwarded-for-spoofing-or-manipulation/) - [Bypass IP blocks with the X-Forwarded-For header](https://www.sjoerdlangkemper.nl/2017/03/01/bypass-ip-block-with-x-forwarded-for-header/) - [Forwarded header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Forwarded)
> When using Nginx as a reverse proxy you may want to pass through some information of the remote client to your backend web server. I think it's good practices because gives you more control of forwarded headers.
> It's very important for servers behind proxy because it allow to interpret the client correctly. Proxies are the "eyes" of such servers, they should not allow a curved perception of reality. If not all requests are passed through a proxy, as a result, requests received directly from clients may contain e.g. inaccurate IP addresses in headers.
> `X-Forwarded` headers are also important for statistics or filtering. Other example could be access control rules on your app, because without these headers filtering mechanism may not working properly.
> If you use a front-end service like Apache or whatever else as the front-end to your APIs, you will need these headers to understand what IP or hostname was used to connect to the API.
> Forwarding these headers is also important if you use the https protocol (it has become a standard nowadays).
> However, I would not rely on either the presence of all `X-Forwarded` headers, or the validity of their data.
> Internet Engineering Task Force released a new RFC ([RFC-6648](https://tools.ietf.org/html/rfc6648)), recommending deprecation of `X-` prefix.
> The `X-` in front of a header name customarily has denoted it as experimental/non-standard/vendor-specific. Once it's a standard part of HTTP, it'll lose the prefix.
> If it’s possible for new custom header to be standardized, use a non-used and meaningful header name.
> The use of custom headers with `X-` prefix is not forbidden but discouraged. In other words, you can keep using `X-` prefixed headers, but it's not recommended and you may not document them as if they are public standard.