Skip to content
This repository was archived by the owner on Mar 4, 2020. It is now read-only.

Commit 51abeb3

Browse files
ofrobotsMarshallOfSound
authored andcommitted
inspector: check Host header
Backport-PR-URL: https://github.com/nodejs-private/node-private/pull/108 PR-URL: https://github.com/nodejs-private/node-private/pull/102/ Reviewed-By: Ben Noordhuis <[email protected]> Reviewed-By: Сковорода Никита Андреевич <[email protected]> Reviewed-By: Anna Henningsen <[email protected]>
1 parent a846eab commit 51abeb3

File tree

3 files changed

+84
-7
lines changed

3 files changed

+84
-7
lines changed

src/inspector_socket.cc

+51-7
Original file line numberDiff line numberDiff line change
@@ -397,12 +397,7 @@ static int header_value_cb(http_parser* parser, const char* at, size_t length) {
397397
auto inspector = static_cast<InspectorSocket*>(parser->data);
398398
auto state = inspector->http_parsing_state;
399399
state->parsing_value = true;
400-
if (state->current_header.size() == sizeof(SEC_WEBSOCKET_KEY_HEADER) - 1 &&
401-
node::StringEqualNoCaseN(state->current_header.data(),
402-
SEC_WEBSOCKET_KEY_HEADER,
403-
sizeof(SEC_WEBSOCKET_KEY_HEADER) - 1)) {
404-
state->ws_key.append(at, length);
405-
}
400+
state->headers[state->current_header].append(at, length);
406401
return 0;
407402
}
408403

@@ -475,10 +470,59 @@ static void handshake_failed(InspectorSocket* inspector) {
475470
// init_handshake references message_complete_cb
476471
static void init_handshake(InspectorSocket* socket);
477472

473+
static std::string TrimPort(const std::string& host) {
474+
size_t last_colon_pos = host.rfind(":");
475+
if (last_colon_pos == std::string::npos)
476+
return host;
477+
size_t bracket = host.rfind("]");
478+
if (bracket == std::string::npos || last_colon_pos > bracket)
479+
return host.substr(0, last_colon_pos);
480+
return host;
481+
}
482+
483+
static bool IsIPAddress(const std::string& host) {
484+
if (host.length() >= 4 && host.front() == '[' && host.back() == ']')
485+
return true;
486+
int quads = 0;
487+
for (char c : host) {
488+
if (c == '.')
489+
quads++;
490+
else if (!isdigit(c))
491+
return false;
492+
}
493+
return quads == 3;
494+
}
495+
496+
static std::string HeaderValue(const struct http_parsing_state_s* state,
497+
const std::string& header) {
498+
bool header_found = false;
499+
std::string value;
500+
for (const auto& header_value : state->headers) {
501+
if (node::StringEqualNoCaseN(header_value.first.data(), header.data(),
502+
header.length())) {
503+
if (header_found)
504+
return "";
505+
value = header_value.second;
506+
header_found = true;
507+
}
508+
}
509+
return value;
510+
}
511+
512+
static bool IsAllowedHost(const std::string& host_with_port) {
513+
std::string host = TrimPort(host_with_port);
514+
return host.empty() || IsIPAddress(host)
515+
|| node::StringEqualNoCase(host.data(), "localhost")
516+
|| node::StringEqualNoCase(host.data(), "localhost6");
517+
}
518+
478519
static int message_complete_cb(http_parser* parser) {
479520
InspectorSocket* inspector = static_cast<InspectorSocket*>(parser->data);
480521
struct http_parsing_state_s* state = inspector->http_parsing_state;
481-
if (parser->method != HTTP_GET) {
522+
state->ws_key = HeaderValue(state, "Sec-WebSocket-Key");
523+
524+
if (!IsAllowedHost(HeaderValue(state, "Host")) ||
525+
parser->method != HTTP_GET) {
482526
handshake_failed(inspector);
483527
} else if (!parser->upgrade) {
484528
if (state->callback(inspector, kInspectorHandshakeHttpGet, state->path)) {

src/inspector_socket.h

+2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include "util-inl.h"
66
#include "uv.h"
77

8+
#include <map>
89
#include <string>
910
#include <vector>
1011

@@ -37,6 +38,7 @@ struct http_parsing_state_s {
3738
std::string ws_key;
3839
std::string path;
3940
std::string current_header;
41+
std::map<std::string, std::string> headers;
4042
};
4143

4244
struct ws_state_s {

test/cctest/test_inspector_socket.cc

+31
Original file line numberDiff line numberDiff line change
@@ -936,4 +936,35 @@ TEST_F(InspectorSocketTest, NoCloseResponseFromClinet) {
936936
reinterpret_cast<uv_handle_t*>(&client_socket)));
937937
}
938938

939+
static void HostCheckedForGet_handshake(enum inspector_handshake_event state,
940+
const std::string& path, bool* cont) {
941+
EXPECT_EQ(kInspectorHandshakeFailed, state);
942+
EXPECT_TRUE(path.empty());
943+
*cont = false;
944+
}
945+
946+
TEST_F(InspectorSocketTest, HostCheckedForGet) {
947+
handshake_delegate = HostCheckedForGet_handshake;
948+
const char WRITE_REQUEST[] = "GET /respond/withtext HTTP/1.1\r\n"
949+
"Host: notlocalhost:9222\r\n\r\n";
950+
send_in_chunks(WRITE_REQUEST, sizeof(WRITE_REQUEST) - 1);
951+
952+
expect_handshake_failure();
953+
assert_both_sockets_closed();
954+
}
955+
956+
TEST_F(InspectorSocketTest, HostCheckedForUpgrade) {
957+
handshake_delegate = HostCheckedForGet_handshake;
958+
const char UPGRADE_REQUEST[] = "GET /ws/path HTTP/1.1\r\n"
959+
"Host: nonlocalhost:9229\r\n"
960+
"Upgrade: websocket\r\n"
961+
"Connection: Upgrade\r\n"
962+
"Sec-WebSocket-Key: aaa==\r\n"
963+
"Sec-WebSocket-Version: 13\r\n\r\n";
964+
send_in_chunks(UPGRADE_REQUEST, sizeof(UPGRADE_REQUEST) - 1);
965+
966+
expect_handshake_failure();
967+
assert_both_sockets_closed();
968+
}
969+
939970
} // anonymous namespace

0 commit comments

Comments
 (0)