Skip to content

Commit d6d3344

Browse files
authored
Add Modern cipher suites and deprecate legacy TLS (#1283)
Update the :strong and :compatible cipher suite upgrades to align with modern security standards, prioritizing TLS 1.3 and 1.2. Remove support for the insecure TLS 1.0 and 1.1 protocols in accordance with RFC 8996.
1 parent 63f1236 commit d6d3344

File tree

2 files changed

+49
-68
lines changed

2 files changed

+49
-68
lines changed

lib/plug/ssl.ex

Lines changed: 34 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -75,34 +75,30 @@ defmodule Plug.SSL do
7575
import Plug.Conn
7676

7777
@strong_tls_ciphers [
78-
~c"ECDHE-RSA-AES256-GCM-SHA384",
79-
~c"ECDHE-ECDSA-AES256-GCM-SHA384",
80-
~c"ECDHE-RSA-AES128-GCM-SHA256",
81-
~c"ECDHE-ECDSA-AES128-GCM-SHA256",
82-
~c"DHE-RSA-AES256-GCM-SHA384",
83-
~c"DHE-RSA-AES128-GCM-SHA256"
78+
# TLS 1.3 Ciphersuites
79+
~c"TLS_AES_256_GCM_SHA384",
80+
~c"TLS_CHACHA20_POLY1305_SHA256",
81+
~c"TLS_AES_128_GCM_SHA256"
8482
]
8583

8684
@compatible_tls_ciphers [
87-
~c"ECDHE-RSA-AES256-GCM-SHA384",
85+
# TLS 1.3 Ciphersuites
86+
~c"TLS_AES_256_GCM_SHA384",
87+
~c"TLS_CHACHA20_POLY1305_SHA256",
88+
~c"TLS_AES_128_GCM_SHA256",
89+
# TLS 1.2 Ciphersuites
8890
~c"ECDHE-ECDSA-AES256-GCM-SHA384",
89-
~c"ECDHE-RSA-AES128-GCM-SHA256",
91+
~c"ECDHE-RSA-AES256-GCM-SHA384",
92+
~c"ECDHE-ECDSA-CHACHA20-POLY1305",
93+
~c"ECDHE-RSA-CHACHA20-POLY1305",
9094
~c"ECDHE-ECDSA-AES128-GCM-SHA256",
95+
~c"ECDHE-RSA-AES128-GCM-SHA256",
9196
~c"DHE-RSA-AES256-GCM-SHA384",
92-
~c"DHE-RSA-AES128-GCM-SHA256",
93-
~c"ECDHE-RSA-AES256-SHA384",
94-
~c"ECDHE-ECDSA-AES256-SHA384",
95-
~c"ECDHE-RSA-AES128-SHA256",
96-
~c"ECDHE-ECDSA-AES128-SHA256",
97-
~c"DHE-RSA-AES256-SHA256",
98-
~c"DHE-RSA-AES128-SHA256",
99-
~c"ECDHE-RSA-AES256-SHA",
100-
~c"ECDHE-ECDSA-AES256-SHA",
101-
~c"ECDHE-RSA-AES128-SHA",
102-
~c"ECDHE-ECDSA-AES128-SHA"
97+
~c"DHE-RSA-AES128-GCM-SHA256"
10398
]
10499

105100
@eccs [
101+
:x25519,
106102
:secp256r1,
107103
:secp384r1,
108104
:secp521r1
@@ -137,30 +133,23 @@ defmodule Plug.SSL do
137133
138134
To simplify configuration of TLS defaults, this function provides two preconfigured
139135
options: `cipher_suite: :strong` and `cipher_suite: :compatible`. The Ciphers
140-
chosen and related configuration come from the [OWASP Cipher String Cheat
141-
Sheet](https://www.owasp.org/index.php/TLS_Cipher_String_Cheat_Sheet)
142-
143-
We've made two modifications to the suggested config from the OWASP recommendations.
144-
First we include ECDSA certificates which are excluded from their configuration.
145-
Second we have changed the order of the ciphers to deprioritize DHE because of
146-
performance implications noted within the OWASP post itself. As the article notes
147-
"...the TLS handshake with DHE hinders the CPU about 2.4 times more than ECDHE".
148-
149-
The **Strong** cipher suite only supports tlsv1.2. Ciphers were based on the OWASP
150-
Group A+ and includes support for RSA or ECDSA certificates. The intention of this
151-
configuration is to provide as secure as possible defaults knowing that it will not
152-
be fully compatible with older browsers and operating systems.
153-
154-
The **Compatible** cipher suite supports tlsv1, tlsv1.1 and tlsv1.2. Ciphers were
155-
based on the OWASP Group B and includes support for RSA or ECDSA certificates. The
156-
intention of this configuration is to provide as secure as possible defaults that
157-
still maintain support for older browsers and Android versions 4.3 and earlier
158-
159-
For both suites we've specified certificate curves secp256r1, ecp384r1 and secp521r1.
160-
Since OWASP doesn't prescribe curves we've based the selection on [Mozilla's
161-
recommendations](https://wiki.mozilla.org/Security/Server_Side_TLS#Cipher_names_correspondence_table)
162-
163-
**The cipher suites were last updated on 2018-JUN-14.**
136+
chosen and related configuration come from the [Transport Layer Security Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Transport_Layer_Security_Cheat_Sheet.html)
137+
138+
The **Strong** cipher suite supports TLSv1.3 as recommended by the Transport
139+
Layer Security Cheat Sheet. General purpose web applications should default to
140+
TLSv1.3 with ALL other protocols disabled.
141+
142+
The **Compatible** cipher suite supports TLSv1.2 and TLSv1.3. This
143+
suite provides strong security while maintaining compatibility with a wide
144+
range of modern clients.
145+
146+
Legacy protocols TLSv1.1 and TLSv1.0 are officially deprecated by
147+
[RFC 8996](https://www.rfc-editor.org/rfc/rfc8996.html) and are
148+
considered insecure.
149+
150+
[Test your ssl configuration](https://ssl-config.mozilla.org/)
151+
152+
**The cipher suites were last updated on 2025-AUG-28.**
164153
"""
165154
@spec configure([:ssl.tls_server_option()]) ::
166155
{:ok, [:ssl.tls_server_option()]} | {:error, String.t()}
@@ -301,14 +290,14 @@ defmodule Plug.SSL do
301290
options
302291
|> set_managed_tls_defaults
303292
|> keynew(:ciphers, 0, {:ciphers, @strong_tls_ciphers})
304-
|> keynew(:versions, 0, {:versions, [:"tlsv1.2"]})
293+
|> keynew(:versions, 0, {:versions, [:"tlsv1.3"]})
305294
end
306295

307296
defp set_compatible_tls_defaults(options) do
308297
options
309298
|> set_managed_tls_defaults
310299
|> keynew(:ciphers, 0, {:ciphers, @compatible_tls_ciphers})
311-
|> keynew(:versions, 0, {:versions, [:"tlsv1.2", :"tlsv1.1", :tlsv1]})
300+
|> keynew(:versions, 0, {:versions, [:"tlsv1.3", :"tlsv1.2"]})
312301
end
313302

314303
defp validate_ciphers(options) do

test/plug/ssl_test.exs

Lines changed: 15 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -40,43 +40,35 @@ defmodule Plug.SSLTest do
4040
assert {:ok, opts} = configure(key: "abcdef", cert: "ghijkl", cipher_suite: :strong)
4141
assert opts[:cipher_suite] == nil
4242
assert opts[:honor_cipher_order] == true
43-
assert opts[:eccs] == [:secp256r1, :secp384r1, :secp521r1]
44-
assert opts[:versions] == [:"tlsv1.2"]
43+
assert opts[:eccs] == [:x25519, :secp256r1, :secp384r1, :secp521r1]
44+
assert opts[:versions] == [:"tlsv1.3"]
4545

4646
assert opts[:ciphers] == [
47-
~c"ECDHE-RSA-AES256-GCM-SHA384",
48-
~c"ECDHE-ECDSA-AES256-GCM-SHA384",
49-
~c"ECDHE-RSA-AES128-GCM-SHA256",
50-
~c"ECDHE-ECDSA-AES128-GCM-SHA256",
51-
~c"DHE-RSA-AES256-GCM-SHA384",
52-
~c"DHE-RSA-AES128-GCM-SHA256"
47+
~c"TLS_AES_256_GCM_SHA384",
48+
~c"TLS_CHACHA20_POLY1305_SHA256",
49+
~c"TLS_AES_128_GCM_SHA256"
5350
]
5451
end
5552

5653
test "sets cipher suite to compatible" do
5754
assert {:ok, opts} = configure(key: "abcdef", cert: "ghijkl", cipher_suite: :compatible)
5855
assert opts[:cipher_suite] == nil
5956
assert opts[:honor_cipher_order] == true
60-
assert opts[:eccs] == [:secp256r1, :secp384r1, :secp521r1]
61-
assert opts[:versions] == [:"tlsv1.2", :"tlsv1.1", :tlsv1]
57+
assert opts[:eccs] == [:x25519, :secp256r1, :secp384r1, :secp521r1]
58+
assert opts[:versions] == [:"tlsv1.3", :"tlsv1.2"]
6259

6360
assert opts[:ciphers] == [
64-
~c"ECDHE-RSA-AES256-GCM-SHA384",
61+
~c"TLS_AES_256_GCM_SHA384",
62+
~c"TLS_CHACHA20_POLY1305_SHA256",
63+
~c"TLS_AES_128_GCM_SHA256",
6564
~c"ECDHE-ECDSA-AES256-GCM-SHA384",
66-
~c"ECDHE-RSA-AES128-GCM-SHA256",
65+
~c"ECDHE-RSA-AES256-GCM-SHA384",
66+
~c"ECDHE-ECDSA-CHACHA20-POLY1305",
67+
~c"ECDHE-RSA-CHACHA20-POLY1305",
6768
~c"ECDHE-ECDSA-AES128-GCM-SHA256",
69+
~c"ECDHE-RSA-AES128-GCM-SHA256",
6870
~c"DHE-RSA-AES256-GCM-SHA384",
69-
~c"DHE-RSA-AES128-GCM-SHA256",
70-
~c"ECDHE-RSA-AES256-SHA384",
71-
~c"ECDHE-ECDSA-AES256-SHA384",
72-
~c"ECDHE-RSA-AES128-SHA256",
73-
~c"ECDHE-ECDSA-AES128-SHA256",
74-
~c"DHE-RSA-AES256-SHA256",
75-
~c"DHE-RSA-AES128-SHA256",
76-
~c"ECDHE-RSA-AES256-SHA",
77-
~c"ECDHE-ECDSA-AES256-SHA",
78-
~c"ECDHE-RSA-AES128-SHA",
79-
~c"ECDHE-ECDSA-AES128-SHA"
71+
~c"DHE-RSA-AES128-GCM-SHA256"
8072
]
8173
end
8274

0 commit comments

Comments
 (0)