# Fix Nginx Weak SSL Cipher Configuration Vulnerability

A security scan flags your Nginx server for using weak SSL ciphers. The report lists vulnerabilities like RC4, DES, and export-grade ciphers still being accepted. Your SSL Labs grade drops from A to C.

Identifying Weak Ciphers

Run a cipher scan against your server:

bash
nmap --script ssl-enum-ciphers -p 443 example.com

The output shows every cipher your server accepts, graded by strength. Look for any cipher rated "weak" or "C":

bash
| ssl-enum-ciphers:
|   TLSv1.2:
|     ciphers:
|       TLS_RSA_WITH_RC4_128_SHA (rsa 2048) - C
|       TLS_RSA_WITH_3DES_EDE_CBC_SHA (rsa 2048) - C
|       TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (secp256r1) - A

Removing Weak Ciphers

Replace your ssl_ciphers directive with a strong, modern configuration:

nginx
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';
ssl_prefer_server_ciphers on;

This configuration: - Uses only ECDHE key exchange (forward secrecy) - Uses only AES-GCM or ChaCha20-Poly1305 (authenticated encryption) - Excludes RSA key exchange (no forward secrecy) - Excludes CBC mode ciphers (vulnerable to padding oracle attacks) - Excludes RC4, DES, 3DES, and all export-grade ciphers

Disabling Legacy Protocols

Also ensure old protocols are disabled:

nginx
ssl_protocols TLSv1.2 TLSv1.3;

Remove TLSv1 and TLSv1.1 entirely. TLS 1.0 and 1.1 have been deprecated by RFC 8996 and are considered insecure.

DH Parameter Strength

Generate a strong Diffie-Hellman parameter:

bash
sudo openssl dhparam -out /etc/nginx/dhparam.pem 4096

Then add to your Nginx configuration:

nginx
ssl_dhparam /etc/nginx/dhparam.pem;

Without this, Nginx may use a weak 1024-bit DH parameter, which the security scanner will flag.

OCSP Stapling

Enable OCSP stapling to improve TLS handshake performance and privacy:

nginx
ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;

OCSP stapling allows Nginx to provide the certificate revocation status directly during the handshake, avoiding a separate OCSP request to the CA.

Complete Production SSL Configuration

```nginx server { listen 443 ssl http2; server_name example.com;

ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

ssl_protocols TLSv1.2 TLSv1.3; 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'; ssl_prefer_server_ciphers on; ssl_dhparam /etc/nginx/dhparam.pem;

ssl_session_cache shared:SSL:10m; ssl_session_timeout 1d; ssl_session_tickets off;

ssl_stapling on; ssl_stapling_verify on;

add_header Strict-Transport-Security "max-age=63072000" always; add_header X-Content-Type-Options nosniff always; add_header X-Frame-Options DENY always; } ```

The ssl_session_cache and ssl_session_tickets off ensure session resumption does not weaken forward secrecy. The Strict-Transport-Security header prevents protocol downgrade attacks.

Verifying the Fix

After reloading:

bash
sudo nginx -t && sudo systemctl reload nginx

Test with SSL Labs:

bash
# Or use the command-line testssl.sh tool
./testssl.sh https://example.com

You should see an A or A+ grade, with no weak ciphers reported and TLS 1.0/1.1 rejected.