@summersec/dsh-web-auth

securitytested: passnpmMIT

Transport-level authentication gate for the DeepSeek Harness Web GUI with server-side sessions, HttpOnly cookies, IP-based login throttling, and an scrypt password CLI.

下载量 / Downloads
906
依赖体积 / node_modules
0.53 MB
测试时间 / Tested
2026-11-07
DSH 版本 / Version
0.2.2-rc.1

Install

dsh plugin --profile web add @summersec/dsh-web-auth

Sandbox test results

StageResult
1 install✓
2 list✓
3 mount✓
4 boot—

Four stages run in an isolated sandbox: install (network on) → list → mount → boot (last three with no network).

README

dsh-web-auth

![npm](https://www.npmjs.com/package/@summersec/dsh-web-auth)

![Node.js](https://nodejs.org/)

![License: MIT](./LICENSE)

![topic: dsh-plugin](https://github.com/topics/dsh-plugin)

DeepSeek Harness(DSH)Web GUI 的传输层登录门。

官方 webserver 会直接暴露 GUI、插件 bundle、/api、SSE 与 WebSocket,没有统一的身份边界。本插件会禁用未鉴权的官方载体,并替换为兼容 ctx.webServer 契约的服务:在请求进入业务路由之前完成会话校验。

English: [README.md](./README.md)


登录页面


为什么需要它

DSH 自带 Web 宿主适合本地调试,但不是产品级访问控制:

  • 监听 0.0.0.0 或挂到反向代理后,控制面可能被整站暴露。
  • 仅靠前端“登录页”挡不住 /api、静态插件资源、SSE 与 WebSocket upgrade。
  • 会话与口令校验必须落在 HTTP 载体本身。

@summersec/dsh-web-auth 做的事:

1. 禁用 @deepseek-ai/dsh-host-webserver。

2. 插入 webserver-auth,继续提供相同的 ctx.webServer 接口(register / registerUpgrade / registerFallback / tapIndex / host / port)。

3. 用服务端会话 Cookie 拦截 HTTP 与 upgrade 流量。

其他插件仍按原方式注册路由,无需感知鉴权实现。


功能一览

方面 · 行为

保护范围 · HTTP 路由 与 WebSocket / HTTP upgrade

默认模式 · always:即使绑定 127.0.0.1 也要登录

可选模式 · non-loopback:仅非 loopback 绑定时启用鉴权

口令 · scrypt 散列(scrypt$N$r$p$salt$key);明文环境变量仅作临时用途

会话 · 32 字节随机 token、内存存储、滑动过期

Cookie · HttpOnly、SameSite=Strict,按需 Secure

防爆破 · 按客户端 IP 限制登录失败次数,返回 Retry-After

登录体验 · 内置 /auth/login 页面(浅色/深色),支持表单与 JSON

加固 · 登录/登出 Origin 校验、回跳路径净化、鉴权响应 CSP 与防嵌套


环境要求

  • Node.js >= 22
  • 已配置 web profile 的 DeepSeek Harness(peer:@deepseek-ai/cordis ^4.0.1)
  • 进程环境中的口令散列(推荐),或临时明文口令

快速开始

# 1) 生成随机口令与 scrypt 散列(请离线妥善保存口令)
npx --yes @summersec/dsh-web-auth generate

# 2) 仅在当前 shell 导出散列(不要提交到仓库)
$env:WEB_AUTH_PASSWORD_HASH = 'scrypt$...'
$env:WEB_AUTH_USERNAME = 'admin'

# 3) 安装到 web profile
dsh plugin --profile web add @summersec/dsh-web-auth

# 4) 启动 GUI
dsh web

访问原来的 DSH 地址。未登录的浏览器导航会跳转到 /auth/login;API 等非 HTML 客户端收到 401 JSON:

{ "error": "authentication_required" }

登录成功后写入会话 Cookie,并跳回原路径。页面注入的浏览器引导会让同源 API、SSE 和第三方插件请求明确携带该 Cookie;如果内存会话过期或服务重启导致旧会话失效,收到 authentication_required 时会自动回到登录页,避免插件停留在无提示的传输失败状态。

不要把口令或散列写进会共享/提交的项目 .env。优先使用进程环境、密钥管理系统,或仓库外的主机级环境文件。

从源码安装

git clone https://github.com/SummerSec/dsh-web-auth.git
cd dsh-web-auth
npm install

node .\bin\dsh-web-auth.js generate
$env:WEB_AUTH_PASSWORD_HASH = 'scrypt$...'

# 在 DSH 工作区侧,或使用本地路径安装:
dsh plugin --profile web add <path-to-dsh-web-auth>
dsh web

已有口令生成散列(至少 12 个字符):

$env:WEB_AUTH_PASSWORD = '至少十二个字符的强口令'
node .\bin\dsh-web-auth.js hash-password
Remove-Item Env:WEB_AUTH_PASSWORD

也可通过 stdin 传入(CLI 不会接受命令行参数形式的口令):

'至少十二个字符的强口令' | node .\bin\dsh-web-auth.js hash-password

鉴权模式

authMode / WEB_AUTH_MODE · 何时启用鉴权

always(默认) · 始终启用,包括 host: 127.0.0.1

non-loopback · 仅当 host 不是 127.0.0.1 时启用(例如具体局域网 IP)

# 默认:永远需要登录
$env:WEB_AUTH_MODE = 'always'
dsh web

# loopback 可不登录;绑定任何非 loopback 地址都会自动开闸
$env:WEB_AUTH_MODE = 'non-loopback'
dsh web --host 192.168.1.20

当鉴权处于启用状态,且既未配置 passwordHash 也未配置 password 时,插件会在启动阶段直接抛错,避免误上线成“空门”服务。


环境变量

bundle(cordis.patch.yml)将这些变量映射到插件配置:

变量 · 默认值 · 含义

WEB_AUTH_MODE · always · always 或 non-loopback

WEB_AUTH_USERNAME · admin · 登录用户名

WEB_AUTH_PASSWORD_HASH · (无) · 推荐:由 generate / hash-password 生成的 scrypt 散列

WEB_AUTH_PASSWORD · (无) · 明文口令,仅建议临时/实验环境使用

生产与长期部署请优先使用 WEB_AUTH_PASSWORD_HASH。


高级配置

bundle 会:

1. 将官方 webserver 行设为 disabled: true。

2. 插入名为 @summersec/dsh-web-auth 的 webserver-auth 行。

DSH 补丁对配置是整块替换。若要覆盖高级字段,请在 profile 的 cordis.patch.yml 中完整重写 webserver-auth:

- id: webserver-auth
  name: '@summersec/dsh-web-auth'
  inject: [webStartup]
  config:
    host: !!js ctx.webStartup.host ?? '127.0.0.1'
    port: !!js ctx.webStartup.port ?? 3080
    authMode: always
    username: admin
    passwordHash: !!js process.env.WEB_AUTH_PASSWORD_HASH
    sessionTtlMinutes: 720
    maxAttempts: 5
    attemptWindowSeconds: 300
    secureCookie: auto
    trustProxy: false

配置项说明

字段 · 类型 / 取值 · 默认 · 说明

host · IP 或主机名 · 127.0.0.1 · 监听地址;任何非 loopback 绑定都会强制鉴权

port · 0–65535 · 3080 · 监听端口;0 表示系统分配

authMode · always \ · non-loopback · always · 见[鉴权模式](#鉴权模式)

username · string · admin · 单账号共享访问边界

password · string · — · 明文;生产环境避免使用

passwordHash · scrypt$... · — · 必须为 CLI 生成的格式

sessionTtlMinutes · 1–43200 · 720(12 小时) · 滑动过期:每次鉴权成功访问会续期

maxAttempts · 1–1000 · 5 · 同一 IP 在窗口内允许的失败次数

attemptWindowSeconds · 1–86400 · 300 · 失败计数窗口长度

secureCookie · auto \ · always \ · never · auto · 是否附加 Cookie Secure

trustProxy · boolean · false · 是否信任 X-Forwarded-*(仅受控代理后开启)

secureCookie 与 trustProxy

场景 · 建议

本机 loopback HTTP · secureCookie: auto,trustProxy: false

Node 进程直接终结 TLS · secureCookie: auto(加密 socket 时自动加 Secure)

nginx / Caddy / Cloudflare 终结 HTTPS · secureCookie: auto 或 always,trustProxy: true,并保证只有代理能访问 DSH 端口

若在端口可被不可信客户端直连时开启 trustProxy,攻击者可伪造 X-Forwarded-For / X-Forwarded-Proto,削弱 IP 限流或 Cookie 安全语义。务必先锁死网络访问路径。

公网部署请在 DSH 前放置 HTTPS 反向代理。


登录失败限流

插件按客户端 IP 记录登录失败次数。默认配置下,同一 IP 在 300 秒内失败 5 次后,后续登录会收到 429 Too Many Requests 和 Retry-After,直到计数窗口过期。登录成功会清除该 IP 的失败记录。

阈值由以下配置控制:

maxAttempts: 5
attemptWindowSeconds: 300

这项防护有明确边界:

  • 计数保存在进程内存中,服务重启后会清空,多实例之间也不会共享。
  • 限制对象是 IP,不是账号。攻击者轮换来源 IP 时,可以绕过单 IP 阈值。
  • trustProxy: false 时使用 socket 地址;开启 trustProxy 后会信任 X-Forwarded-For 的第一个值,因此 DSH 端口必须只允许受控代理访问。

公网部署时,

…(truncated)

Rendered from the README published on npm. Formatted only, not edited.

Versions

Published on npm::5,最后更新 2026-08-30

Links

GitHub · Homepage · npm

Same category