From 356ae9a4a3b3dd2f83854d6b99f3afb24dd3856d Mon Sep 17 00:00:00 2001 From: Fedor Indutny Date: Sat, 30 Jan 2016 18:49:11 -0500 Subject: [PATCH 1/2] https: evict cached sessions on error Instead of using the same session over and over, evict it when the socket emits error. This could be used as a mitigation of #3692, until OpenSSL fix will be merged/released. See: https://github.com/nodejs/node/issues/3692 --- lib/https.js | 16 ++++ .../test-https-agent-session-eviction.js | 83 +++++++++++++++++++ 2 files changed, 99 insertions(+) create mode 100644 test/parallel/test-https-agent-session-eviction.js diff --git a/lib/https.js b/lib/https.js index 7008a79131c663..9881c0fe1cf722 100644 --- a/lib/https.js +++ b/lib/https.js @@ -84,6 +84,13 @@ function createConnection(port, host, options) { self._cacheSession(options._agentKey, socket.getSession()); }); + + // Evict session on error + socket.once('close', function(err) { + if (err) + self._evictSession(options._agentKey); + }); + return socket; } @@ -164,6 +171,15 @@ Agent.prototype._cacheSession = function _cacheSession(key, session) { this._sessionCache.map[key] = session; }; +Agent.prototype._evictSession = function _evictSession(key) { + const index = this._sessionCache.list.indexOf(key); + if (index === -1) + return; + + this._sessionCache.list.splice(index, 1); + delete this._sessionCache.map[key]; +}; + const globalAgent = new Agent(); exports.globalAgent = globalAgent; diff --git a/test/parallel/test-https-agent-session-eviction.js b/test/parallel/test-https-agent-session-eviction.js new file mode 100644 index 00000000000000..ac93db86f21e88 --- /dev/null +++ b/test/parallel/test-https-agent-session-eviction.js @@ -0,0 +1,83 @@ +'use strict'; + +const common = require('../common'); + +if (!common.hasCrypto) { + console.log('1..0 # Skipped: missing crypto'); + return; +} + +const assert = require('assert'); +const https = require('https'); +const fs = require('fs'); +const constants = require('constants'); + +const options = { + key: fs.readFileSync(common.fixturesDir + '/keys/agent1-key.pem'), + cert: fs.readFileSync(common.fixturesDir + '/keys/agent1-cert.pem'), + secureOptions: constants.SSL_OP_NO_TICKET +}; + +// Create TLS1.2 server +https.createServer(options, function(req, res) { + res.end('ohai'); +}).listen(common.PORT, function() { + first(this); +}); + +// Do request and let agent cache the session +function first(server) { + const req = https.request({ + port: common.PORT, + rejectUnauthorized: false + }, function(res) { + res.resume(); + + server.close(function() { + faultyServer(); + }); + }); + req.end(); +} + +// Create TLS1 server +function faultyServer() { + options.secureProtocol = 'TLSv1_method'; + https.createServer(options, function(req, res) { + res.end('hello faulty'); + }).listen(common.PORT, function() { + second(this); + }); +} + +// Attempt to request using cached session +function second(server, session) { + const req = https.request({ + port: common.PORT, + rejectUnauthorized: false + }, function(res) { + res.resume(); + }); + + // Let it fail + req.on('error', common.mustCall(function(err) { + assert(/wrong version number/.test(err.message)); + + req.on('close', function() { + third(server); + }); + })); + req.end(); +} + +// Try on more time - session should be evicted! +function third(server) { + const req = https.request({ + port: common.PORT, + rejectUnauthorized: false + }, function(res) { + res.resume(); + server.close(); + }); + req.end(); +} From b9b79fdbed704cb647700d799b94f15e88124763 Mon Sep 17 00:00:00 2001 From: Fedor Indutny Date: Sat, 30 Jan 2016 18:59:56 -0500 Subject: [PATCH 2/2] fix --- lib/https.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/https.js b/lib/https.js index 9881c0fe1cf722..2cf1f8c4918825 100644 --- a/lib/https.js +++ b/lib/https.js @@ -86,9 +86,9 @@ function createConnection(port, host, options) { }); // Evict session on error - socket.once('close', function(err) { + socket.once('close', (err) => { if (err) - self._evictSession(options._agentKey); + this._evictSession(options._agentKey); }); return socket;