| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -140,6 +140,94 @@ To test the renegotiation limits on a server, connect to it using the OpenSSL | |||
| 140 | 140 | command-line client (`openssl s_client -connect address:port`) then input | |
| 141 | 141 | `R<CR>` (i.e., the letter `R` followed by a carriage return) multiple times. | |
| 142 | 142 | ||
| 143 | + ### Session Resumption | ||
| 144 | + | ||
| 145 | + Establishing a TLS session can be relatively slow. The process can be sped | ||
| 146 | + up by saving and later reusing the session state. There are several mechanisms | ||
| 147 | + to do so, discussed here from oldest to newest (and preferred). | ||
| 148 | + | ||
| 149 | + ***Session Identifiers*** Servers generate a unique ID for new connections and | ||
| 150 | + send it to the client. Clients and servers save the session state. When | ||
| 151 | + reconnecting, clients send the ID of their saved session state and if the server | ||
| 152 | + also has the state for that ID, it can agree to use it. Otherwise, the server | ||
| 153 | + will create a new session. See [RFC 2246][] for more information, page 23 and | ||
| 154 | + 30. | ||
| 155 | + | ||
| 156 | + Resumption using session identifiers is supported by most web browsers when | ||
| 157 | + making HTTPS requests. | ||
| 158 | + | ||
| 159 | + For Node.js, clients must call [`tls.TLSSocket.getSession()`][] after the | ||
| 160 | + [`'secureConnect'`][] event to get the session data, and provide the data to the | ||
| 161 | + `session` option of [`tls.connect()`][] to reuse the session. Servers must | ||
| 162 | + implement handlers for the [`'newSession'`][] and [`'resumeSession'`][] events | ||
| 163 | + to save and restore the session data using the session ID as the lookup key to | ||
| 164 | + reuse sessions. To reuse sessions across load balancers or cluster workers, | ||
| 165 | + servers must use a shared session cache (such as Redis) in their session | ||
| 166 | + handlers. | ||
| 167 | + | ||
| 168 | + ***Session Tickets*** The servers encrypt the entire session state and send it | ||
| 169 | + to the client as a "ticket". When reconnecting, the state is sent to the server | ||
| 170 | + in the initial connection. This mechanism avoids the need for server-side | ||
| 171 | + session cache. If the server doesn't use the ticket, for any reason (failure | ||
| 172 | + to decrypt it, it's too old, etc.), it will create a new session and send a new | ||
| 173 | + ticket. See [RFC 5077][] for more information. | ||
| 174 | + | ||
| 175 | + Resumption using session tickets is becoming commonly supported by many web | ||
| 176 | + browsers when making HTTPS requests. | ||
| 177 | + | ||
| 178 | + For Node.js, clients use the same APIs for resumption with session identifiers | ||
| 179 | + as for resumption with session tickets. For debugging, if | ||
| 180 | + [`tls.TLSSocket.getTLSTicket()`][] returns a value, the session data contains a | ||
| 181 | + ticket, otherwise it contains client-side session state. | ||
| 182 | + | ||
| 183 | + Single process servers need no specific implementation to use session tickets. | ||
| 184 | + To use session tickets across server restarts or load balancers, servers must | ||
| 185 | + all have the same ticket keys. There are three 16-byte keys internally, but the | ||
| 186 | + tls API exposes them as a single 48-byte buffer for convenience. | ||
| 187 | + | ||
| 188 | + Its possible to get the ticket keys by calling [`server.getTicketKeys()`][] on | ||
| 189 | + one server instance and then distribute them, but it is more reasonable to | ||
| 190 | + securely generate 48 bytes of secure random data and set them with the | ||
| 191 | + `ticketKeys` option of [`tls.createServer()`][]. The keys should be regularly | ||
| 192 | + regenerated and server's keys can be reset with | ||
| 193 | + [`server.setTicketKeys()`][]. | ||
| 194 | + | ||
| 195 | + Session ticket keys are cryptographic keys, and they ***must be stored | ||
| 196 | + securely***. With TLS 1.2 and below, if they are compromised all sessions that | ||
| 197 | + used tickets encrypted with them can be decrypted. They should not be stored | ||
| 198 | + on disk, and they should be regenerated regularly. | ||
| 199 | + | ||
| 200 | + If clients advertise support for tickets, the server will send them. The | ||
| 201 | + server can disable tickets by supplying | ||
| 202 | + `require('constants').SSL_OP_NO_TICKET` in `secureOptions`. | ||
| 203 | + | ||
| 204 | + Both session identifiers and session tickets timeout, causing the server to | ||
| 205 | + create new sessions. The timeout can be configured with the `sessionTimeout` | ||
| 206 | + option of [`tls.createServer()`][]. | ||
| 207 | + | ||
| 208 | + For all the mechanisms, when resumption fails, servers will create new sessions. | ||
| 209 | + Since failing to resume the session does not cause TLS/HTTPS connection | ||
| 210 | + failures, it is easy to not notice unnecessarily poor TLS performance. The | ||
| 211 | + OpenSSL CLI can be used to verify that servers are resuming sessions. Use the | ||
| 212 | + `-reconnect` option to `openssl s_client`, for example: | ||
| 213 | + | ||
| 214 | + ```sh | ||
| 215 | + $ openssl s_client -connect localhost:443 -reconnect | ||
| 216 | + ``` | ||
| 217 | + | ||
| 218 | + Read through the debug output. The first connection should say "New", for | ||
| 219 | + example: | ||
| 220 | + | ||
| 221 | + ```text | ||
| 222 | + New, TLSv1.2, Cipher is ECDHE-RSA-AES128-GCM-SHA256 | ||
| 223 | + ``` | ||
| 224 | + | ||
| 225 | + Subsequent connections should say "Reused", for example: | ||
| 226 | + | ||
| 227 | + ```text | ||
| 228 | + Reused, TLSv1.2, Cipher is ECDHE-RSA-AES128-GCM-SHA256 | ||
| 229 | + ``` | ||
| 230 | + | ||
| 143 | 231 | ## Modifying the Default TLS Cipher suite | |
| 144 | 232 | ||
| 145 | 233 | Node.js is built with a default suite of enabled and disabled TLS ciphers. | |
@@ -169,10 +257,10 @@ HIGH: | |||
| 169 | 257 | !CAMELLIA | |
| 170 | 258 | ``` | |
| 171 | 259 | ||
| 172 | - This default can be replaced entirely using the [`--tls-cipher-list`][] command line | ||
| 173 | - switch (directly, or via the [`NODE_OPTIONS`][] environment variable). For | ||
| 174 | - instance, the following makes `ECDHE-RSA-AES128-GCM-SHA256:!RC4` the default | ||
| 175 | - TLS cipher suite: | ||
| 260 | + This default can be replaced entirely using the [`--tls-cipher-list`][] command | ||
| 261 | + line switch (directly, or via the [`NODE_OPTIONS`][] environment variable). For | ||
| 262 | + instance, the following makes `ECDHE-RSA-AES128-GCM-SHA256:!RC4` the default TLS | ||
| 263 | + cipher suite: | ||
| 176 | 264 | ||
| 177 | 265 | ```sh | |
| 178 | 266 | node --tls-cipher-list="ECDHE-RSA-AES128-GCM-SHA256:!RC4" server.js | |
@@ -221,11 +309,13 @@ added: v0.9.2 | |||
| 221 | 309 | --> | |
| 222 | 310 | ||
| 223 | 311 | The `'newSession'` event is emitted upon creation of a new TLS session. This may | |
| 224 | - be used to store sessions in external storage. The listener callback is passed | ||
| 225 | - three arguments when called: | ||
| 312 | + be used to store sessions in external storage. The data should be provided to | ||
| 313 | + the [`'resumeSession'`][] callback. | ||
| 314 | + | ||
| 315 | + The listener callback is passed three arguments when called: | ||
| 226 | 316 | ||
| 227 | - * `sessionId` - The TLS session identifier | ||
| 228 | - * `sessionData` - The TLS session data | ||
| 317 | + * `sessionId` {Buffer} The TLS session identifier | ||
| 318 | + * `sessionData` {Buffer} The TLS session data | ||
| 229 | 319 | * `callback` {Function} A callback function taking no arguments that must be | |
| 230 | 320 | invoked in order for data to be sent or received over the secure connection. | |
| 231 | 321 | ||
@@ -288,15 +378,19 @@ The `'resumeSession'` event is emitted when the client requests to resume a | |||
| 288 | 378 | previous TLS session. The listener callback is passed two arguments when | |
| 289 | 379 | called: | |
| 290 | 380 | ||
| 291 | - * `sessionId` - The TLS/SSL session identifier | ||
| 381 | + * `sessionId` {Buffer} The TLS session identifier | ||
| 292 | 382 | * `callback` {Function} A callback function to be called when the prior session | |
| 293 | - has been recovered. | ||
| 294 | - | ||
| 295 | - When called, the event listener may perform a lookup in external storage using | ||
| 296 | - the given `sessionId` and invoke `callback(null, sessionData)` once finished. If | ||
| 297 | - the session cannot be resumed (i.e., doesn't exist in storage) the callback may | ||
| 298 | - be invoked as `callback(null, null)`. Calling `callback(err)` will terminate the | ||
| 299 | - incoming connection and destroy the socket. | ||
| 383 | + has been recovered: `callback([err[, sessionData]])` | ||
| 384 | + * `err` {Error} | ||
| 385 | + * `sessionData` {Buffer} | ||
| 386 | + | ||
| 387 | + The event listener should perform a lookup in external storage for the | ||
| 388 | + `sessionData` saved by the [`'newSession'`][] event handler using the given | ||
| 389 | + `sessionId`. If found, call `callback(null, sessionData)` to resume the session. | ||
| 390 | + If not found, the session cannot be resumed. `callback()` must be called | ||
| 391 | + without `sessionData` so that the handshake can continue and a new session can | ||
| 392 | + be created. It is possible to call `callback(err)` to terminate the incoming | ||
| 393 | + connection and destroy the socket. | ||
| 300 | 394 | ||
| 301 | 395 | Listening for this event will have an effect only on connections established | |
| 302 | 396 | after the addition of the event listener. | |
@@ -406,10 +500,11 @@ Returns the current number of concurrent connections on the server. | |||
| 406 | 500 | added: v3.0.0 | |
| 407 | 501 | --> | |
| 408 | 502 | ||
| 409 | - * Returns: {Buffer} | ||
| 503 | + * Returns: {Buffer} A 48-byte buffer containing the session ticket keys. | ||
| 410 | 504 | ||
| 411 | - Returns a `Buffer` instance holding the keys currently used for | ||
| 412 | - encryption/decryption of the [TLS Session Tickets][]. | ||
| 505 | + Returns the session ticket keys. | ||
| 506 | + | ||
| 507 | + See [Session Resumption][] for more information. | ||
| 413 | 508 | ||
| 414 | 509 | ### server.listen() | |
| 415 | 510 | ||
@@ -433,17 +528,15 @@ existing server. Existing connections to the server are not interrupted. | |||
| 433 | 528 | added: v3.0.0 | |
| 434 | 529 | --> | |
| 435 | 530 | ||
| 436 | - * `keys` {Buffer} The keys used for encryption/decryption of the | ||
| 437 | - [TLS Session Tickets][]. | ||
| 438 | - | ||
| 439 | - Updates the keys for encryption/decryption of the [TLS Session Tickets][]. | ||
| 531 | + * `keys` {Buffer} A 48-byte buffer containing the session ticket keys. | ||
| 440 | 532 | ||
| 441 | - The key's `Buffer` should be 48 bytes long. See `ticketKeys` option in | ||
| 442 | - [`tls.createServer()`] for more information on how it is used. | ||
| 533 | + Sets the session ticket keys. | ||
| 443 | 534 | ||
| 444 | 535 | Changes to the ticket keys are effective only for future server connections. | |
| 445 | 536 | Existing or currently pending server connections will use the previous keys. | |
| 446 | 537 | ||
| 538 | + See [Session Resumption][] for more information. | ||
| 539 | + | ||
| 447 | 540 | ## Class: tls.TLSSocket | |
| 448 | 541 | <!-- YAML | |
| 449 | 542 | added: v0.11.4 | |
@@ -782,19 +875,28 @@ information. | |||
| 782 | 875 | added: v0.11.4 | |
| 783 | 876 | --> | |
| 784 | 877 | ||
| 785 | - Returns the ASN.1 encoded TLS session or `undefined` if no session was | ||
| 786 | - negotiated. Can be used to speed up handshake establishment when reconnecting | ||
| 787 | - to the server. | ||
| 878 | + * {Buffer} | ||
| 879 | + | ||
| 880 | + Returns the TLS session data or `undefined` if no session was | ||
| 881 | + negotiated. On the client, the data can be provided to the `session` option of | ||
| 882 | + [`tls.connect()`][] to resume the connection. On the server, it may be useful | ||
| 883 | + for debugging. | ||
| 884 | + | ||
| 885 | + See [Session Resumption][] for more information. | ||
| 788 | 886 | ||
| 789 | 887 | ### tlsSocket.getTLSTicket() | |
| 790 | 888 | <!-- YAML | |
| 791 | 889 | added: v0.11.4 | |
| 792 | 890 | --> | |
| 793 | 891 | ||
| 794 | - Returns the TLS session ticket or `undefined` if no session was negotiated. | ||
| 892 | + * {Buffer} | ||
| 893 | + | ||
| 894 | + For a client, returns the TLS session ticket if one is available, or | ||
| 895 | + `undefined`. For a server, always returns `undefined`. | ||
| 896 | + | ||
| 897 | + It may be useful for debugging. | ||
| 795 | 898 | ||
| 796 | - This only works with client TLS sockets. Useful only for debugging, for session | ||
| 797 | - reuse provide `session` option to [`tls.connect()`][]. | ||
| 899 | + See [Session Resumption][] for more information. | ||
| 798 | 900 | ||
| 799 | 901 | ### tlsSocket.localAddress | |
| 800 | 902 | <!-- YAML | |
@@ -1228,18 +1330,17 @@ changes: | |||
| 1228 | 1330 | * `requestCert` {boolean} If `true` the server will request a certificate from | |
| 1229 | 1331 | clients that connect and attempt to verify that certificate. **Default:** | |
| 1230 | 1332 | `false`. | |
| 1231 | - * `sessionTimeout` {number} An integer specifying the number of seconds after | ||
| 1232 | - which the TLS session identifiers and TLS session tickets created by the | ||
| 1233 | - server will time out. See [`SSL_CTX_set_timeout`] for more details. | ||
| 1333 | + * `sessionTimeout` {number} The number of seconds after which a TLS session | ||
| 1334 | + created by the server will no longer be resumable. See | ||
| 1335 | + [Session Resumption][] for more information. **Default:** `300`. | ||
| 1234 | 1336 | * `SNICallback(servername, cb)` {Function} A function that will be called if | |
| 1235 | 1337 | the client supports SNI TLS extension. Two arguments will be passed when | |
| 1236 | 1338 | called: `servername` and `cb`. `SNICallback` should invoke `cb(null, ctx)`, | |
| 1237 | 1339 | where `ctx` is a `SecureContext` instance. (`tls.createSecureContext(...)` | |
| 1238 | 1340 | can be used to get a proper `SecureContext`.) If `SNICallback` wasn't | |
| 1239 | 1341 | provided the default callback with high-level API will be used (see below). | |
| 1240 | - * `ticketKeys`: A 48-byte `Buffer` instance consisting of a 16-byte prefix, | ||
| 1241 | - a 16-byte HMAC key, and a 16-byte AES key. This can be used to accept TLS | ||
| 1242 | - session tickets on multiple instances of the TLS server. | ||
| 1342 | + * `ticketKeys`: {Buffer} 48-bytes of cryptographically strong pseudo-random | ||
| 1343 | + data. See [Session Resumption][] for more information. | ||
| 1243 | 1344 | * ...: Any [`tls.createSecureContext()`][] option can be provided. For | |
| 1244 | 1345 | servers, the identity options (`pfx` or `key`/`cert`) are usually required. | |
| 1245 | 1346 | * `secureConnectionListener` {Function} | |
@@ -1414,21 +1515,26 @@ secureSocket = tls.TLSSocket(socket, options); | |||
| 1414 | 1515 | ||
| 1415 | 1516 | where `secureSocket` has the same API as `pair.cleartext`. | |
| 1416 | 1517 | ||
| 1518 | + [`'newSession'`]: #tls_event_newsession | ||
| 1519 | + [`'resumeSession'`]: #tls_event_resumesession | ||
| 1417 | 1520 | [`'secureConnect'`]: #tls_event_secureconnect | |
| 1418 | 1521 | [`'secureConnection'`]: #tls_event_secureconnection | |
| 1419 | 1522 | [`--tls-cipher-list`]: cli.html#cli_tls_cipher_list_list | |
| 1420 | 1523 | [`NODE_OPTIONS`]: cli.html#cli_node_options_options | |
| 1421 | - [`SSL_CTX_set_timeout`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_CTX_set_timeout.html | ||
| 1422 | 1524 | [`crypto.getCurves()`]: crypto.html#crypto_crypto_getcurves | |
| 1423 | 1525 | [`dns.lookup()`]: dns.html#dns_dns_lookup_hostname_options_callback | |
| 1424 | 1526 | [`net.Server.address()`]: net.html#net_server_address | |
| 1425 | 1527 | [`net.Server`]: net.html#net_class_net_server | |
| 1426 | 1528 | [`net.Socket`]: net.html#net_class_net_socket | |
| 1427 | 1529 | [`server.getConnections()`]: net.html#net_server_getconnections_callback | |
| 1530 | + [`server.getTicketKeys()`]: #tls_server_getticketkeys | ||
| 1428 | 1531 | [`server.listen()`]: net.html#net_server_listen | |
| 1532 | + [`server.setTicketKeys()`]: #tls_server_setticketkeys_keys | ||
| 1429 | 1533 | [`tls.DEFAULT_ECDH_CURVE`]: #tls_tls_default_ecdh_curve | |
| 1430 | 1534 | [`tls.Server`]: #tls_class_tls_server | |
| 1431 | 1535 | [`tls.TLSSocket.getPeerCertificate()`]: #tls_tlssocket_getpeercertificate_detailed | |
| 1536 | + [`tls.TLSSocket.getSession()`]: #tls_tlssocket_getsession | ||
| 1537 | + [`tls.TLSSocket.getTLSTicket()`]: #tls_tlssocket_gettlsticket | ||
| 1432 | 1538 | [`tls.TLSSocket`]: #tls_class_tls_tlssocket | |
| 1433 | 1539 | [`tls.connect()`]: #tls_tls_connect_options_callback | |
| 1434 | 1540 | [`tls.createSecureContext()`]: #tls_tls_createsecurecontext_options | |
@@ -1443,10 +1549,12 @@ where `secureSocket` has the same API as `pair.cleartext`. | |||
| 1443 | 1549 | [OpenSSL Options]: crypto.html#crypto_openssl_options | |
| 1444 | 1550 | [OpenSSL cipher list format documentation]: https://www.openssl.org/docs/man1.1.0/apps/ciphers.html#CIPHER-LIST-FORMAT | |
| 1445 | 1551 | [Perfect Forward Secrecy]: #tls_perfect_forward_secrecy | |
| 1552 | + [RFC 2246]: https://www.ietf.org/rfc/rfc2246.txt | ||
| 1553 | + [RFC 5077]: https://tools.ietf.org/html/rfc5077 | ||
| 1446 | 1554 | [RFC 5929]: https://tools.ietf.org/html/rfc5929 | |
| 1447 | 1555 | [SSL_METHODS]: https://www.openssl.org/docs/man1.1.0/ssl/ssl.html#Dealing-with-Protocol-Methods | |
| 1556 | + [Session Resumption]: #tls_session_resumption | ||
| 1448 | 1557 | [Stream]: stream.html#stream_stream | |
| 1449 | - [TLS Session Tickets]: https://www.ietf.org/rfc/rfc5077.txt | ||
| 1450 | 1558 | [TLS recommendations]: https://wiki.mozilla.org/Security/Server_Side_TLS | |
| 1451 | 1559 | [asn1.js]: https://www.npmjs.com/package/asn1.js | |
| 1452 | 1560 | [certificate object]: #tls_certificate_object | |
| Back | FazBrowse Home | New Git URL |
0 commit comments