dsh 000ca41501 fix: treat Origin: null as absent instead of rejecting login
The audit diagnostics showed the real browser posting the login form with
Origin: null (opaque context — sandboxed iframe, privacy proxy, or browser
isolation product), which is not an attack signal. Skip the origin check
for the literal "null" value; real cross-site posts with a concrete
foreign origin are still rejected.

Tests: Origin:null POST tolerated, foreign origin still 403.
2026-08-16 01:43:13 -04:00

panel-auth — DSH 面板访问密码插件

dsh web 面板加一层原生 HTTP 认证(自绘登录页 + Basic + 签名 Cookie), 挂载在 /root/.dsh/profiles/web/cordis.patch.yml 的用户补丁层,升级 DSH 不会丢。

认证逻辑

  • 浏览器访问(Accept: text/html):匿名时返回内置登录页(无 JS、CSP 收紧), 表单 POST 到 /panel-auth/login,成功后签发 Cookie 并跳回原目标地址。
  • API / 脚本(fetch、curl 等):保持经典 401 + WWW-Authenticate: Basic 契约, 仍可用 Basic 凭据直接调用,成功后同样签发 Cookie。
  • WebSocket 升级:匿名一律 401,带 Cookie 放行(浏览器对 WS 不保证携带 Authorization 头,因此依赖 Cookie)。
  • /panel-auth/logout:清除 Cookie 并回到登录页。
  • Cookie 默认 30 天(cookieTtlSeconds),HttpOnly + SameSite=Lax。
  • Fail-openusers 为空或 secret 缺失/过短时不拦截任何请求, 配置写错不会把面板锁死。配置每次请求实时读取,改密码热生效。

登录日志(审计)

  • 所有登录活动写入结构化 JSONL 文件,默认 /root/.dsh/panel-auth-audit.jsonl(可用 auditLogPath 配置修改)。
  • 事件类型:
    event 含义
    login-ok 登录成功(含用户名、IP、User-Agent
    login-fail 登录失败(含用户名、IP、UA、reasonbad-credentials / missing-fields / cross-origin / body-too-large
    logout 主动登出
    challenge 匿名浏览器导航被重定向到登录页
    reject 匿名 API / WebSocket 请求被拒绝(含方法、路径)
  • 每条含 tsISO 时间)、ip(优先 X-Forwarded-For,见下)、ua
  • 文件超过 5MB 自动轮转为 <path>.1
  • 查看示例:tail -f /root/.dsh/panel-auth-audit.jsonl | jq .

IP 说明:面板经 Caddy 反代时,直连 socket 是回环地址;插件在检测到回环 来源时会取 X-Forwarded-For 的首个值作为真实 IP(Caddy 默认会带上该头)。

修改密码

cd /root/.dsh/profiles/web/panel-auth
node hash.js admin 新密码        # 输出新 passwordHash

把输出的 passwordHash 替换进 ../cordis.patch.yml 后(loader HMR 热应用; 如未生效则 systemctl restart dsh-web)。

新增用户

cordis.patch.ymlusers 列表里再加一组 username/passwordHash

更换签名密钥

node hash.js --secret           # 生成新 secret

替换 cordis.patch.ymlsecret 后重启。注意:更换密钥会使所有已签发 Cookie 立即失效,所有人需重新登录。

应急解锁(忘记密码时)

编辑 /root/.dsh/profiles/web/cordis.patch.yml

  • 临时把 users 置为 [](fail-open,面板恢复无密码状态),或
  • 用上面的命令生成新哈希替换。

文件

  • index.js — 插件本体(登录页、认证守卫、审计日志、webServer 包装)
  • crypto.js — scrypt 哈希 / HMAC Cookie 签名(无依赖,纯 node:crypto
  • hash.js — 生成密码哈希与随机密钥的 CLI
  • test.mjs — 单元测试(node test.mjs,覆盖 15 组流程)
S
Description
DSH web panel password gate plugin: HTTP Basic auth + signed cookie, fail-open
Readme
158 KiB
0 Stars 1 Watchers 0 Forks
Languages
JavaScript 100%