Security & Performance

HTTPS and TLS

18 min Lesson 7 of 35

HTTPS and TLS

HTTPS (HTTP Secure) and TLS (Transport Layer Security) are foundational to web security. Understanding how encryption works in transit protects user data from interception and tampering.

SSL/TLS Fundamentals

SSL (Secure Sockets Layer) and its successor TLS create encrypted connections between clients and servers:

// Protocol Evolution
SSL 1.0 - Never released (security flaws)
SSL 2.0 - 1995 (deprecated - insecure)
SSL 3.0 - 1996 (deprecated - POODLE attack)
TLS 1.0 - 1999 (deprecated as of 2020)
TLS 1.1 - 2006 (deprecated as of 2020)
TLS 1.2 - 2008 (still secure)
TLS 1.3 - 2018 (current recommended standard)

// Apache Configuration - Enforce TLS 1.2+
# /etc/httpd/conf.d/ssl.conf
SSLProtocol -all +TLSv1.2 +TLSv1.3
SSLCipherSuite ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256
SSLHonorCipherOrder on

// Nginx Configuration
# /etc/nginx/nginx.conf
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
Warning: Never use SSL 3.0, TLS 1.0, or TLS 1.1 in production. These protocols have known vulnerabilities and are deprecated by major browsers and security standards.

TLS Handshake Process

The TLS handshake establishes a secure connection before any data is transmitted:

// TLS 1.2 Handshake (4 round trips)
1. Client Hello
- Supported TLS versions
- Supported cipher suites
- Random number

2. Server Hello
- Selected TLS version
- Selected cipher suite
- Server certificate
- Random number

3. Client Key Exchange
- Verify server certificate
- Generate pre-master secret
- Encrypt with server public key

4. Change Cipher Spec
- Both sides switch to encrypted communication
- Exchange "Finished" messages

// TLS 1.3 Handshake (1 round trip - faster!)
1. Client Hello
- Supported versions and ciphers
- Key share (pre-computed)

2. Server Hello
- Selected parameters
- Key share
- Certificate
- Finished message
[Encrypted communication begins immediately]
Note: TLS 1.3 reduces handshake latency by 50% compared to TLS 1.2, improving performance while maintaining security. It also removes weak cipher suites and deprecated features.

Certificate Types

SSL/TLS certificates validate server identity and enable encryption. Different types serve different needs:

// 1. Domain Validated (DV) Certificates
- Validates domain ownership only
- Issued within minutes
- Free options available (Let's Encrypt)
- Suitable for blogs, portfolios, small sites
Example: Let's Encrypt, ZeroSSL

// 2. Organization Validated (OV) Certificates
- Validates domain + organization identity
- Requires business verification
- Issued within 1-3 days
- Shows organization name in certificate details
- Suitable for business websites
Example: DigiCert OV, Sectigo OV

// 3. Extended Validation (EV) Certificates
- Highest validation level
- Extensive organization verification
- Issued within 1-2 weeks
- Shows organization name in browser address bar (older browsers)
- Suitable for e-commerce, banking, high-security sites
Example: DigiCert EV, Entrust EV

// 4. Wildcard Certificates
- Secures domain + unlimited subdomains
- *.example.com covers blog.example.com, shop.example.com, etc.
- Cost-effective for multiple subdomains
Example: *.esb1995.com

// 5. Multi-Domain (SAN) Certificates
- Secures multiple different domains
- Subject Alternative Names (SAN)
- example.com, example.net, example.org
Example: Unified Communications Certificate

Let's Encrypt - Free SSL Certificates

Let's Encrypt provides free, automated DV certificates. Perfect for most websites:

# Install Certbot (ACME client)
sudo yum install certbot python3-certbot-apache # RHEL/CentOS
sudo apt install certbot python3-certbot-nginx # Ubuntu/Debian

# Obtain and install certificate (Apache)
sudo certbot --apache -d example.com -d www.example.com

# Obtain and install certificate (Nginx)
sudo certbot --nginx -d example.com -d www.example.com

# Manual certificate (standalone)
sudo certbot certonly --standalone -d example.com

# Automatic renewal (runs twice daily)
sudo certbot renew

# Test renewal process
sudo certbot renew --dry-run

# Add to crontab for automatic renewal
0 0,12 * * * certbot renew --quiet --deploy-hook "systemctl reload apache2"
Best Practice: Let's Encrypt certificates expire after 90 days. Always set up automatic renewal using cron or systemd timers. Test renewal with --dry-run before relying on automation.

HSTS (HTTP Strict Transport Security)

HSTS forces browsers to always use HTTPS, preventing downgrade attacks:

// Apache Configuration
# .htaccess or VirtualHost
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"

// Nginx Configuration
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;

// PHP Implementation
<?php
header('Strict-Transport-Security: max-age=31536000; includeSubDomains; preload');
?>

// Parameters Explained:
max-age=31536000 // 1 year in seconds
includeSubDomains // Apply to all subdomains
preload // Eligible for browser preload lists
Note: HSTS parameters:
max-age: Duration browsers remember to enforce HTTPS (recommended: 1 year)
includeSubDomains: Applies HSTS to all subdomains (ensure ALL subdomains support HTTPS)
preload: Submit to hstspreload.org to be included in browser preload lists (irreversible!)

HSTS Preload

The HSTS preload list is hardcoded into browsers, protecting first-visit users:

// Requirements for HSTS Preload
1. Serve valid HTTPS certificate
2. Redirect HTTP to HTTPS (same host)
3. Serve HSTS header on base domain:
- max-age >= 31536000 (1 year)
- includeSubDomains directive
- preload directive
4. Serve HSTS header on all subdomains

// Submit to Preload List
// Visit: https://hstspreload.org/
// Enter domain and verify requirements

// Apache Redirect + HSTS
<VirtualHost *:80>
ServerName example.com
Redirect permanent / https://example.com/
</VirtualHost>

<VirtualHost *:443>
ServerName example.com
Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"
# ... SSL configuration ...
</VirtualHost>
Warning: HSTS preload is effectively permanent. Removal from preload lists takes months. Only enable if you're certain ALL subdomains will always support HTTPS.

Certificate Pinning

Certificate pinning prevents man-in-the-middle attacks by hardcoding expected certificates or public keys:

// HTTP Public Key Pinning (HPKP) - DEPRECATED
// DO NOT USE: Deprecated due to risks
Public-Key-Pins: pin-sha256="base64=="; max-age=5184000

// Modern Alternative: Certificate Transparency
Expect-CT: max-age=86400, enforce, report-uri="https://example.com/ct-report"

// Mobile App Pinning (iOS - Swift)
let serverTrustPolicy = ServerTrustPolicy.pinPublicKeys(
publicKeys: ServerTrustPolicy.publicKeys(),
validateCertificateChain: true,
validateHost: true
)

// Mobile App Pinning (Android - Kotlin)
val certificatePinner = CertificatePinner.Builder()
.add("example.com", "sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=")
.build()

val client = OkHttpClient.Builder()
.certificatePinner(certificatePinner)
.build()
Note: HPKP was deprecated in 2017 due to risks of permanently bricking websites if misconfigured. Use Certificate Transparency (Expect-CT) for web applications or implement pinning in mobile apps only.

Mixed Content Issues

Mixed content occurs when HTTPS pages load HTTP resources, breaking security:

<!-- INSECURE: Mixed Content -->
<!-- HTTPS page loading HTTP resources -->
<img src="http://example.com/image.jpg">
<script src="http://cdn.example.com/script.js"></script>
<link href="http://example.com/style.css" rel="stylesheet">

<!-- SECURE: Protocol-relative URLs (legacy approach) -->
<img src="//example.com/image.jpg">
<script src="//cdn.example.com/script.js"></script>

<!-- BEST: Explicit HTTPS URLs -->
<img src="https://example.com/image.jpg">
<script src="https://cdn.example.com/script.js"></script>

<!-- Content Security Policy - Block Mixed Content -->
<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">

<?php
// Server-side header
header('Content-Security-Policy: upgrade-insecure-requests');
?>
Best Practice: Use the upgrade-insecure-requests CSP directive to automatically upgrade HTTP requests to HTTPS. This prevents mixed content errors without modifying every resource URL.

TLS Configuration Best Practices

Proper TLS configuration maximizes security and compatibility:

// Apache Virtual Host Configuration
<VirtualHost *:443>
ServerName example.com

# Enable SSL/TLS
SSLEngine on

# Certificate paths
SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem

# TLS protocols (disable old versions)
SSLProtocol -all +TLSv1.2 +TLSv1.3

# Cipher suites (strong encryption only)
SSLCipherSuite ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384
SSLHonorCipherOrder on

# OCSP Stapling (improves performance)
SSLUseStapling on
SSLStaplingCache "shmcb:logs/ssl_stapling(32768)"

# HSTS Header
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
</VirtualHost>

// Test TLS Configuration
// Use SSL Labs: https://www.ssllabs.com/ssltest/
// Command line test:
openssl s_client -connect example.com:443 -tls1_2
openssl s_client -connect example.com:443 -tls1_3

// Check certificate details
openssl x509 -in certificate.crt -text -noout

// Verify certificate chain
openssl verify -CAfile chain.pem certificate.crt

Common TLS Vulnerabilities

Understanding common TLS vulnerabilities helps prevent attacks:

// 1. POODLE (Padding Oracle On Downgraded Legacy Encryption)
// Attack on SSL 3.0
// Fix: Disable SSL 3.0 completely
SSLProtocol -all +TLSv1.2 +TLSv1.3

// 2. BEAST (Browser Exploit Against SSL/TLS)
// Attack on TLS 1.0 CBC ciphers
// Fix: Use TLS 1.2+ or disable CBC ciphers in TLS 1.0

// 3. CRIME (Compression Ratio Info-leak Made Easy)
// Attack on TLS compression
// Fix: Disable TLS compression
SSLCompression off

// 4. Heartbleed
// Buffer over-read in OpenSSL
// Fix: Update OpenSSL to 1.0.1g or later
yum update openssl

// 5. FREAK (Factoring RSA Export Keys)
// Downgrade attack to weak export ciphers
// Fix: Disable export ciphers
SSLCipherSuite !EXPORT

// 6. Logjam
// Downgrade to weak Diffie-Hellman key exchange
// Fix: Use strong DH parameters (2048+ bits)
openssl dhparam -out dhparams.pem 2048
SSLOpenSSLConfCmd DHParameters "/path/to/dhparams.pem"

// 7. DROWN (Decrypting RSA with Obsolete and Weakened eNcryption)
// Attack on servers supporting SSLv2
// Fix: Disable SSLv2 everywhere
SSLProtocol -all +TLSv1.2 +TLSv1.3
Exercise: Set up a complete HTTPS environment:
1. Install Certbot and obtain a Let's Encrypt certificate for your domain
2. Configure Apache/Nginx to use TLS 1.2 and TLS 1.3 only
3. Set up strong cipher suites (use Mozilla SSL Configuration Generator)
4. Enable OCSP stapling for performance
5. Add HSTS header with 1-year max-age and includeSubDomains
6. Configure automatic HTTP to HTTPS redirection
7. Set up automatic certificate renewal with cron
8. Test configuration at SSL Labs (aim for A+ rating)
9. Implement Content-Security-Policy with upgrade-insecure-requests
10. Monitor certificate expiration dates