-
-
Notifications
You must be signed in to change notification settings - Fork 33.5k
Description
The documentation for 'unknownProtocol'
says this:
The
'unknownProtocol'
event is emitted when a connecting client fails to
negotiate an allowed protocol (i.e. HTTP/2 or HTTP/1.1). The event handler
receives the socket for handling. If no listener is registered for this event,
the connection is terminated.
The logic seems wrong though. It only passes through nothing (no protocol negotiated) or http/1.1, everything else is ignored:
node/lib/internal/http2/core.js
Lines 2614 to 2634 in 11f8024
if (socket.alpnProtocol === false || socket.alpnProtocol === 'http/1.1') { | |
// Fallback to HTTP/1.1 | |
if (options.allowHTTP1 === true) { | |
socket.server[kIncomingMessage] = options.Http1IncomingMessage; | |
socket.server[kServerResponse] = options.Http1ServerResponse; | |
return httpConnectionListener.call(this, socket); | |
} | |
// Let event handler deal with the socket | |
debug(`Unknown protocol from ${socket.remoteAddress}:${socket.remotePort}`); | |
if (!this.emit('unknownProtocol', socket)) { | |
// We don't know what to do, so let's just tell the other side what's | |
// going on in a format that they *might* understand. | |
socket.end('HTTP/1.0 403 Forbidden\r\n' + | |
'Content-Type: text/plain\r\n\r\n' + | |
'Unknown ALPN Protocol, expected `h2` to be available.\n' + | |
'If this is a HTTP request: The server was not ' + | |
'configured with the `allowHTTP1` option or a ' + | |
'listener for the `unknownProtocol` event.\n'); | |
} | |
return; | |
} |
Caveat: if the check is loosened, care should be taken not to introduce an information leak.
For an attacker it should not be possible to deduce whether the server has { allowHTTP1: true }
and an 'unknownProtocol'
listener installed by sending messages with the ALPN proto set to http/1.1
and e.g. hax/13.37
, and then comparing the responses he gets back.