HTTPS and TLS/SSL Encryption: Securing the Web

HTTPS (HTTP Secure) and TLS (Transport Layer Security) form the foundation of secure communication on the Internet. Every time you see the padlock icon in your browser, TLS is working behind the scenes to protect your data from eavesdropping, tampering, and impersonation. This deep dive explores how TLS/SSL encryption works, from the initial handshake to encrypted data transfer.

Understanding TLS/SSL

Protocol Evolution

SSL 1.0 (Never released)
SSL 2.0 (1995) - Deprecated
SSL 3.0 (1996) - Deprecated (POODLE attack)
TLS 1.0 (1999) - Deprecated
TLS 1.1 (2006) - Deprecated
TLS 1.2 (2008) - Widely used
TLS 1.3 (2018) - Current standard, recommended

What TLS Provides

  1. Encryption: Data confidentiality through symmetric encryption
  2. Authentication: Server (and optionally client) identity verification
  3. Integrity: Detection of message tampering

Cryptographic Foundations

Symmetric Encryption

Same key for encryption and decryption:

Plaintext → [Encrypt with Key K] → Ciphertext
Ciphertext → [Decrypt with Key K] → Plaintext

Common Algorithms:
- AES (Advanced Encryption Standard)
  - AES-128, AES-256
- ChaCha20

Example of AES encryption concept:

from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.backends import default_backend
import os

# Generate a random 256-bit key
key = os.urandom(32)
## Generate a random 128-bit IV
iv = os.urandom(16)

## Create cipher
cipher = Cipher(
    algorithms.AES(key),
    modes.CBC(iv),
    backend=default_backend()
)

## Encrypt
encryptor = cipher.encryptor()
plaintext = b"Secret message here!"
## Pad to block size
padded = plaintext + b' ' * (16 - len(plaintext) % 16)
ciphertext = encryptor.update(padded) + encryptor.finalize()

## Decrypt
decryptor = cipher.decryptor()
decrypted = decryptor.update(ciphertext) + decryptor.finalize()

Asymmetric Encryption (Public Key Cryptography)

Different keys for encryption and decryption:

Public Key (Known to everyone)
Private Key (Kept secret)

Encryption:  Plaintext + Public Key → Ciphertext
Decryption:  Ciphertext + Private Key → Plaintext

Common Algorithms:
- RSA (Rivest-Shamir-Adleman)
- ECDSA (Elliptic Curve Digital Signature Algorithm)
- Ed25519 (Edwards-curve Digital Signature Algorithm)

RSA key generation concept:

from cryptography.hazmat.primitives.asymmetric import rsa, padding
from cryptography.hazmat.primitives import hashes

## Generate RSA key pair
private_key = rsa.generate_private_key(
    public_exponent=65537,
    key_size=2048
)
public_key = private_key.public_key()

## Encrypt with public key
message = b"Secret data"
ciphertext = public_key.encrypt(
    message,
    padding.OAEP(
        mgf=padding.MGF1(algorithm=hashes.SHA256()),
        algorithm=hashes.SHA256(),
        label=None
    )
)

## Decrypt with private key
plaintext = private_key.decrypt(
    ciphertext,
    padding.OAEP(
        mgf=padding.MGF1(algorithm=hashes.SHA256()),
        algorithm=hashes.SHA256(),
        label=None
    )
)

Hash Functions

One-way functions for integrity:

Input (any size) → Hash Function → Fixed-size digest

Properties:
- Deterministic (same input = same output)
- Fast to compute
- Infeasible to reverse
- Small input change = completely different hash
- Collision resistant

Common Algorithms:
- SHA-256 (Secure Hash Algorithm)
- SHA-384, SHA-512
- BLAKE2

TLS Handshake Process

TLS 1.2 Handshake

Client                                Server
  │                                     │
  │─────── ClientHello ────────────────>│
  │  - Protocol versions                │
  │  - Cipher suites                    │
  │  - Random nonce                     │
  │                                     │
  │<────── ServerHello ─────────────────│
  │  - Selected protocol version        │
  │  - Selected cipher suite            │
  │  - Random nonce                     │
  │                                     │
  │<────── Certificate ─────────────────│
  │  - Server's certificate chain       │
  │                                     │
  │<──── ServerKeyExchange ─────────────│
  │  - Key exchange parameters          │
  │  (RSA: encrypted pre-master)        │
  │  (DHE: DH parameters)               │
  │                                     │
  │<──── CertificateRequest ────────────│
  │  (Optional, for client auth)        │
  │                                     │
  │<────── ServerHelloDone ─────────────│
  │                                     │
  │─────── Certificate ────────────────>│
  │  (If client auth requested)         │
  │                                     │
  │──── ClientKeyExchange ─────────────>│
  │  - Pre-master secret (encrypted)    │
  │                                     │
  │──── CertificateVerify ─────────────>│
  │  (If client auth)                   │
  │                                     │
  │──── ChangeCipherSpec ──────────────>│
  │                                     │
  │─────── Finished ───────────────────>│
  │  - Handshake verification           │
  │                                     │
  │<──── ChangeCipherSpec ──────────────│
  │                                     │
  │<────── Finished ────────────────────│
  │  - Handshake verification           │
  │                                     │
  │  Encrypted Application Data         │
  │<══════════════════════════════════>│

TLS 1.3 Handshake (Improved)

Faster and more secure:

Client                                Server
  │                                     │
  │─────── ClientHello ────────────────>│
  │  - Protocol versions (TLS 1.3)      │
  │  - Cipher suites                    │
  │  - Key shares (early DH)            │
  │  - Extensions                       │
  │                                     │
  │         EncryptedExtensions         │
  │<────────────────────────────────────│
  │  - ServerHello                      │
  │  - Selected key share               │
  │  - Certificate                      │
  │  - CertificateVerify                │
  │  - Finished                         │
  │                                     │
  │─────── Finished ───────────────────>│
  │                                     │
  │  Encrypted Application Data         │
  │<══════════════════════════════════>│

Benefits:
- 1-RTT handshake (vs 2-RTT in TLS 1.2)
- 0-RTT resumption possible
- Removed vulnerable features
- All handshake encrypted (except ClientHello/ServerHello)

Certificate Management

X.509 Certificates

Structure of a digital certificate:

Certificate:
    Version: 3
    Serial Number: 04:00:00:00:00:01:15:4b:5a:c3:94
    Signature Algorithm: SHA256-RSA
    Issuer: CN=DigiCert Global Root CA
    Validity:
        Not Before: Nov 10 00:00:00 2023 GMT
        Not After: Nov  9 23:59:59 2033 GMT
    Subject: CN=example.com
    Subject Public Key Info:
        Public Key Algorithm: rsaEncryption
        RSA Public Key: (2048 bit)
    X509v3 Extensions:
        X509v3 Subject Alternative Name:
            DNS:example.com, DNS:www.example.com
        X509v3 Key Usage:
            Digital Signature, Key Encipherment
        X509v3 Extended Key Usage:
            TLS Web Server Authentication
    Signature: (signature bytes)

Certificate Chain

Root CA Certificate (Self-signed)
    ↓
Intermediate CA Certificate (Signed by Root)
    ↓
Server Certificate (Signed by Intermediate)

Example certificate chain validation:

## View certificate chain
openssl s_client -connect example.com:443 -showcerts

## Verify certificate
openssl verify -CAfile ca-bundle.crt server.crt

## View certificate details
openssl x509 -in server.crt -text -noout

Certificate Authorities (CAs)

Trusted organizations that issue certificates:

  • DigiCert
  • Let’s Encrypt (Free, automated)
  • Sectigo
  • GlobalSign
  • GoDaddy

Obtaining a Certificate

Using Let’s Encrypt with Certbot:

## Install certbot
sudo apt install certbot python3-certbot-nginx

## Obtain certificate
sudo certbot --nginx -d example.com -d www.example.com

## Certificate files created:
## /etc/letsencrypt/live/example.com/fullchain.pem
## /etc/letsencrypt/live/example.com/privkey.pem

## Auto-renewal (Let's Encrypt certs expire in 90 days)
sudo certbot renew --dry-run

Manual certificate request:

## Generate private key
openssl genrsa -out private.key 2048

## Generate CSR (Certificate Signing Request)
openssl req -new -key private.key -out request.csr \
  -subj "/C=US/ST=California/L=San Francisco/O=Example Inc/CN=example.com"

## Submit CSR to CA and receive signed certificate

## Verify certificate matches private key
openssl x509 -noout -modulus -in certificate.crt | openssl md5
openssl rsa -noout -modulus -in private.key | openssl md5
## MD5 hashes should match

Cipher Suites

A cipher suite specifies algorithms for the TLS connection:

Format (TLS 1.2):
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256

Components:
- TLS: Protocol
- ECDHE: Key exchange (Elliptic Curve Diffie-Hellman Ephemeral)
- RSA: Authentication
- AES_128_GCM: Encryption (AES 128-bit in GCM mode)
- SHA256: Message authentication

TLS 1.3 Format (Simplified):
TLS_AES_128_GCM_SHA256

Only specifies:
- Encryption algorithm
- Hash function
(Key exchange and authentication standardized in TLS 1.3)
Strong ciphers:
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
TLS_DHE_RSA_WITH_AES_256_GCM_SHA384
TLS_DHE_RSA_WITH_AES_128_GCM_SHA256

Avoid (weak or deprecated):
TLS_RSA_WITH_3DES_EDE_CBC_SHA (3DES)
TLS_RSA_WITH_RC4_128_SHA (RC4)
TLS_RSA_WITH_* (No forward secrecy)

TLS 1.3 Cipher Suites

Mandatory:
TLS_AES_128_GCM_SHA256

Recommended:
TLS_AES_256_GCM_SHA384
TLS_CHACHA20_POLY1305_SHA256
TLS_AES_128_CCM_SHA256

Perfect Forward Secrecy (PFS)

Ensures past sessions remain secure even if private key is compromised.

Without PFS (RSA key exchange):
- Pre-master secret encrypted with server's public key
- If private key compromised, attacker can decrypt all recorded traffic

With PFS (DHE/ECDHE):
- Ephemeral keys generated for each session
- Session keys derived from ephemeral keys
- Compromising server's private key doesn't decrypt past sessions

Cipher suites with PFS:
TLS_ECDHE_* (Elliptic Curve DHE)
TLS_DHE_*   (Diffie-Hellman Ephemeral)

Server Configuration

Nginx TLS Configuration

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

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

    # TLS protocols
    ssl_protocols TLSv1.2 TLSv1.3;
    
    # Cipher suites (TLS 1.2)
    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;

    # DH parameters for DHE ciphers
    ssl_dhparam /etc/nginx/dhparam.pem;

    # OCSP Stapling
    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;

    # Session cache
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;
    ssl_session_tickets off;

    # HSTS (HTTP Strict Transport Security)
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;

    # Other security headers
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-XSS-Protection "1; mode=block" always;

    location / {
        root /var/www/html;
        index index.html;
    }
}

## HTTP to HTTPS redirect
server {
    listen 80;
    server_name example.com;
    return 301 https://$server_name$request_uri;
}

Generate DH parameters:

openssl dhparam -out /etc/nginx/dhparam.pem 2048

Apache TLS Configuration

<VirtualHost *:443>
    ServerName example.com
    DocumentRoot /var/www/html

    # Enable SSL
    SSLEngine on
    
    # Certificate files
    SSLCertificateFile /etc/letsencrypt/live/example.com/cert.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
    SSLCertificateChainFile /etc/letsencrypt/live/example.com/chain.pem

    # TLS protocols
    SSLProtocol -all +TLSv1.2 +TLSv1.3
    
    # Cipher suites
    SSLCipherSuite 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
    SSLHonorCipherOrder on

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

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

TLS Testing and Validation

OpenSSL Command Line

## Test TLS connection
openssl s_client -connect example.com:443

## Test specific TLS version
openssl s_client -connect example.com:443 -tls1_2
openssl s_client -connect example.com:443 -tls1_3

## Display certificate
openssl s_client -connect example.com:443 -showcerts

## Check certificate expiration
echo | openssl s_client -connect example.com:443 2>/dev/null | openssl x509 -noout -dates

## Test cipher suite
openssl s_client -connect example.com:443 -cipher 'ECDHE-RSA-AES128-GCM-SHA256'

## Verify certificate chain
openssl s_client -connect example.com:443 -CAfile /etc/ssl/certs/ca-certificates.crt

Online Testing Tools

SSL Labs Server Test:
https://www.ssllabs.com/ssltest/

Checks:
- Certificate validity
- Protocol support
- Cipher suites
- Vulnerabilities
- Grade: A+, A, B, C, F

Security Headers:
https://securityheaders.com/

HSTS Preload:
https://hstspreload.org/

Testing with curl

## Verbose TLS connection
curl -v https://example.com

## Specific TLS version
curl --tlsv1.2 https://example.com
curl --tlsv1.3 https://example.com

## Check certificate
curl -vvI https://example.com 2>&1 | grep -i 'expire\|subject\|issuer'

## Test without certificate validation (debugging only!)
curl -k https://example.com

## Display certificate details
curl -vvI --stderr - https://example.com | grep -i 'SSL\|TLS'

Common TLS Attacks and Mitigations

BEAST (Browser Exploit Against SSL/TLS)

Attack: Exploits CBC cipher vulnerability in TLS 1.0
Mitigation:
- Use TLS 1.2+ with AEAD ciphers (GCM, ChaCha20-Poly1305)
- Disable TLS 1.0

CRIME (Compression Ratio Info-leak Made Easy)

Attack: Exploits TLS compression to steal secrets
Mitigation:
- Disable TLS compression
ssl_compression off; (Nginx)

POODLE (Padding Oracle On Downgraded Legacy Encryption)

Attack: Forces downgrade to SSL 3.0, exploits padding oracle
Mitigation:
- Disable SSL 3.0 and TLS 1.0
- Use TLS_FALLBACK_SCSV

Heartbleed

Attack: OpenSSL bug allowing memory disclosure
Mitigation:
- Update OpenSSL to patched version
- Reissue certificates
- Change private keys

ROBOT (Return Of Bleichenbacher’s Oracle Threat)

Attack: Exploits RSA key exchange padding oracle
Mitigation:
- Use ECDHE/DHE key exchange (PFS)
- Disable RSA key exchange

HTTPS Best Practices

1. Use Strong Configurations

✓ TLS 1.2 minimum (TLS 1.3 preferred)
✓ Strong cipher suites only
✓ Perfect forward secrecy
✓ 2048-bit or larger RSA keys
✓ Disable SSL 2.0, SSL 3.0, TLS 1.0, TLS 1.1

2. Certificate Management

✓ Use certificates from trusted CAs
✓ Include all intermediate certificates
✓ Monitor expiration dates
✓ Automate renewal (Let's Encrypt)
✓ Use SAN certificates for multiple domains

3. Enable HSTS

## Strict-Transport-Security header
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;

Considerations:
- Test thoroughly before preloading
- Preload list is permanent (difficult to remove)
- Affects all subdomains with includeSubDomains

4. Implement OCSP Stapling

Benefits:
- Improves performance
- Protects client privacy
- Enables real-time revocation checking

Configuration:
ssl_stapling on;
ssl_stapling_verify on;

5. Security Headers

## Prevent clickjacking
add_header X-Frame-Options "SAMEORIGIN" always;

## Prevent MIME sniffing
add_header X-Content-Type-Options "nosniff" always;

## XSS protection
add_header X-XSS-Protection "1; mode=block" always;

## Referrer policy
add_header Referrer-Policy "strict-origin-when-cross-origin" always;

## Content Security Policy
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'" always;

6. Regular Updates

✓ Keep OpenSSL/web server updated
✓ Monitor security advisories
✓ Test after updates
✓ Have rollback plan

7. Monitor and Alert

## Certificate expiration monitoring
openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | openssl x509 -noout -dates

## Automated monitoring script
#!/bin/bash
DOMAIN="example.com"
EXPIRY=$(echo | openssl s_client -servername $DOMAIN -connect $DOMAIN:443 2>/dev/null | openssl x509 -noout -enddate | cut -d= -f2)
EXPIRY_EPOCH=$(date -d "$EXPIRY" +%s)
NOW_EPOCH=$(date +%s)
DAYS_LEFT=$(( ($EXPIRY_EPOCH - $NOW_EPOCH) / 86400 ))

if [ $DAYS_LEFT -lt 30 ]; then
    echo "WARNING: Certificate expires in $DAYS_LEFT days!"
fi

Conclusion

HTTPS and TLS/SSL encryption are critical for securing web communications. Understanding the underlying mechanisms—handshake process, cipher suites, certificate validation, and proper configuration—enables you to:

  • Implement secure HTTPS connections
  • Troubleshoot TLS issues effectively
  • Configure optimal security settings
  • Protect against known vulnerabilities
  • Maintain compliance with security standards

Key takeaways:

  • Use TLS 1.2+ with strong cipher suites
  • Implement perfect forward secrecy
  • Properly manage certificates and keys
  • Enable HSTS and security headers
  • Regularly test and update configurations
  • Monitor certificate expiration
  • Stay informed about security vulnerabilities

As web security evolves, staying current with TLS best practices and promptly addressing vulnerabilities remains essential for protecting users and data.

Thank you for reading! If you have any feedback or comments, please send them to [email protected].