From 46b8f750ae86aa5686a126b6b9c81ddac5bea5e0 Mon Sep 17 00:00:00 2001 From: qing <1776177662@qq.com> Date: Sat, 25 Jul 2026 13:07:18 +0800 Subject: [PATCH] fixbug --- gateway/README.md | 11 +++++++++++ gateway/example.ini | 9 +++++++++ gateway/src/main.cpp | 25 ++++++++++++------------- 3 files changed, 32 insertions(+), 13 deletions(-) diff --git a/gateway/README.md b/gateway/README.md index 98a943e..6544096 100644 --- a/gateway/README.md +++ b/gateway/README.md @@ -125,6 +125,15 @@ default = http://127.0.0.1:9200 closed = http://127.0.0.1:8005;http://127.0.0.1:8007; opened = http://127.0.0.1:9200;http://127.0.0.1:8006; +[Token] +# Token 有效期(秒),默认 3600 = 1 小时 +keep_time = 3600 + +[CORS] +# 允许跨域的 Origin 白名单(分号分隔) +# 仅命中的 Origin 才会回填 Access-Control-Allow-Origin;缺省为空(不回填) +allowed_origins = https://qsont.me;https://www.qsont.me;http://127.0.0.1:8443;http://localhost:8443 + [Database] path = sqlite3.db ``` @@ -132,6 +141,8 @@ path = sqlite3.db - `Proxy.default`:未带 `Target-Url` header 时的默认转发地址(不需 Token,主要服务前端静态资源)。 - `Proxy.opened`:允许外部带 Token 访问的内部服务白名单(分号分隔)。 - `Proxy.closed`:仅记录用途,实际靠"不在 opened 中即拒绝"实现隔离。 +- `Token.keep_time`:登录签发 Token 的有效期(秒),缺省 3600。 +- `CORS.allowed_origins`:OPTIONS 预检允许跨域的 Origin 白名单(分号分隔),缺省为空(不回填 ACAO)。 ## 部署模式 diff --git a/gateway/example.ini b/gateway/example.ini index 617b5f6..f6fbd24 100644 --- a/gateway/example.ini +++ b/gateway/example.ini @@ -11,5 +11,14 @@ default = http://127.0.0.1:9200 closed = http://127.0.0.1:8005;http://127.0.0.1:8007; opened = http://127.0.0.1:9200;http://127.0.0.1:8006; +[Token] +# Token 有效期(秒),默认 3600 = 1 小时 +keep_time = 3600 + +[CORS] +# 允许跨域的 Origin 白名单(分号分隔) +# 仅命中的 Origin 才会回填 Access-Control-Allow-Origin;缺省为空(不回填) +allowed_origins = https://qsont.me;https://www.qsont.me;http://127.0.0.1:8443;http://localhost:8443 + [Database] path = sqlite3.db diff --git a/gateway/src/main.cpp b/gateway/src/main.cpp index 9a0ae2d..ac2d552 100644 --- a/gateway/src/main.cpp +++ b/gateway/src/main.cpp @@ -37,7 +37,11 @@ std::vector split(const std::string& s, char delim) { std::istringstream stream(s); std::string token; while (std::getline(stream, token, delim)) { - tokens.push_back(token); + // 跳过空串:避免 "a;b;" 末尾分号产生 "" 元素 + // 防御白名单匹配场景下空串被误判为命中 + if (!token.empty()) { + tokens.push_back(token); + } } return tokens; } @@ -291,6 +295,8 @@ static bool _TLS = false; static std::string _DEFT_URL; static std::vector _OPEN_URL; static std::string _DB_PATH; +static int _TOKEN_KEEP_TIME = 3600; // Token 有效期(秒),可由 [Token] keep_time 配置 +static std::vector _CORS_ORIGINS; // CORS 允许的 Origin 白名单,可由 [CORS] allowed_origins 配置 /* instance items */ static std::unique_ptr _SERVE; @@ -399,6 +405,8 @@ int main(int argc, char **argv) { _DEFT_URL = cf.get("Proxy.default", ""); _OPEN_URL = split(cf.get("Proxy.opened", ""), ';'); _DB_PATH = cf.get("Database.path", ""); + _TOKEN_KEEP_TIME = cf.get("Token.keep_time", 3600); + _CORS_ORIGINS = split(cf.get("CORS.allowed_origins", ""), ';'); } catch (ConfIni::IniConfigureFileParseException &e) { std::cerr << "ERROR: " << e.what() << std::endl; @@ -507,19 +515,12 @@ void registerRoutes(HttpServer &server) { pmc::net::http::response res; res.result(pmc::net::http::status::ok); - // CORS 白名单(P1-4):仅允许官方域名,防止任意网站跨域调用 - // 原配置 Access-Control-Allow-Origin: * 过宽,XSS 拿到 token 后可跨域读取数据 + // CORS 白名单:从 [CORS] allowed_origins 加载,缺省为空(不回填 ACAO) // 动态回填 Origin:仅当请求 Origin 命中白名单时才返回该值,否则不返回 ACAO 头 - static const std::vector allowed_origins = { - "https://qsont.me", - "https://www.qsont.me", - "http://127.0.0.1:8443", // 本地开发调试 - "http://localhost:8443" - }; auto origin_it = req.base().find("Origin"); if (origin_it != req.base().end()) { std::string origin = std::string(origin_it->value()); - for (const auto& allowed : allowed_origins) { + for (const auto& allowed : _CORS_ORIGINS) { if (origin == allowed) { res.set(pmc::net::http::field::access_control_allow_origin, origin); res.set(pmc::net::http::field::vary, "Origin"); @@ -709,12 +710,10 @@ http::response handleLogin( auto _PRIV = MyRSA::Private_Key::from_pem(_KEYGEN->get_private_key_pem()); - int keep_time = 3600; - json::value jv_t = { {"user", username}, {"created_at", LocalTime::getCurrent()}, - {"keep_time", keep_time} + {"keep_time", _TOKEN_KEEP_TIME} }; std::string data = json::serialize(jv_t); std::string token = Base64::base64_encode(data);