fix(libhttp): 修复P1-5静态文件路径遍历 + 同步审计文档

- 新增 isSafeStaticPath() 校验静态文件路径,拒绝 ..、空字节、非/开头及URL编码遍历(%2e/%2f/%5c)
- handleRequest 静态文件服务前校验 target_path
- 审计文档标记 P1-5 已修复
This commit is contained in:
qing committed 2026-08-04 00:04:55 +08:00
1 parent da4957c52d
commit fb485ebac4
3 files changed
+26 -5

No files matched your search

+1
View File
@@ -167,6 +167,7 @@ private:
std::mutex sessions_mutex_;
std::unordered_map<std::string, std::string> parseQueryParams(const std::string& query);
bool isSafeStaticPath(const std::string& path) const;
std::regex wildcardToRegex(const std::string& pattern);
bool matchPath(const std::string& path, const std::regex& pattern);
http::response<http::string_body> handleRequest(const http::request<http::string_body>& req);
+21 -1
View File
@@ -1,4 +1,5 @@
#include "us/detail/HttpServerImpl.hpp"
#include <cctype>
namespace pmc {
namespace net {
@@ -91,7 +92,7 @@ http::response<http::string_body> HttpServer::handleRequest(const http::request<
auto handler = findRoute(method, target_path);
if (!handler && !static_directory_.empty()) {
if (!handler && !static_directory_.empty() && isSafeStaticPath(target_path)) {
std::string file_path = static_directory_ + target_path;
std::ifstream file(file_path, std::ios::binary);
if (file.is_open()) {
@@ -136,6 +137,25 @@ http::response<http::string_body> HttpServer::handleRequest(const http::request<
return res;
}
// ---- 静态文件路径安全校验(P1-5)----
bool HttpServer::isSafeStaticPath(const std::string& path) const {
// 防御:路径遍历、空字节、绝对 URI 形式、URL 编码遍历
if (path.empty()) return false;
if (path[0] != '/') return false; // 拒绝 "http://..."/相对形式
if (path.find('\0') != std::string::npos) return false; // 拒绝空字节截断
if (path.find("..") != std::string::npos) return false; // 拒绝明文 ".."
// 拒绝 URL 编码遍历/斜杠变体(%2e/./%2f/%5c)
std::string lower;
lower.reserve(path.size());
for (char c : path)
lower.push_back(static_cast<char>(std::tolower(static_cast<unsigned char>(c))));
if (lower.find("%2e") != std::string::npos) return false;
if (lower.find("%2f") != std::string::npos) return false;
if (lower.find("%5c") != std::string::npos) return false;
return true;
}
// ---- Session HTTP 处理 ----
void HttpServer::Session::setRemoteInfo(const std::string& ip, unsigned short port) {
remote_ip_ = ip;