1
0
mirror of synced 2025-11-05 07:30:34 +03:00

Merge commit from fork

* Fix "Untrusted HTTP Header Handling (REMOTE*/LOCAL*)"

* Fix "Untrusted HTTP Header Handling (X-Forwarded-For)"

* Fix security problems in docker/main.cc
This commit is contained in:
yhirose
2025-10-27 19:54:12 -04:00
committed by GitHub
parent 11eed05ce7
commit ac9ebb0ee3
3 changed files with 355 additions and 43 deletions

View File

@@ -3100,21 +3100,20 @@ protected:
#endif
.Get("/remote_addr",
[&](const Request &req, Response &res) {
auto remote_addr = req.headers.find("REMOTE_ADDR")->second;
EXPECT_TRUE(req.has_header("REMOTE_PORT"));
EXPECT_EQ(req.remote_addr, req.get_header_value("REMOTE_ADDR"));
EXPECT_EQ(req.remote_port,
std::stoi(req.get_header_value("REMOTE_PORT")));
res.set_content(remote_addr.c_str(), "text/plain");
ASSERT_FALSE(req.has_header("REMOTE_ADDR"));
ASSERT_FALSE(req.has_header("REMOTE_PORT"));
ASSERT_ANY_THROW(req.get_header_value("REMOTE_ADDR"));
ASSERT_ANY_THROW(req.get_header_value("REMOTE_PORT"));
res.set_content(req.remote_addr, "text/plain");
})
.Get("/local_addr",
[&](const Request &req, Response &res) {
EXPECT_TRUE(req.has_header("LOCAL_PORT"));
EXPECT_TRUE(req.has_header("LOCAL_ADDR"));
auto local_addr = req.get_header_value("LOCAL_ADDR");
auto local_port = req.get_header_value("LOCAL_PORT");
EXPECT_EQ(req.local_addr, local_addr);
EXPECT_EQ(req.local_port, std::stoi(local_port));
ASSERT_FALSE(req.has_header("LOCAL_ADDR"));
ASSERT_FALSE(req.has_header("LOCAL_PORT"));
ASSERT_ANY_THROW(req.get_header_value("LOCAL_ADDR"));
ASSERT_ANY_THROW(req.get_header_value("LOCAL_PORT"));
auto local_addr = req.local_addr;
auto local_port = std::to_string(req.local_port);
res.set_content(local_addr.append(":").append(local_port),
"text/plain");
})
@@ -11208,3 +11207,240 @@ TEST(HeaderSmugglingTest, ChunkedTrailerHeadersMerged) {
std::string res;
ASSERT_TRUE(send_request(1, req, &res));
}
TEST(ForwardedHeadersTest, NoProxiesSetting) {
Server svr;
std::string observed_remote_addr;
std::string observed_xff;
svr.Get("/ip", [&](const Request &req, Response &res) {
observed_remote_addr = req.remote_addr;
observed_xff = req.get_header_value("X-Forwarded-For");
res.set_content("ok", "text/plain");
});
thread t = thread([&]() { svr.listen(HOST, PORT); });
auto se = detail::scope_exit([&] {
svr.stop();
t.join();
ASSERT_FALSE(svr.is_running());
});
svr.wait_until_ready();
Client cli(HOST, PORT);
auto res = cli.Get("/ip", {{"X-Forwarded-For", "203.0.113.66"}});
ASSERT_TRUE(res);
EXPECT_EQ(StatusCode::OK_200, res->status);
EXPECT_EQ(observed_xff, "203.0.113.66");
EXPECT_TRUE(observed_remote_addr == "::1" || observed_remote_addr == "127.0.0.1");
}
TEST(ForwardedHeadersTest, NoForwardedHeaders) {
Server svr;
svr.set_trusted_proxies({"203.0.113.66"});
std::string observed_remote_addr;
std::string observed_xff;
svr.Get("/ip", [&](const Request &req, Response &res) {
observed_remote_addr = req.remote_addr;
observed_xff = req.get_header_value("X-Forwarded-For");
res.set_content("ok", "text/plain");
});
thread t = thread([&]() { svr.listen(HOST, PORT); });
auto se = detail::scope_exit([&] {
svr.stop();
t.join();
ASSERT_FALSE(svr.is_running());
});
svr.wait_until_ready();
Client cli(HOST, PORT);
auto res = cli.Get("/ip");
ASSERT_TRUE(res);
EXPECT_EQ(StatusCode::OK_200, res->status);
EXPECT_EQ(observed_xff, "");
EXPECT_TRUE(observed_remote_addr == "::1" || observed_remote_addr == "127.0.0.1");
}
TEST(ForwardedHeadersTest, SingleTrustedProxy_UsesIPBeforeTrusted) {
Server svr;
svr.set_trusted_proxies({"203.0.113.66"});
std::string observed_remote_addr;
std::string observed_xff;
svr.Get("/ip", [&](const Request &req, Response &res) {
observed_remote_addr = req.remote_addr;
observed_xff = req.get_header_value("X-Forwarded-For");
res.set_content("ok", "text/plain");
});
thread t = thread([&]() { svr.listen(HOST, PORT); });
auto se = detail::scope_exit([&] {
svr.stop();
t.join();
ASSERT_FALSE(svr.is_running());
});
svr.wait_until_ready();
Client cli(HOST, PORT);
auto res = cli.Get("/ip", {{"X-Forwarded-For", "198.51.100.23, 203.0.113.66"}});
ASSERT_TRUE(res);
EXPECT_EQ(StatusCode::OK_200, res->status);
EXPECT_EQ(observed_xff, "198.51.100.23, 203.0.113.66");
EXPECT_EQ(observed_remote_addr, "198.51.100.23");
}
TEST(ForwardedHeadersTest, MultipleTrustedProxies_UsesClientIP) {
Server svr;
svr.set_trusted_proxies({"203.0.113.66", "192.0.2.45"});
std::string observed_remote_addr;
std::string observed_xff;
svr.Get("/ip", [&](const Request &req, Response &res) {
observed_remote_addr = req.remote_addr;
observed_xff = req.get_header_value("X-Forwarded-For");
res.set_content("ok", "text/plain");
});
thread t = thread([&]() { svr.listen(HOST, PORT); });
auto se = detail::scope_exit([&] {
svr.stop();
t.join();
ASSERT_FALSE(svr.is_running());
});
svr.wait_until_ready();
Client cli(HOST, PORT);
auto res = cli.Get(
"/ip",
{{"X-Forwarded-For", "198.51.100.23, 203.0.113.66, 192.0.2.45"}});
ASSERT_TRUE(res);
EXPECT_EQ(StatusCode::OK_200, res->status);
EXPECT_EQ(observed_xff, "198.51.100.23, 203.0.113.66, 192.0.2.45");
EXPECT_EQ(observed_remote_addr, "198.51.100.23");
}
TEST(ForwardedHeadersTest, TrustedProxyNotInHeader_UsesFirstFromXFF) {
Server svr;
svr.set_trusted_proxies({"192.0.2.45"});
std::string observed_remote_addr;
std::string observed_xff;
svr.Get("/ip", [&](const Request &req, Response &res) {
observed_remote_addr = req.remote_addr;
observed_xff = req.get_header_value("X-Forwarded-For");
res.set_content("ok", "text/plain");
});
thread t = thread([&]() { svr.listen(HOST, PORT); });
auto se = detail::scope_exit([&] {
svr.stop();
t.join();
ASSERT_FALSE(svr.is_running());
});
svr.wait_until_ready();
Client cli(HOST, PORT);
auto res = cli.Get("/ip",
{{"X-Forwarded-For", "198.51.100.23, 198.51.100.24"}});
ASSERT_TRUE(res);
EXPECT_EQ(StatusCode::OK_200, res->status);
EXPECT_EQ(observed_xff, "198.51.100.23, 198.51.100.24");
EXPECT_EQ(observed_remote_addr, "198.51.100.23");
}
TEST(ForwardedHeadersTest, LastHopTrusted_SelectsImmediateLeftIP) {
Server svr;
svr.set_trusted_proxies({"192.0.2.45"});
std::string observed_remote_addr;
std::string observed_xff;
svr.Get("/ip", [&](const Request &req, Response &res) {
observed_remote_addr = req.remote_addr;
observed_xff = req.get_header_value("X-Forwarded-For");
res.set_content("ok", "text/plain");
});
thread t = thread([&]() { svr.listen(HOST, PORT); });
auto se = detail::scope_exit([&] {
svr.stop();
t.join();
ASSERT_FALSE(svr.is_running());
});
svr.wait_until_ready();
Client cli(HOST, PORT);
auto res = cli.Get(
"/ip",
{{"X-Forwarded-For", "198.51.100.23, 203.0.113.66, 192.0.2.45"}});
ASSERT_TRUE(res);
EXPECT_EQ(StatusCode::OK_200, res->status);
EXPECT_EQ(observed_xff, "198.51.100.23, 203.0.113.66, 192.0.2.45");
EXPECT_EQ(observed_remote_addr, "203.0.113.66");
}
TEST(ForwardedHeadersTest, HandlesWhitespaceAroundIPs) {
Server svr;
svr.set_trusted_proxies({"192.0.2.45"});
std::string observed_remote_addr;
std::string observed_xff;
svr.Get("/ip", [&](const Request &req, Response &res) {
observed_remote_addr = req.remote_addr;
observed_xff = req.get_header_value("X-Forwarded-For");
res.set_content("ok", "text/plain");
});
thread t = thread([&]() { svr.listen(HOST, PORT); });
auto se = detail::scope_exit([&] {
svr.stop();
t.join();
ASSERT_FALSE(svr.is_running());
});
svr.wait_until_ready();
Client cli(HOST, PORT);
auto res = cli.Get(
"/ip",
{{"X-Forwarded-For", " 198.51.100.23 , 203.0.113.66 , 192.0.2.45 "}});
ASSERT_TRUE(res);
EXPECT_EQ(StatusCode::OK_200, res->status);
// Header parser trims surrounding whitespace of the header value
EXPECT_EQ(observed_xff, "198.51.100.23 , 203.0.113.66 , 192.0.2.45");
EXPECT_EQ(observed_remote_addr, "203.0.113.66");
}