Forráskód Böngészése

Fix crash on empty X-Forwarded-For with trusted proxies configured

yhirose 2 hónapja
szülő
commit
5c9285776e
2 módosított fájl, 54 hozzáadás és 1 törlés
  1. 7 1
      httplib.h
  2. 47 0
      test/test.cc

+ 7 - 1
httplib.h

@@ -11888,6 +11888,11 @@ get_client_ip(const std::string &x_forwarded_for,
                   ip_list.emplace_back(std::string(b + r.first, b + r.second));
                 });
 
+  // A malformed X-Forwarded-For (empty, comma-only, whitespace-only) yields
+  // no segments. Signal "no client IP derived" with an empty string so the
+  // caller can fall back to the connection-level remote address.
+  if (ip_list.empty()) { return std::string(); }
+
   for (size_t i = 0; i < ip_list.size(); ++i) {
     auto ip = ip_list[i];
 
@@ -11978,7 +11983,8 @@ Server::process_request(Stream &strm, const std::string &remote_addr,
 
   if (!trusted_proxies_.empty() && req.has_header("X-Forwarded-For")) {
     auto x_forwarded_for = req.get_header_value("X-Forwarded-For");
-    req.remote_addr = get_client_ip(x_forwarded_for, trusted_proxies_);
+    auto derived = get_client_ip(x_forwarded_for, trusted_proxies_);
+    req.remote_addr = derived.empty() ? remote_addr : derived;
   } else {
     req.remote_addr = remote_addr;
   }

+ 47 - 0
test/test.cc

@@ -14251,6 +14251,53 @@ TEST(ForwardedHeadersTest, HandlesWhitespaceAroundIPs) {
   EXPECT_EQ(observed_remote_addr, "203.0.113.66");
 }
 
+// An X-Forwarded-For header whose value parses to zero IP segments must not
+// crash the server (it used to call front() on an empty vector inside
+// get_client_ip). The connection-level remote address must be retained instead.
+static void run_malformed_xff_test(const std::string &xff_value) {
+  Server svr;
+  svr.set_trusted_proxies({"192.0.2.45"});
+
+  std::string observed_remote_addr;
+  svr.Get("/ip", [&](const Request &req, Response &res) {
+    observed_remote_addr = req.remote_addr;
+    res.set_content("ok", "text/plain");
+  });
+
+  int port = 0;
+  thread t = thread([&]() {
+    port = svr.bind_to_any_port(HOST);
+    svr.listen_after_bind();
+  });
+  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", xff_value}});
+
+  ASSERT_TRUE(res);
+  EXPECT_EQ(StatusCode::OK_200, res->status);
+  EXPECT_TRUE(observed_remote_addr == "::1" ||
+              observed_remote_addr == "127.0.0.1");
+}
+
+TEST(ForwardedHeadersTest, EmptyXForwardedFor_DoesNotCrash) {
+  run_malformed_xff_test("");
+}
+
+TEST(ForwardedHeadersTest, CommaOnlyXForwardedFor_DoesNotCrash) {
+  run_malformed_xff_test(",");
+}
+
+TEST(ForwardedHeadersTest, MultipleCommasXForwardedFor_DoesNotCrash) {
+  run_malformed_xff_test(", , ,");
+}
+
 #ifndef _WIN32
 TEST(ServerRequestParsingTest, RequestWithoutContentLengthOrTransferEncoding) {
   Server svr;