mirror of
https://github.com/yhirose/cpp-httplib.git
synced 2026-10-16 10:49:36 +00:00
Prevent forwarding of authentication credentials during cross-host redirects as per RFC 9110. Add tests for basic auth and bearer token scenarios.
This commit is contained in:
1 parent
cb8365349f
commit
703abbb53b
2 files changed
+64
-12
No files matched your search
@@ -13048,18 +13048,11 @@ inline void ClientImpl::setup_redirect_client(ClientType &client) {
|
|||||||
client.set_compress(compress_);
|
client.set_compress(compress_);
|
||||||
client.set_decompress(decompress_);
|
client.set_decompress(decompress_);
|
||||||
|
|
||||||
// Copy authentication settings BEFORE proxy setup
|
// NOTE: Authentication credentials (basic auth, bearer token, digest auth)
|
||||||
if (!basic_auth_username_.empty()) {
|
// are intentionally NOT copied to the redirect client. Per RFC 9110 Section
|
||||||
client.set_basic_auth(basic_auth_username_, basic_auth_password_);
|
// 15.4, credentials must not be forwarded when redirecting to a different
|
||||||
}
|
// host. This function is only called for cross-host redirects; same-host
|
||||||
if (!bearer_token_auth_token_.empty()) {
|
// redirects are handled directly in ClientImpl::redirect().
|
||||||
client.set_bearer_token_auth(bearer_token_auth_token_);
|
|
||||||
}
|
|
||||||
#ifdef CPPHTTPLIB_SSL_ENABLED
|
|
||||||
if (!digest_auth_username_.empty()) {
|
|
||||||
client.set_digest_auth(digest_auth_username_, digest_auth_password_);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Setup proxy configuration (CRITICAL ORDER - proxy must be set
|
// Setup proxy configuration (CRITICAL ORDER - proxy must be set
|
||||||
// before proxy auth)
|
// before proxy auth)
|
||||||
|
|||||||
@@ -2382,6 +2382,65 @@ TEST(RedirectToDifferentPort, Redirect) {
|
|||||||
EXPECT_EQ("Hello World!", res->body);
|
EXPECT_EQ("Hello World!", res->body);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
TestDoNotForwardCredentialsOnRedirect(std::function<void(Client &)> set_auth) {
|
||||||
|
Server svr1;
|
||||||
|
std::string captured_authorization;
|
||||||
|
svr1.Get("/target", [&](const Request &req, Response &res) {
|
||||||
|
captured_authorization = req.get_header_value("Authorization");
|
||||||
|
res.set_content("OK", "text/plain");
|
||||||
|
});
|
||||||
|
|
||||||
|
int svr1_port = 0;
|
||||||
|
auto thread1 = std::thread([&]() {
|
||||||
|
svr1_port = svr1.bind_to_any_port(HOST);
|
||||||
|
svr1.listen_after_bind();
|
||||||
|
});
|
||||||
|
|
||||||
|
Server svr2;
|
||||||
|
svr2.Get("/redir", [&](const Request & /*req*/, Response &res) {
|
||||||
|
res.set_redirect(
|
||||||
|
"http://localhost:" + std::to_string(svr1_port) + "/target", 302);
|
||||||
|
});
|
||||||
|
|
||||||
|
int svr2_port = 0;
|
||||||
|
auto thread2 = std::thread([&]() {
|
||||||
|
svr2_port = svr2.bind_to_any_port(HOST);
|
||||||
|
svr2.listen_after_bind();
|
||||||
|
});
|
||||||
|
auto se = detail::scope_exit([&] {
|
||||||
|
svr2.stop();
|
||||||
|
thread2.join();
|
||||||
|
svr1.stop();
|
||||||
|
thread1.join();
|
||||||
|
ASSERT_FALSE(svr2.is_running());
|
||||||
|
ASSERT_FALSE(svr1.is_running());
|
||||||
|
});
|
||||||
|
|
||||||
|
svr1.wait_until_ready();
|
||||||
|
svr2.wait_until_ready();
|
||||||
|
|
||||||
|
Client cli("localhost", svr2_port);
|
||||||
|
cli.set_follow_location(true);
|
||||||
|
set_auth(cli);
|
||||||
|
|
||||||
|
auto res = cli.Get("/redir");
|
||||||
|
ASSERT_TRUE(res);
|
||||||
|
EXPECT_EQ(StatusCode::OK_200, res->status);
|
||||||
|
// RFC 9110: credentials MUST NOT be forwarded to a different host
|
||||||
|
EXPECT_TRUE(captured_authorization.empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(RedirectToDifferentPort, DoNotForwardCredentialsBasicAuth) {
|
||||||
|
TestDoNotForwardCredentialsOnRedirect(
|
||||||
|
[](Client &cli) { cli.set_basic_auth("admin", "secret"); });
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(RedirectToDifferentPort, DoNotForwardCredentialsBearerToken) {
|
||||||
|
TestDoNotForwardCredentialsOnRedirect(
|
||||||
|
[](Client &cli) { cli.set_bearer_token_auth("my-secret-token"); });
|
||||||
|
}
|
||||||
|
|
||||||
TEST(RedirectToDifferentPort, OverflowPortNumber) {
|
TEST(RedirectToDifferentPort, OverflowPortNumber) {
|
||||||
Server svr;
|
Server svr;
|
||||||
svr.Get("/redir", [&](const Request & /*req*/, Response &res) {
|
svr.Get("/redir", [&](const Request & /*req*/, Response &res) {
|
||||||
|
|||||||
Reference in new issue
Block a user