By Fatskills Exam Guides Team — the exam nerds behind 28,500+ quizzes and 2.1M practice questions across 500+ global exams.
Hyper-practical, zero-fluff guide for engineers who need to deploy, troubleshoot, or pass the exam—yesterday.
You’re configuring a TLS 1.3 VPN for a remote team, or hardening an NGINX web server to pass a compliance audit. The auditor flags a warning: "Your key exchange lacks Perfect Forward Secrecy (PFS). If your private key is ever compromised, all past sessions can be decrypted."
This is a disaster waiting to happen.- Without PFS, an attacker who steals your server’s private key can decrypt all past encrypted traffic (e.g., passwords, credit card numbers, API keys).- With PFS, even if the private key is stolen, each session’s keys are ephemeral—past traffic stays secure.
Real-world scenario:You inherit a legacy Apache server using RSA key exchange (no PFS). Your CISO demands you upgrade to ECDHE (Elliptic Curve Diffie-Hellman Ephemeral) to meet PCI DSS 4.0 requirements. You have 24 hours to: 1. Generate new keys.2. Update the TLS config.3. Verify PFS is active.4. Ensure no downtime.
This guide gives you the exact steps, commands, and pitfalls to pull this off.
openssl s_client -connect example.com:443 -tls1_2 | grep "Key Exchange"
ECDHE-RSA-AES256-GCM-SHA384
RSA-AES256-GCM-SHA384
✅ NGINX installed (tested on Ubuntu 22.04) ✅ OpenSSL 1.1.1+ (for TLS 1.3 support) ✅ Root/sudo access✅ A domain with SSL cert (Let’s Encrypt or self-signed)
# Generate a private key using curve25519 (modern, fast) openssl ecparam -genkey -name prime256v1 -out /etc/ssl/private/nginx-ecdsa.key # Generate a CSR (for Let’s Encrypt or self-signed) openssl req -new -key /etc/ssl/private/nginx-ecdsa.key -out /etc/ssl/certs/nginx-ecdsa.csr
Why?- ECDSA keys are smaller and faster than RSA.- prime256v1 is widely supported (use secp384r1 for higher security).
# Install Certbot sudo apt install certbot python3-certbot-nginx -y # Request a certificate (uses ECDSA by default if key exists) sudo certbot --nginx -d example.com --key-type ecdsa
Expected output:
Successfully received certificate.Certificate is saved at: /etc/letsencrypt/live/example.com/fullchain.pem Private key is saved at: /etc/letsencrypt/live/example.com/privkey.pem
Edit /etc/nginx/sites-available/default (or your config file):
/etc/nginx/sites-available/default
server { listen 443 ssl http2; server_name example.com; # ECDSA certificate (modern, faster) ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; # RSA fallback (for old clients) ssl_certificate /etc/ssl/certs/nginx-rsa.crt; ssl_certificate_key /etc/ssl/private/nginx-rsa.key; # Enable TLS 1.2 + 1.3 (TLS 1.3 enforces ECDHE) ssl_protocols TLSv1.2 TLSv1.3; # Prioritize ECDHE (PFS) ssl_prefer_server_ciphers on; ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305'; # Enable session resumption (faster handshakes) ssl_session_cache shared:SSL:10m; ssl_session_timeout 1d; ssl_session_tickets off; # Disable for PFS (optional) }
Key settings:- ssl_protocols TLSv1.2 TLSv1.3 → Enforces modern TLS.- ssl_ciphers → Prioritizes ECDHE (PFS).- ssl_session_tickets off → Disables session tickets (optional, but improves PFS).
ssl_protocols TLSv1.2 TLSv1.3
ssl_ciphers
ssl_session_tickets off
# Check if ECDHE is used (should see "ECDHE" in output) openssl s_client -connect example.com:443 -tls1_2 | grep "Key Exchange" # Expected output (PFS enabled): # Key Exchange: ECDHE-RSA-AES256-GCM-SHA384 # Check TLS 1.3 (should show "TLS_AES_256_GCM_SHA384") openssl s_client -connect example.com:443 -tls1_3 | grep "Cipher" # Expected output (TLS 1.3): # Cipher : TLS_AES_256_GCM_SHA384
✅ Success criteria:- TLS 1.2 → Shows ECDHE in key exchange.- TLS 1.3 → Shows TLS_AES_256_GCM_SHA384 (ECDHE is mandatory in TLS 1.3).
# Test config for errors sudo nginx -t # Reload NGINX sudo systemctl reload nginx # Check logs for errors sudo tail -f /var/log/nginx/error.log
? If you see errors:- "No shared cipher" → Your ssl_ciphers list is too restrictive. Add ECDHE-RSA-AES256-GCM-SHA384.- "SSL_CTX_use_PrivateKey_file failed" → Check file permissions (chmod 600 on private keys).
chmod 600
Strict-Transport-Security: max-age=31536000; includeSubDomains
RSA
openssl s_client
ssl_protocols TLSv1.2 TLSv1.3;
prime256v1
secp384r1
curve25519
sudo systemctl reload nginx
ssl_session_tickets off;
❌ RSA, PSK
"What is the main advantage of ECDHE over DHE?"
❌ "More secure" (both are secure, but ECDHE is more efficient)
"Why is RSA key exchange considered insecure for PFS?"
❌ "It’s slower" (irrelevant to PFS)
"Which TLS version enforces ECDHE by default?"
"You need to configure a web server for PCI DSS compliance. Which key exchange should you use?"- ✅ ECDHE (PFS required by PCI DSS) - ❌ RSA (no PFS) - ❌ DHE (slower than ECDHE) - ❌ PSK (not suitable for web)
You’re given an Apache server with this config:
SSLCipherSuite RSA-AES256-GCM-SHA384 SSLProtocol -all +TLSv1.2
Task:1. Modify the config to enable PFS.2. Verify the change with openssl s_client.
# Update Apache config (/etc/apache2/mods-available/ssl.conf) SSLCipherSuite ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384 SSLProtocol -all +TLSv1.2 +TLSv1.3 # Restart Apache sudo systemctl restart apache2 # Verify openssl s_client -connect example.com:443 -tls1_2 | grep "Key Exchange"
Key Exchange: ECDHE-RSA-AES256-GCM-SHA384
Why it works:- ECDHE replaces RSA for key exchange (PFS).- TLS 1.3 enforces ECDHE by default.
openssl s_client -connect example.com:443 -tls1_2
ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:...'
openssl ecparam -genkey -name prime256v1
secp192r1
Strict-Transport-Security: max-age=31536000
includeSubDomains
Now go fix your TLS config before the auditor does. ?
Join 4M+ learners. Unlock unlimited quizzes, wrong-answer tracking, flashcards + reminders, study guides, and 1-on-1 challenges.