From 7c34908e587733039f862bb2015fd747f586a2f4 Mon Sep 17 00:00:00 2001 From: oldkingnana <2472204250@qq.com> Date: Mon, 22 Jun 2026 03:46:56 +0800 Subject: [PATCH] fix: mask sensitive stream load headers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Mask Authorization, Proxy-Authorization, Auth-Token, and token values when rendering HTTP request headers for logs/debug strings. 中文:对 Stream Load HTTP 请求日志中的敏感 Header 做脱敏,避免 Authorization、Proxy-Authorization、Auth-Token 和 token 明文泄露。 --- .../action/stream_load_forward_handler.cpp | 8 +-- be/src/service/http/http_request.cpp | 18 +++++- be/test/service/http/http_request_test.cpp | 62 +++++++++++++++++++ 3 files changed, 80 insertions(+), 8 deletions(-) create mode 100644 be/test/service/http/http_request_test.cpp diff --git a/be/src/service/http/action/stream_load_forward_handler.cpp b/be/src/service/http/action/stream_load_forward_handler.cpp index 449bf7a8cabe24..cd708dc178bdc7 100644 --- a/be/src/service/http/action/stream_load_forward_handler.cpp +++ b/be/src/service/http/action/stream_load_forward_handler.cpp @@ -32,11 +32,7 @@ namespace doris { #include "common/compile_check_begin.h" int StreamLoadForwardHandler::on_header(HttpRequest* req) { - std::ostringstream headers_info; - const auto& headers = req->headers(); - for (const auto& header : headers) { - headers_info << header.first << ":" << header.second << " "; - } + std::string headers_info = req->get_all_headers(); std::ostringstream params_info; const auto* params = req->params(); @@ -46,7 +42,7 @@ int StreamLoadForwardHandler::on_header(HttpRequest* req) { LOG(INFO) << "StreamLoadForward request started - " << "path: " << req->raw_path() << ", remote: " << req->remote_host() << ", headers: [" - << headers_info.str() << "]" + << headers_info << "]" << ", params: [" << params_info.str() << "]"; std::shared_ptr ctx(new StreamLoadForwardContext()); diff --git a/be/src/service/http/http_request.cpp b/be/src/service/http/http_request.cpp index 22231200de57d5..18fb6b8d4eb0f1 100644 --- a/be/src/service/http/http_request.cpp +++ b/be/src/service/http/http_request.cpp @@ -36,6 +36,12 @@ namespace doris { static std::string s_empty = ""; +static bool is_sensitive_header(const std::string& header_name) { + return iequal(header_name, HttpHeaders::AUTHORIZATION) || + iequal(header_name, HttpHeaders::PROXY_AUTHORIZATION) || iequal(header_name, "token") || + iequal(header_name, HttpHeaders::AUTH_TOKEN); +} + HttpRequest::HttpRequest(evhttp_request* evhttp_request) : _ev_req(evhttp_request) {} HttpRequest::~HttpRequest() { @@ -87,7 +93,11 @@ std::string HttpRequest::debug_string() const { << "raw_path:" << _raw_path << "\n" << "headers: \n"; for (auto& iter : _headers) { - ss << "key=" << iter.first << ", value=" << iter.second << "\n"; + if (is_sensitive_header(iter.first)) { + ss << "key=" << iter.first << ", value=***MASKED***\n"; + } else { + ss << "key=" << iter.first << ", value=" << iter.second << "\n"; + } } ss << "params: \n"; for (auto& iter : _params) { @@ -116,7 +126,11 @@ const std::string& HttpRequest::param(const std::string& key) const { std::string HttpRequest::get_all_headers() const { std::stringstream headers; for (const auto& header : _headers) { - headers << header.first << ":" << header.second + ", "; + if (is_sensitive_header(header.first)) { + headers << header.first << ":***MASKED***, "; + } else { + headers << header.first << ":" << header.second << ", "; + } } return headers.str(); } diff --git a/be/test/service/http/http_request_test.cpp b/be/test/service/http/http_request_test.cpp new file mode 100644 index 00000000000000..07fab72aa99b62 --- /dev/null +++ b/be/test/service/http/http_request_test.cpp @@ -0,0 +1,62 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +#include "service/http/http_request.h" + +#include + +namespace doris { + +TEST(HttpRequestTest, MaskSensitiveHeadersInGetAllHeaders) { + HttpRequest req(nullptr); + req._headers.emplace("Authorization", "Bearer fake_secret"); + req._headers.emplace("Proxy-Authorization", "Basic fake_proxy"); + req._headers.emplace("Auth-Token", "fake_auth_token"); + req._headers.emplace("token", "fake_lower_token"); + req._headers.emplace("label", "normal_label"); + + std::string headers = req.get_all_headers(); + + EXPECT_NE(headers.find("Authorization:***MASKED***"), std::string::npos); + EXPECT_NE(headers.find("Proxy-Authorization:***MASKED***"), std::string::npos); + EXPECT_NE(headers.find("Auth-Token:***MASKED***"), std::string::npos); + EXPECT_NE(headers.find("token:***MASKED***"), std::string::npos); + EXPECT_NE(headers.find("label:normal_label"), std::string::npos); + + EXPECT_EQ(headers.find("fake_secret"), std::string::npos); + EXPECT_EQ(headers.find("fake_proxy"), std::string::npos); + EXPECT_EQ(headers.find("fake_auth_token"), std::string::npos); + EXPECT_EQ(headers.find("fake_lower_token"), std::string::npos); +} + +TEST(HttpRequestTest, MaskSensitiveHeadersInDebugString) { + HttpRequest req(nullptr); + req._headers.emplace("Authorization", "Bearer fake_secret"); + req._headers.emplace("token", "fake_lower_token"); + req._headers.emplace("label", "normal_label"); + + std::string debug_string = req.debug_string(); + + EXPECT_NE(debug_string.find("key=Authorization, value=***MASKED***"), std::string::npos); + EXPECT_NE(debug_string.find("key=token, value=***MASKED***"), std::string::npos); + EXPECT_NE(debug_string.find("key=label, value=normal_label"), std::string::npos); + + EXPECT_EQ(debug_string.find("fake_secret"), std::string::npos); + EXPECT_EQ(debug_string.find("fake_lower_token"), std::string::npos); +} + +} // namespace doris