Files
HomeDash/searxng-settings.yml
HomeDash dea722f51c fix(security): 管理 API 默认拒绝 + 堵住渗透测试报告的 5 个攻击面
2026-10-22 渗透测试报告(report.md)实测确认:统一入口的管理 API 在公网
完全未鉴权,可匿名改路由表、拆登录墙、改门户口令、写门户 HTML、读全部
浏览历史、做内网 SSRF 探测。根因有两层,本次一并修复。

## 根因 1:requireAdminToken 默认放行(代码层)

    if !requireTokenForWrite { return true }

线上没有 NAVI_ADMIN_REQUIRE_TOKEN,于是所有"调了鉴权"的 handler 实际全部
放行——形同虚设。现在改为 fail-closed:

  - 配了 NAVI_ADMIN_TOKEN        → 校验 Bearer token
  - 未配且显式 NAVI_ADMIN_ALLOW_UNAUTHENTICATED=1 → 放行(仅本机调试)
  - 其它                          → 401 拒绝

## 根因 2:login 域没有任何 auth_request(部署层)

kind=auth 的 server 块全站 requireLogin=false(它本身就是登录服务,这点
合理),但 location / 把 /api/、/admin/ 原样反代到 127.0.0.1:3005。两层
都没管 → 管理 API 裸奔。

新增 Route.AdminGuard:开启后 server 级挂 auth_request,只白名单放行登录
流程(/_portal/login|logout|verify、/login、/portal-page、favicon),
其余 /api/、/admin/ 一律要求已登录。

## 同时修掉的 4 个具体问题

1. /api/sync-info 明文回显 syncToken → 不再回显,且要求鉴权。
   泄露该 token 等于浏览器历史的全读写权。
2. /api/history GET 无鉴权 → 与 DELETE 分支一致,要求管理员令牌。
3. /api/frameable 未鉴权 SSRF → 加鉴权 + 内网/回环黑名单。除 IP 字面量外
   还对域名解析结果做校验,防止 localtest.me 之类指向 127.0.0.1 的绕过。
4. dashy 域 bypassPaths 里的 "/api/" 过宽 → 收窄到 "/api/history/"
   (本意只放行浏览记录上报,实际把整个管理 API 暴露了)。

## 回归护栏

新增 admin-server/security_test.go(10 条)与 main_test_setup_test.go。
每条断言都是"改回旧行为就会失败",已用 3 次变异测试验证:
  - 恢复默认放行        → TestAdminAPIFailsClosedByDefault FAIL
  - sync-info 回显 token → TestSyncInfoDoesNotLeakToken FAIL
  - 移除内网黑名单      → TestFrameableBlocksInternalTargets FAIL
  - /api/ 豁免认证      → TestAuthKindWithAdminGuardProtectsAPI FAIL
  - 不给 server 级 auth → 同上 FAIL

测试 56 项全绿。

## 顺带

searxng-settings.yml:停用 360search / ddgw / wikidata / wikipedia
(各自的实测理由见文件内注释),request_timeout 8.0→4.0。
Dockerfile:给 duckduckgo_web 引擎硬编码的 timeout=2 打补丁(经代理必超时)。
2026-10-22 14:08:06 +08:00

77 lines
2.8 KiB
YAML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

use_default_settings: true
general:
instance_name: "JianF Search"
debug: false
search:
safe_search: 0
autocomplete: "baidu"
default_lang: "zh-CN"
server:
port: 8888
bind_address: "127.0.0.1"
secret_key: "changeme-in-production"
image_proxy: true
ui:
static_use_hash: true
default_theme: simple
query_in_title: true
results_on_new_tab: false
redis:
url: false
outgoing:
# 走代理时握手与回源更慢。默认 3.0 / 4.0 会把一批引擎直接判为超时,
# 但调太大同样有害:SearXNG 会等所有引擎超时才返回,单个卡住的引擎
# 就能把整次搜索拖到 request_timeout 那么长(实测 8.0 时出现 19s 长尾)。
# 4.0/6.0 是折中:长尾收敛到 4s 左右,代价是慢引擎当次少结果。
request_timeout: 4.0
max_request_timeout: 6.0
pool_connections: 100
pool_maxsize: 20
# SearXNG curl_cffi 只认这个配置(不走 http_proxy 环境变量)
# 需要代理出网时取消注释并填写你的代理地址
# proxies:
# all://: http://your-proxy:7890
proxies: {}
engines:
- name: google
disabled: false
- name: bing
disabled: false
# www.bing.com 会 302 跳到 cn.bing.com,而 SearXNG 引擎请求不跟随重定向
# (allow_redirects=False)。结果只解析 178 字节的跳转页 -> 0 条且不报错,
# 表现为「Bing 结果异常少」。直接指向 cn.bing.com 可绕开重定向。
base_url: https://cn.bing.com
- name: duckduckgo
# html 端点(no-JS)实测被 DDG 反爬拦死:10/10 返回挑战页(202 + anomaly),
# 高密度请求后连 duckduckgo.com 主站也进入挑战态。改用下面的
# duckduckgo web(走 links.duckduckgo.com/d.js JSON API)。
disabled: true
- name: duckduckgo web
# 自带 firefox TLS 指纹 + default_headers=False,不受 no-JS 挑战页影响。
# 注意它依赖 Dockerfile 里对 _fetch_first_page_link 超时的补丁(上游硬编码
# timeout=2,经代理必超时 -> 引擎被挂起 -> 秒回 0 条)。
disabled: false
- name: 360search
# 实测单条查询 13~15s,且运行时 timeout=20s(高于全局),是长尾延迟的
# 主要来源。需要恢复时改回 false 并重启 searxng。
disabled: true
- name: wikipedia
disabled: false
- name: github
disabled: false
- name: npm
disabled: false
- name: pypi
disabled: false
# 实测上游不可用,默认关闭以避免无谓等待与错误日志:
# baidu -> 302 跳验证页(CAPTCHA,命中后引擎被封 1 小时)
# sogou -> 302 + 引擎自身 AttributeError('SXNG_Response' has no attribute 'next_request')
- name: baidu
disabled: true
- name: sogou
disabled: true
- name: startpage
disabled: true
- name: brave
disabled: true