TLS cipher suites are the cryptographic algorithms that secure the communication between a client and a server.
Here’s a TLS handshake in action, using openssl s_client to connect to a hypothetical server:
openssl s_client -connect example.com:443 -cipher HIGH:!aNULL
This command initiates a TLS connection to example.com on port 443, explicitly requesting only "HIGH" strength cipher suites and excluding "aNULL" (anonymous NULL ciphers). The output will show the negotiated cipher suite, for example:
...
New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384
Server public key is 2048 bit
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
SSL-Session:
Protocol : TLSv1.3
Cipher : TLS_AES_256_GCM_SHA384
Session-ID: ...
Session-time: ...
Start Time: ...
Verify return code: 0 (ok)
...
This shows that the client and server agreed on TLS_AES_256_GCM_SHA384, a strong modern cipher suite.
The problem TLS cipher suites solve is establishing a secure, private, and authenticated channel over an insecure network like the internet. Without them, data transmitted would be plain text, vulnerable to eavesdropping and tampering. The process involves a complex negotiation where the client and server agree on a set of algorithms for key exchange, encryption, and message authentication.
Internally, a cipher suite is typically composed of three parts:
- Key Exchange Algorithm: How the client and server securely agree on a shared secret key. Common examples include RSA, Diffie-Hellman (DH), and Elliptic Curve Diffie-Hellman (ECDH).
- Symmetric Encryption Algorithm: The algorithm used to encrypt the actual data being transmitted. Examples include AES, ChaCha20.
- Message Authentication Code (MAC) Algorithm: Used to ensure the integrity and authenticity of the messages. Examples include SHA-256, SHA-384.
When you configure TLS cipher suites, you’re essentially telling the server which of these combinations it’s willing to use and in what order of preference. The client then picks the best one it supports from the server’s offered list.
Here’s a common configuration snippet for Nginx:
ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256';
ssl_prefer_server_ciphers on;
ssl_ciphers lists the allowed cipher suites, separated by colons. ECDHE-ECDSA-AES256-GCM-SHA384 means: Elliptic Curve Diffie-Hellman Ephemeral (key exchange), ECDSA (authentication), AES in 256-bit mode with Galois/Counter Mode (encryption), and SHA384 (MAC). ssl_prefer_server_ciphers on; ensures the server’s preferred order is used, not the client’s.
The most surprising thing about cipher suite negotiation is that the order you specify them in often matters more than the specific list of ciphers you include. If you list a weaker cipher suite before a stronger one that both client and server support, the weaker one will be chosen.
While modern TLS versions (TLS 1.2 and 1.3) have significantly improved security and introduced stronger cipher suites, older protocols and suites like RC4, DES, 3DES, and MD5 are still sometimes enabled by default or by misconfiguration. These are vulnerable to various attacks, including brute-force, birthday attacks, and known-plaintext attacks, which can allow an attacker to decrypt traffic or forge messages. The goal of disabling weak ciphers is to force clients to use only the strongest available cryptography.
The next concept you’ll likely encounter is the impact of different TLS versions (TLS 1.2 vs. TLS 1.3) and how they handle cipher suites differently, particularly with TLS 1.3 removing many older cipher types entirely.