ASVS 5.0 V12.1.2 requires that your TLS endpoints offer only recommended cipher suites, with the strongest ones preferred. It is a Level 2 requirement. If your application targets Level 3, every suite you offer must also provide forward secrecy.
In practice that means switching off legacy suites (RC4, 3DES, export grade, static RSA key exchange, CBC suites you do not need) and letting TLS 1.3 do most of the work. TLS 1.3 only defines five suites and all of them are modern AEAD ciphers with forward secrecy, so a TLS 1.3 first policy gets you most of the way.
Why it matters
A server is as strong as the weakest suite it will agree to. Attackers and downgrade tools do not need to break your best cipher. They only need a client and server that can be steered toward a weak one, or a passive recorder who saves traffic today and decrypts it later because the key exchange had no forward secrecy.
Forward secrecy means each session uses a throwaway key. If your server certificate key leaks next year, last year's recorded traffic stays unreadable. Static RSA key exchange has no such property.
How to implement it
Start from a maintained profile instead of writing a cipher string from memory. The Mozilla SSL configuration generator publishes "intermediate" and "modern" profiles that track current guidance.
An nginx example in the spirit of the intermediate profile:
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 off;
The list holds only ECDHE suites with AEAD ciphers, so it satisfies the Level 3 forward secrecy wording as well. TLS 1.3 suites are enabled automatically and are not controlled by ssl_ciphers.
In Go, the standard library already picks sensible defaults. If you restrict suites, restrict TLS 1.2 only:
cfg := &tls.Config{
MinVersion: tls.VersionTLS12,
CipherSuites: []uint16{
tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
},
}
Apply the same policy at every termination point: the load balancer, the CDN, the ingress controller and any service that listens on its own port.
How to test it
Enumerate what the endpoint accepts. Either of these works:
nmap --script ssl-enum-ciphers -p 443 example.com
testssl.sh --cipher-per-proto example.com
Pass criteria: no RC4, 3DES, NULL, export or anonymous suites; no suite without ECDHE or DHE if you claim Level 3; the strongest suite is offered first. Then test with an old client by forcing a weak suite:
openssl s_client -connect example.com:443 -tls1_2 -cipher AES128-SHA
The handshake must fail. Put the scan in CI against staging so a config change cannot quietly re-enable something weak.
Click through it at your own pace, or open it full screen.
Common mistakes
- Fixing the public load balancer and forgetting the internal listener, the admin port or the mail server.
- Copying a cipher string from a ten year old blog post.
- Enabling TLS 1.3 but leaving TLS 1.0 and 1.1 on for one old client nobody can name.
- Claiming Level 3 while still offering static RSA suites for compatibility.
- Testing only the default virtual host. SNI hosts can carry their own settings.
Try it yourself
Pick one staging hostname and run the enumeration above. Write down every suite and protocol version it accepts, then compare the list with the intermediate profile from the Mozilla generator. Remove anything extra, redeploy and rerun the scan. Keep the before and after output in your ticket: it is the evidence an assessor will ask for.
If you run several termination points, repeat the exercise for each. A common finding is that the CDN is clean while a direct origin port still accepts TLS 1.0. Add the scan to your pipeline so the answer stays the same after the next infrastructure change.
A useful habit is to review the policy twice a year. Guidance on cipher suites changes slowly but it does change, and a list that was recommended five years ago may now be on the avoid list.
Quick check
Does enabling TLS 1.3 alone satisfy V12.1.2?
Only if TLS 1.2 and older are off. If you still allow TLS 1.2, its suite list must be restricted too.
Which level requires forward secrecy for every suite?
Level 3. Level 2 asks for recommended suites with the strongest preferred.