Skip to content

Commit 04936da

Browse files
committed
fix: resolve false positives in hsts_header and ssl_prefer_server_ciphers checks
HSTS: recognize `security_headers on` (ngx_security_headers module) and `more_set_headers` setting Strict-Transport-Security as valid HSTS providers, eliminating false "Missing HSTS header" warnings. ssl_prefer_server_ciphers: invert the check — flag `on` (LOW) instead of `off` (MEDIUM). All authoritative sources (Mozilla, nginx maintainers) recommend `off` for modern cipher lists where all ciphers are strong AEAD; client preference improves performance for mobile clients without AES-NI.
1 parent 0afe730 commit 04936da

File tree

12 files changed

+137
-19
lines changed

12 files changed

+137
-19
lines changed

docs/en/checks/hsts-header.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,3 +57,5 @@ http {
5757
## Notes
5858

5959
- Servers configured with `ssl_reject_handshake on;` are skipped, because they never emit HTTP response headers.
60+
- The [`ngx_security_headers`](https://github.com/GetPageSpeed/ngx_security_headers) module (`security_headers on;`) is recognized as providing HSTS — no separate `add_header` is required.
61+
- The `more_set_headers` directive (from the [headers-more](https://github.com/openresty/headers-more-nginx-module) module) setting `Strict-Transport-Security` is also recognized.

docs/en/checks/weak-ssl-tls.md

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ Detects cipher suites that should be avoided:
3737
- **MD5-based ciphers** - Weak hash function
3838

3939
### 3. Server Cipher Preference
40-
Detects when `ssl_prefer_server_ciphers` is disabled, allowing clients to choose potentially weaker ciphers.
40+
Detects when `ssl_prefer_server_ciphers` is set to `on`. With modern cipher lists containing only strong AEAD ciphers, server cipher preference is unnecessary and may hurt performance — mobile clients without AES-NI hardware benefit from choosing ChaCha20-Poly1305 over AES-GCM. Both [Mozilla](https://ssl-config.mozilla.org/) and nginx maintainers recommend `off`.
4141

4242
## Examples
4343

@@ -59,6 +59,15 @@ server {
5959
```
6060
**Issue**: `Weak ciphers found: RC4, DES, 3DES`
6161

62+
### ❌ Bad: Server cipher preference enabled
63+
```nginx
64+
server {
65+
listen 443 ssl;
66+
ssl_prefer_server_ciphers on; # Unnecessary with modern cipher lists
67+
}
68+
```
69+
**Issue**: `Server cipher preference enabled unnecessarily` (LOW)
70+
6271
### ✅ Good: Secure configuration
6372
```nginx
6473
server {
@@ -70,8 +79,8 @@ server {
7079
# Mozilla Intermediate cipher suite
7180
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
7281
73-
# Server chooses cipher
74-
ssl_prefer_server_ciphers on;
82+
# Client chooses cipher (recommended by Mozilla)
83+
ssl_prefer_server_ciphers off;
7584
7685
# HSTS is checked by the dedicated `hsts_header` plugin.
7786
}

gixy/plugins/hsts_header.py

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ def post_audit(self, root):
6363
server_add_headers if server_add_headers else http_add_headers
6464
)
6565

66-
self._check_hsts(server_block, effective_add_headers)
66+
self._check_hsts(server_block, http_block, effective_add_headers)
6767

6868
def _server_has_ssl(self, server_block):
6969
for listen_dir in server_block.find("listen"):
@@ -76,7 +76,34 @@ def _server_rejects_handshake(self, server_block):
7676
ssl_reject = server_block.some("ssl_reject_handshake")
7777
return bool(ssl_reject and ssl_reject.args and ssl_reject.args[0] == "on")
7878

79-
def _check_hsts(self, server_block, add_headers):
79+
def _has_security_headers_module(self, server_block, http_block):
80+
"""Check if security_headers directive is enabled in server or http block."""
81+
for block in (server_block, http_block):
82+
if block is None:
83+
continue
84+
directive = block.some("security_headers")
85+
if directive and directive.args and directive.args[0] == "on":
86+
return True
87+
return False
88+
89+
def _has_more_set_headers_hsts(self, server_block, http_block):
90+
"""Check if more_set_headers sets Strict-Transport-Security in server or http block."""
91+
for block in (server_block, http_block):
92+
if block is None:
93+
continue
94+
for directive in block.find("more_set_headers"):
95+
for header_name in directive.headers:
96+
if header_name.lower() == "strict-transport-security":
97+
return True
98+
return False
99+
100+
def _check_hsts(self, server_block, http_block, add_headers):
101+
# Skip if security_headers module or more_set_headers provides HSTS
102+
if self._has_security_headers_module(server_block, http_block):
103+
return
104+
if self._has_more_set_headers_hsts(server_block, http_block):
105+
return
106+
80107
hsts_directive = None
81108
for add_header in add_headers:
82109
if (

gixy/plugins/weak_ssl_tls.py

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
Checks for:
55
- Outdated protocols (SSLv2, SSLv3, TLSv1, TLSv1.1)
66
- Weak cipher suites
7-
- Insecure ssl_prefer_server_ciphers settings
7+
- Unnecessary ssl_prefer_server_ciphers on
88
"""
99

1010
import gixy
@@ -180,20 +180,22 @@ def _check_ciphers(self, directive):
180180
)
181181

182182
def _check_prefer_server_ciphers(self, directive):
183-
"""Check if ssl_prefer_server_ciphers is properly configured."""
184-
if directive.args and directive.args[0] == "off":
183+
"""Check if ssl_prefer_server_ciphers is unnecessarily enabled."""
184+
if directive.args and directive.args[0] == "on":
185185
self.add_issue(
186-
severity=gixy.severity.MEDIUM,
186+
severity=gixy.severity.LOW,
187187
directive=[directive, directive.parent],
188-
summary="Server cipher preference disabled",
189-
reason="ssl_prefer_server_ciphers is off, allowing clients to choose ciphers. "
190-
"This may result in weaker cipher selection if the client prefers insecure options.",
188+
summary="Server cipher preference enabled unnecessarily",
189+
reason="ssl_prefer_server_ciphers is on, forcing server cipher order. "
190+
"With modern cipher lists (all strong AEAD ciphers), client cipher preference "
191+
"improves performance — mobile clients without AES-NI benefit from choosing "
192+
"ChaCha20-Poly1305 over AES-GCM. Mozilla and nginx maintainers recommend off.",
191193
fixes=[
192194
self.make_fix(
193-
title="Enable server cipher preference",
194-
search="ssl_prefer_server_ciphers off",
195-
replace="ssl_prefer_server_ciphers on",
196-
description="Let the server choose the strongest cipher",
195+
title="Disable server cipher preference",
196+
search="ssl_prefer_server_ciphers on",
197+
replace="ssl_prefer_server_ciphers off",
198+
description="Let clients choose the most efficient cipher",
197199
),
198200
],
199201
)

tests/integration/wordpress_production.conf

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ http {
6161

6262
# SSL settings (global defaults)
6363
ssl_protocols TLSv1.2 TLSv1.3;
64-
ssl_prefer_server_ciphers on;
64+
ssl_prefer_server_ciphers off;
6565
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
6666
ssl_session_cache shared:SSL:10m;
6767
ssl_session_timeout 1d;
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
http {
2+
server {
3+
listen 443 ssl;
4+
more_set_headers "Strict-Transport-Security: max-age=31536000";
5+
}
6+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
http {
2+
security_headers on;
3+
server {
4+
listen 443 ssl;
5+
}
6+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
http {
2+
server {
3+
listen 443 ssl;
4+
security_headers on;
5+
}
6+
}

tests/plugins/simply/weak_ssl_tls/prefer_off.conf

Lines changed: 0 additions & 1 deletion
This file was deleted.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
ssl_prefer_server_ciphers on;

0 commit comments

Comments
 (0)