🎁 福利专区全网大模型免费应用 + 新用户福利 + 注册活动入口,低成本玩转 AI

远程访问认证 GDWhisper/dsh-web-startup-auth

DeepSeek Harnessv0.1.13
GDWhisper4 天前有提交已提供中文文档扫描:含敏感能力

DSHDeepSeek Harness远程 Web 启动 + 用户名/密码认证插件。 | DeepSeek…

54.5/100
综合分
65
GitHub 星标
591
npm 周下载
—/5
用户评分

数据截至 2026/10/30 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。

安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add dsh-web-startup-auth
npm 源 · dsh-web-startup-auth 的发布者账号已校验与本仓库一致

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:已验证
是什么
dsh 原生插件 · security
装得上吗
本站已在 dsh 0.2.1-rc.2 下真实安装成功
非静态推断
L5 · 运行时冒烟等级说明 →
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
活跃:最近一次提交在 4 天前
档位由哪些信号合成

本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。

验证判据与等级说明 →
社区实装还没有人打卡 · 装过的第一个就是你
安装兼容性检查✓ 自动检查通过
展开查看检查明细 ↓

以下结论由程序自动检查 npm 包、engines 声明与入口文件得出,未做人工实机验证——能装不等于用着没问题。

✓npm 包dsh-web-startup-auth @ 0.1.13
✓Node 引擎未声明 engines.node
✓dsh CLI 依赖要求 >=0.1.7-rc.1 <0.3.0-0 · 最新 0.2.1-rc.5 兼容
✓入口文件main/exports/bin 已声明

验证方式:npm registry 存在性 + package.json 静态校验 · 最后检查 2026/11/2 17:39:16

安全扫描自动 · 静态分析源码
v2.7.0
🔵 扫描:含敏感能力尚无人工评估
展开查看扫描说明与证据 ↓

静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。

可执行外部命令读写/删除本地文件发起外部网络请求
查看扫描证据(共 38 处,展示前 30 条)
  • 执行外部命令固定命令
    lib/startup.js:118
    execSync('stty -echo', { stdio: 'ignore' });
  • 执行外部命令固定命令
    lib/startup.js:129
    execSync('stty echo', { stdio: 'ignore' });
  • 发起网络请求
    lib/client.js:59
    const res = await fetch("/api/auth/status");
  • 发起网络请求
    lib/client.js:69
    const res = await fetch("/api/auth/policy");
  • 发起网络请求
    lib/client.js:80
    const res = await fetch("/api/auth/session-max-age");
  • 发起网络请求
    lib/client.js:91
    const res = await fetch("/api/auth/challenge-policy");
  • 发起网络请求
    lib/client.js:371
    await fetch("/api/auth/logout", { method: "POST" });
  • 发起网络请求
    lib/client.js:394
    const res = await fetch("/api/auth/change-password", {
  • 读取本地文件
    lib/credential-store.js:66
    if (!existsSync(credentialFile()))
  • 读取本地文件
    lib/credential-store.js:69
    return JSON.parse(readFileSync(credentialFile(), 'utf8'));
  • 读取本地文件
    lib/credential-store.js:78
    if (!existsSync(dir)) {
  • 写入本地文件
    lib/credential-store.js:79
    mkdirSync(dir, { recursive: true, mode: 0o700 });
  • 写入本地文件
    lib/credential-store.js:92
    writeFileSync(credentialFile(), JSON.stringify(data, null, 2), { encoding: 'utf8', mode: 0o600 });
  • 读取本地文件
    lib/credential-store.js:102
    if (existsSync(credentialFile())) {
  • 写入本地文件
    lib/credential-store.js:103
    chmodSync(credentialFile(), 0o600);
  • 发起网络请求
    lib/client/index.js:40
    const res = await fetch('/api/auth/status');
  • 发起网络请求
    lib/client/index.js:52
    const res = await fetch('/api/auth/policy');
  • 发起网络请求
    lib/client/index.js:65
    const res = await fetch('/api/auth/session-max-age');
  • 发起网络请求
    lib/client/index.js:78
    const res = await fetch('/api/auth/challenge-policy');
  • 发起网络请求
    lib/client/index.js:365
    await fetch('/api/auth/logout', { method: 'POST' });
  • 发起网络请求
    lib/client/index.js:381
    const res = await fetch('/api/auth/change-password', {
  • 读取本地文件
    src/credential-store.ts:91
    if (!existsSync(credentialFile())) return undefined
  • 读取本地文件
    src/credential-store.ts:93
    return JSON.parse(readFileSync(credentialFile(), 'utf8')) as CredentialFile
  • 读取本地文件
    src/credential-store.ts:102
    if (!existsSync(dir)) {
  • 写入本地文件
    src/credential-store.ts:103
    mkdirSync(dir, { recursive: true, mode: 0o700 })
  • 写入本地文件
    src/credential-store.ts:117
    writeFileSync(credentialFile(), JSON.stringify(data, null, 2), { encoding: 'utf8', mode: 0o600 })
  • 读取本地文件
    src/credential-store.ts:128
    if (existsSync(credentialFile())) {
  • 写入本地文件
    src/credential-store.ts:129
    chmodSync(credentialFile(), 0o600)
  • 执行外部命令固定命令
    src/startup.ts:179
    execSync('stty -echo', { stdio: 'ignore' })
  • 执行外部命令固定命令
    src/startup.ts:189
    execSync('stty echo', { stdio: 'ignore' })
扫描于 2026/11/3(0 天前) · 范围 入口闭包 + 全包扫描 · 来源 npm 发布包

静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。

依赖的 DSH / Cordis 模块
@deepseek-ai/dsh-credentials@deepseek-ai/dsh-cmdline@deepseek-ai/dsh-host-webserver@deepseek-ai/schemastery@deepseek-ai/dsh-client-ui-settings@deepseek-ai/dsh-client-ui-slots@deepseek-ai/cordis@deepseek-ai/dsh
给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个

界面预览

1 张 · 点击查看大图

功能亮点

  • 远程Web启动
  • 用户名密码认证
v0.1.132026-10-17
基线推进到 dsh 0.2.1 正式通道,双线兼容适配也随之转正。 · 变更内容 dsh-web-startup-auth v0.1.13,以 dsh next 通道为基线(0.2.1-rc.2)。 · 新增 · 兼容 dsh 0.2.1 线:上游在该版本收紧了 --host 值域(只收单个具体 IP,拒绝通配绑定),本插件原地拓宽 schema,--host 0.0.0.0 与 --host :: 继续可用(#f924307)。 · 透传上游两个新启动能力:--public-url(声明反代后的对外访问 URL)与 --tls-cert/--tls-key(直连 HTTPS,自签证书也可用)。开启 HTTPS 后,会话 cookie 与自动补发的浏览器 cookie 都会带上 ; Secure(#f924307)。 · 依赖基线推进到 dsh 0.2.1-rc.2(next 通道);在低于 0.2.1 的 dsh 上使用新旗标会明确报错,提示需要 dsh ≥ 0.2.1,而不是被静默忽略(#9cbfbb8)。 · 修复 · 无。 · 验证 · 230 个 vitest 测试全绿;typecheck / build 干净。 · 隔离实例实机(dsh 0.2.1-rc.2)三形态全绿:--host 0.0.0.0 登录墙十二探针、具体 IP + TLS 自签全链、--host :: 双栈信任围栏;flag 门禁报错文案与上游逐字一致。
v0.1.122026-09-29
加固 API 会话防护(双层闸门 + dsh 版本门槛),支持 IPv6 绑定,基线跟进 0.2.0-rc.1 · 变更内容 dsh-web-startup-auth v0.1.12,以 dsh next 通道为基线(0.2.0-rc.1)。 · 新增 · dsh web --host 支持 IPv6 绑定(如 --host ::,Linux 下默认双栈,IPv4 也能连):纯 IPv6 的局域网不再卡在启动、也不会被挡在登录页之前(#3712227)。 · API 访问新增第二层会话防护:只有登录会话(或真本机访问)能调用共享 API,上游的 30 天浏览器凭据不能单独作为 API 通行凭据;两层防护互为保险,任一侧上游接口变化都不会让 API 裸奔(#dea2c55)。 · 声明支持的 dsh 版本范围(0.1.7-rc.1 起、0.3.0 之前):跑在不兼容的 dsh 上时插件会被明确跳过并打印原因,不再静默运行(#dea2c55)。 · 基线跟进 dsh 0.2.0-rc.1(next 通道),依赖声明同步升级(#de9a149)。 · 修复 · 无。 · 验证 · 213 个 vitest 测试全绿(含 IPv6 绑定与信任围栏用例);typecheck / build 干净;IPv6 双栈与围栏经隔离实例实机验收。
v0.1.112026-09-26
新增可选滑块拼图验证,凭据路径与 OAuth 回调适配 dsh 0.1.7-rc.1 · 变更内容 dsh-web-startup-auth v0.1.11,以 dsh next 通道为基线(0.1.7-rc.1)。 · 新增 · 登录表单前可选加一道滑块拼图验证(设置面板 → 认证 → 人机验证,默认关闭):开启后,提交密码前先拼对图。这是应网友要求加的彩蛋,不是安全边界——答案画在图上,脚本能读出来(#4430a9a)。 · 每道拼图还画一个假缺口,形状永远和真缺口不同,所以解题靠观察,不靠背答案(#4430a9a)。 · 修复 · DeepSeek 账号登录不再被登录墙吃掉:/oauth/callback 现在未登录也能访问,换浏览器点登录链接也能正常回跳,授权码不再丢失(#4430a9a)。 · 凭据文件跟随 $DSH_HOME:自定义 DSH_HOME 或跑多实例时,不再和 ~/.dsh 共用同一份账号(此前新实例可能读到另一实例的管理员账号)(#4430a9a)。 · 依赖声明跟进到 dsh 0.1.7-rc.1(5 个 @deepseek-ai/dsh-* 包),构建前先清空 lib/,删掉源文件后旧产物不会再跟着发布包走(#a5e1f58)。 · 验证 · 180 个 vitest 测试全绿;typecheck / build 干净(重新构建后 lib/ 零漂移,产物可复现)。
数据来自仓库的 GitHub Release,可能与插件实际版本不一致。

README

由 DeepSeek 最新模型翻译生成
dsh-web-startup-auth DSH(DeepSeek Harness)远程 Web 启动 + 用户名/密码认证插件。 ⚠️ 版本跟进声明:本项目只跟进官方 dsh 的正式发布通道(next dist-tag),不跟进 alpha 预览通道(当前基线:dsh 0.2.1-rc.2,依赖 5 个 @deepseek-ai/dsh- 已 bump 到 ^0.2.1-rc.1(caret 在 0.2.1 线内自动解析到最新 rc);适配审查与观察哨见 docs/upgrade-dsh-0.2.0-playbook.md)。0.2.1 线双时代兼容已落地并随 bump 生效(通配 --host 的 schema 拓窗、LAN 信任的官方消费路径、TLS/--public-url 透传;在 0.2.1 之前的 dsh 上这些新 flag 会明确报错而非静默忽略)。 登录页 原版 @deepseek-ai/dsh-web-app/startup 出于安全考虑硬拒绝 --host 0.0.0.0;本插件替换它,并配一个带登录/注册页的认证插件,让 dsh web 可以在局域网(或任何非回环接口)上安全暴露浏览器界面。
展开完整文档(README 剩余 1 节)
dsh-web-startup-auth

DSH(DeepSeek Harness)远程 Web 启动 + 用户名/密码认证插件。

⚠️ 版本跟进声明:本项目只跟进官方 dsh 的正式发布通道(next dist-tag),不跟进 alpha 预览通道(当前基线:dsh 0.2.1-rc.2,依赖 5 个 @deepseek-ai/dsh- 已 bump 到 ^0.2.1-rc.1(caret 在 0.2.1 线内自动解析到最新 rc);适配审查与观察哨见 docs/upgrade-dsh-0.2.0-playbook.md)。0.2.1 线双时代兼容已落地并随 bump 生效(通配 --host 的 schema 拓窗、LAN 信任的官方消费路径、TLS/--public-url 透传;在 0.2.1 之前的 dsh 上这些新 flag 会明确报错而非静默忽略)。

登录页

原版 @deepseek-ai/dsh-web-app/startup 出于安全考虑硬拒绝 --host 0.0.0.0;本插件替换它,并配一个带登录/注册页的认证插件,让 dsh web 可以在局域网(或任何非回环接口)上安全暴露浏览器界面。

特性

- 远程启动:--host 0.0.0.0 可用,替代原版启动器的硬性拒绝;具体 IP 字面量(如 --host 192.168.1.5、--host ::1、--host fd00::1)与通配 :: 同样可用(#35;非规范 IPv6 拼写自动规范化,带 zone 的(%eth0)与 IPv4-mapped(::ffff:a.b.c.d)写法拒绝)。纯 IPv6 网络下 0.0.0.0 只绑 IPv4、界面不可达;:: 在 Linux 默认双栈(net.ipv6.bindv6only=0),同时监听 IPv6 与 IPv4-mapped,比 0.0.0.0 覆盖更全;bindv6only=1 的系统上 :: 仅 IPv6。另透传上游两个启动能力(需 dsh ≥ 0.2.1):--public-url <url>(声明对外访问 URL)与 --tls-cert/--tls-key(直连 HTTPS,见「安全说明」);在低于 0.2.1 的 dsh 上使用会明确报错提示需要 dsh ≥ 0.2.1,而不是静默忽略。
- 登录/注册页:远程访问首次会引导设置管理员账号密码,之后进入登录页;与 DSH 黑白蓝风格一致;颜色跟随系统明暗偏好(prefers-color-scheme)。
- 免登录的本地访问:判定依据是请求本身而非启动参数——TCP 对端地址与 Host 头都是回环时才免认证。所以本机浏览器直接访问 http://127.0.0.1:<端口>/ 无需注册或登录;局域网客户端、以及反向代理转发来的请求(Host 是公网域名)一律需要会话。免登录不等于已登录:本机没有会话 cookie,认证页显示的是「管理员账号」而不是「当前登录」,也不会给出退出登录入口(没有会话可退)。
- 可选的「本机登录校验」:默认本机免登录;管理员可在设置面板 → 认证 → 登录要求里把这个开关打开,之后连本机地址也要求会话(多人共享服务器时用它禁止同机其他账号免登录)。开关须先有管理员账号才能启用(未注册时后端会拒绝,设置页会先引导去注册)。
- 可选的人机验证(滑块拼图):应网友要求加上了没什么用的防人机验证,有兴趣可以开启试试 XD —— 在设置面板 → 认证 → 人机验证里滑动开启,登录时会让你把一块拼图拖进缺口。每张图里画了两个缺口:拼图块和真缺口是同一种形状(凸块方向每张随机:右/左/上/下,也可能没有凸块,共 5 种),旁边的假缺口形状永远不同,拼图块只塞得进形状相同的那个(纯装饰,脚本照样秒过)。
说它没什么用是有实测依据的:拼图的答案必须画在图上(人要看着它拖),所以脚本几十行就能读出来——本插件按常规做法实现的三种变体,用约 30 行脚本攻击的命中率分别是 100%(缺口涂暗)、100%(只描边)、97%(撒噪点,但那一版连人也解不出来)。之前试过的 4 位数字图片题同样被模板匹配打到 96.7%。当个乐子,别当安全边界。 详见 docs/agent/human-verification.md。
- 登录限流硬化:每 IP 10 分钟内 5 次失败锁 30 秒,外加全局指数退避——所有来源累计失败超过 20 次后按台阶翻倍(5 秒 → 10 秒 → …封顶 5 分钟),用来挡住"一千个 IP 各试几次"的分布式撞库;429 带 Retry-After。本机(真回环且未开启「本机登录校验」)豁免全局退避,避免攻击者借此把管理员锁在自己机器外面。
- 会话认证:登录后下发签名 cookie(dsh_sid,默认 14 天有效、可在设置面板调节(3–180 天档位),HttpOnly + SameSite=Lax;TLS 监听下自动追加 ; Secure)。
- API 保护:所有注册路由(/api/ 及第三方插件的 RPC 路由,除 /api/auth/ 与 /login)必须携带有效会话,否则返回 401/拒绝握手。
- 设置面板「认证」标签页:向 DSH 设置面板注入"认证"页,提供退出登录(仅在持有会话时出现)、修改用户名、修改密码与会话有效期档位选择。标签在导航栏里显示盾牌+勾图标(上游不允许注册方指定图标,由本插件在前端替换默认的齿轮)。界面颜色全部使用 DSH 主题 token,跟随明/暗主题自动切换(#25)。
- 远程场景修复(局域网 HTTP 访问的坑):
- crypto.randomUUID polyfill —— 非安全上下文下该 API 缺失,会导致所有 RPC 失败。
- 原生浏览器认证桥接 —— 从 dsh 0.1.2 起(当前基线 0.2.1-rc.2),上游自带浏览器认证(dsh-auth- 签名 cookie),/api 与 index.html 一律要求携带,连回环都不豁免(本机也得先换 token URL)。本插件为已通过自己认证的访问者自动补发该 cookie:这类访问者要么持有 dsh_sid 会话,要么是 TCP 对端 + Host 双回环的本地请求。页面导航经一次 200 跳板(meta refresh 回原路径)即带上,登录响应直接下发(不用 3xx:重定向响应里新设的 cookie 不会带给重定向目标,补发会被逐跳重放成 ERR_TOO_MANY_REDIRECTS),全程无需接触启动打印的 token URL——「账号/密码 + 可撤销会话」仍是唯一认证入口,上游 cookie 只是通过上游闸门的凭据。

安装

本插件是一个 DSH bundle(package.json 的 dsh.bundle.patch 声明了随包分发的 cordis.patch.yml)。用 dsh plugin 安装后,包会被加入 profile 的 dsh.profile.bundles,补丁层自动生效,无需手动编辑任何配置文件。

方式一:从源码安装
git clone <仓库地址>
cd dsh-web-startup-auth
npm install # 安装构建依赖(typescript 等)
npm run build # 编译 src/ 到 lib/(插件运行时加载 lib/ 下的产物)
dsh plugin --profile web add .

方式二:从 npm registry 安装(已装过旧版本时执行同一条命令即可升级)
dsh plugin --profile web add dsh-web-startup-auth@latest

dsh plugin 是 pnpm 转发器,--profile <name> 必填;add . 会把当前目录以 link: 方式装进 profile。

版本范围:本插件声明支持 dsh >=0.1.7-rc.1、不支持 0.3.0 起的版本线(含其预发布版)。运行中的 dsh 超出范围时,dsh 会跳过本 bundle 并打印原因——这是刻意的 fail-loud:宁可不加载,也不在未适配验证过的 dsh minor 版本线上静默运行。注意粒度是 minor 线:同一条线内的后续版本(含 rc 等预发布)会照常加载,每出一条新 minor 线要先完成适配再考虑放宽范围。确需强行启用可走 profile 的 version exemption(插件管理器文档)。

启动:

dsh web --host 0.0.0.0
纯 IPv6 网络(或想同时覆盖 IPv6):
dsh web --host :: --port 8080
具体地址绑定(如只服务某块网卡):
dsh web --host 192.168.1.5
直连 HTTPS(需 dsh >= 0.2.1;自签证书同样可用,浏览器会提示不受信任):
dsh web --host 0.0.0.0 --tls-cert cert.pem --tls-key key.pem

安装时已自动应用补丁,无需再用 --patch 叠加——重复叠加会把插件再插入一遍,导致重复。

使用

1. 浏览器访问 http://<主机IP>:<端口>/(在本机则用 http://127.0.0.1:<端口>/,无需登录)。IPv6 地址在 URL 中必须加方括号:http://[<IPv6地址>]:<端口>/。注意:--host :: 启动时终端只打印回环 URL(上游的 LAN 地址推导只枚举 IPv4),局域网 IPv6 地址请用上面的形式手动拼接;打印的回环 URL 固定是 http://127.0.0.1:<端口>/(上游硬编码),bindv6only=1 的系统上 :: 是纯 IPv6 套接字、它不通,本机请用 http://[::1]:<端口>/。
2. 远程访问首次会跳转到 /login,显示"设置管理员账号密码"注册表单。
3. 注册成功后自动登录并进入主界面;之后访问需登录。
4. 退出登录 / 修改用户名 / 修改密码 / 调整会话有效期 / 开关拼图验证:打开主界面设置面板 → 认证标签页(同时也是一个独立入口,/api/auth/logout 清除会话 cookie)。

如果需要在本地设置账号密码(本机默认免登录,界面不会自动跳登录页):

1. 浏览器打开 http://127.0.0.1:<端口>/login —— 未注册时该页直接显示注册表单。
2. 或进设置面板 → 认证,页顶「尚未设置管理员账号」处点「前往设置管理员账号」。

注册后本机仍免登录;想让本机也要登录,到认证 → 登录要求打开「本机登录校验」(需先有账号)。开关打开后本机也要走 /login(页面会立即跳过去),登录后认证页才会显示「当前登录」和退出登录入口。

凭据与会话密钥保存在 $DSH_HOME/web-auth.json($DSH_HOME 未设置时即 ~/.dsh/web-auth.json,与 dsh 自身数据同目录;可用环境变量 DSH_WEB_AUTH_FILE 覆盖整个路径):

- 密码使用 scrypt(随机盐,64 字节)散列存储,不保存明文。
- 会话 cookie 用随机生成的密钥做 HMAC-SHA256 签名,防伪造。有效期档位(sessionMaxAgeDays,默认 14)也存在这个文件里,可在设置面板调节;调整只对新签发的会话生效。
- 忘记密码:在服务器本机执行 dsh --profile web auth-reset,交互式设置新密码(或 dsh --profile web auth-reset --password <新密码> 非交互)。重置会轮换会话密钥,所有已登录的浏览器都需要重新登录一次。
- 修改用户名 / 修复含控制字符的用户名:dsh --profile web auth-reset --username <新用户名>(可与 --password 同用)。同样轮换会话密钥。用户名在注册/登录/修改时统一剥除 C0 控制字符(0x00–0x1F)与 DEL(0x7F)——旧版本若已把含 DEL 的用户名原样存盘,用它即可修复。
- 兜底方案:删除凭据文件($DSH_HOME/web-auth.json,默认 ~/.dsh/web-auth.json)并重启,即可重新注册。这只影响登录状态——已登录的浏览器需要再登录一次,不会删除任何会话记录或历史数据(它们存在 ~/.dsh/sessions/ 等位置,与本文件无关)。
- auth-reset 不能用来首次创建账号:它要求已有凭据,否则报「尚未注册管理员账号,无需重置」。首次只能用上面的注册页。

常见问题

Q:怎么在本地设置账号密码?必须代理到公网才能配置吗?

不需要,代理到公网不是前提。本机默认免登录(不会自动跳登录页),所以请在浏览器手动打开 http://127.0.0.1:<端口>/login——未注册时这一页直接显示注册表单;或者进设置面板 → 认证,页顶「尚未设置管理员账号」处点「前往设置管理员账号」。注意命令行 dsh --profile web auth-reset 只能改已有账号的密码/用户名,不能用来首次建号。

Q:本机不想登录,远程才要登录,可以吗?

这就是默认行为。设置面板 → 认证 → 登录要求默认关闭,即本机(真回环)免登录;远程客户端一律需要会话。打开这个开关(需先有管理员账号)则本机也强制登录,适合多人共用一台服务器时禁止同机其他账号免登录。没有「受信主机免登录」这种开关,--trusted-host 也不参与认证判断。

Q:忘记密码 / 想改用户名?

dsh --profile web auth-reset # 交互式
dsh --profile web auth-reset --password <新密码> # 非交互
dsh --profile web auth-reset --username <新用户名>

都会轮换会话密钥,所有已登录的浏览器需要重新登录一次。兜底方案是删掉凭据文件($DSH_HOME/web-auth.json,默认 ~/.dsh/web-auth.json)再重启重新注册——不影响历史会话数据。

Q:访问某个接口返回 403,是本插件拦的吗?

本插件的认证失败只会返回 401 或者跳转到登录页,从不返回 403。所以看到 403 先看响应体的形状来定位来源:

| 响应体 | 来源 | 怎么办 |
| 401,或页面被送到 /login | 本插件(会话无效) | 重新登录 |
| 纯文本 forbidden | 上游 dsh 的 Host 信任围栏 | 检查反向代理是否保留了真实 Host,必要时加 --trusted-host <域名> |
| {"error":"request-not-trusted"} | 第三方插件自带的回环限制 | 见下一条 |
| transport failure ... HTTP 403 | 第三方插件自带的回环限制 | 见下一条 |

Q:第三方插件(如 dsh-im、dsh-workbuddy-connect)在局域网返回 403?

这是该插件给它自己的接口加的回环地址限制(只放行 127.0.0.1 / localhost),与本插件和你的服务器都无关——本插件只管 /api/ 的会话闸门,管不到别的插件挂在 webServer 上的路由。

- dsh-im:提供了开关,在 profile 的 cordis.patch.yml 里加 rpcAuthority: trusted-host;新版已默认放行,一般不用配。
- 没有开关的插件(如 dsh-workbuddy-connect):只能去该插件的仓库提 issue,请求提供一个可配置的等价开关。

临时绕过办法是在你自己的电脑上做一次 SSH 端口转发,让浏览器通过回环地址访问,限制就不会触发:

ssh -L 3080:127.0.0.1:3080 用户名@<服务器IP>

保持这个窗口不关,浏览器打开 http://127.0.0.1:3080 即可。注意此时所有请求的 Host 都是回环,会被当作本机访问——不要在不受信任的网络上这么做。

Q:设置面板报「加载提供方目录失败 / settings are unavailable in this browser」?

最常见的原因是装到了旧版本。这个症状在 0.1.1 就已修好,0.1.5 起换了实现(远程浏览器下 settings 面板正常渲染)。先确认版本:

dsh plugin --profile web add dsh-web-startup-auth@latest

add 时务必带 @latest:不带的话 pnpm 会一直复用首次写入的版本号,之后用 update 也升不上去(历史上因此排查过多次)。

Q:升级 dsh 之后插件行为异常?

- 从源码安装的:改完源码要 npm run build,然后重启 dsh web(lib/ 是入库的构建产物,不构建等于没改)。
- 从 npm 安装的:重跑一次上面那条 add dsh-web-startup-auth@latest。
- 本插件支持 dsh >=0.1.7-rc.1,不支持 0.3.0 起的版本线。超出范围时 dsh 会跳过本 bundle 并在启动日志里打印原因(刻意的 fail-loud),在启动日志里搜 skipped 就能确认。

Q:登录页和首页来回循环跳转 / Safari 报 ERR_TOO_MANY_REDIRECTS?

- 首页与 /login 互跳的死循环:0.1.3 起已修复(0.1.2 的认证判定只看启动参数、不看请求本身,反代场景下会误判)。
- Safari / iOS 上补发原生 cookie 的跳转被反复重放:0.1.11 起已修复。

两者如果仍出现,先确认装的是最新版,清一下该站点的 cookie 再试。

Q:拼图验证能挡住脚本吗?

挡不住,如「特性」一节所说——答案就画在图上,脚本几十行就能读出来。当个乐子,别当安全边界。

索引

如果您在寻找开箱即用的专为 Agent 时代研发的 IDE,推荐您使用 Omniterm

安全说明

- 本插件提供认证,但不提供传输加密。明文 HTTP 下,凭据与流量会被同一网络中的抓包者看到,建议只在可信内网使用,或在前面部署 HTTPS 反向代理;dsh 0.2.1 起也可用 --tls-cert/--tls-key 直连 HTTPS——此时会话 cookie 与补发的原生 cookie 自动带上 ; Secure(低于 0.2.1 的 dsh 没有这个能力,用到时会明确报错,提示需要 dsh ≥ 0.2.1)。
- 会话有效期默认 14 天,可在设置面板「认证」标签页调节(3/7/14/30/60/90/180 天档位,持久化在凭据文件里);调整只影响新签发的会话,已登录的会话保持签发时的有效期。
- 密码散列用 Node 内置的 crypto.scryptSync,无第三方依赖。
- 会话无法在服务端撤销:dsh_sid 是自包含的签名 cookie,/api/auth/logout 只清除浏览器一侧的 cookie。cookie 一旦泄露(比如明文 HTTP 下被嗅探),在有效期内无法单独吊销(上限就是设置面板所选的会话有效期档位)。例外:dsh --profile web auth-reset、设置面板的「修改密码」与「修改用户名」都会轮换会话密钥,一次性让所有已登录的浏览器重新登录(操作者自己的当前会话由服务端重新签发,保持登录)。
- 首次注册窗口:凭据未设置时,任何访问者都能注册为管理员。在把服务暴露到不可信网络之前,请先完成首次注册。
- 登录防护:登录失败按客户端 IP 限速——连续 5 次失败锁定 30 秒(纯内存,无持久化);注册要求密码至少 8 个字符。限速覆盖 /api/auth/login、/api/auth/change-password 与 /api/auth/change-username(旧密码/当前密码错误同样计次)。需要更严格的防护,请在反向代理层加通用限速。
- API 会话闸门双层防护:所有受保护路由在注册层默认拒绝(未认证导航 302 到登录页,其余 401);共享 API 另有一道会话闸门,挂在上游官方 connection/request 扩展点上。两层互为保险:上游接口变化导致其中一层失效时,另一层仍保证只有可撤销的会话(或真本机回环)能访问 API——30 天不可单独吊销的上游原生 cookie 永远不能单独作为 API 凭据。
- 凭据文件权限:$DSH_HOME/web-auth.json(默认 ~/.dsh/web-auth.json;含密码哈希与会话签名密钥)以 0600 保存,目录以 0700 创建;插件启动时会自动修复旧版本遗留的过宽权限。
- --trusted-host:该参数透传给上游 dsh 的 Host 信任围栏(connection 的 trustedHosts),不参与本插件认证判断——远程客户端一律需要有效会话,不存在「受信主机免登录」。
- 反向代理(nginx 等)部署:可以放心的做法是 dsh 只监听 127.0.0.1,由代理做 SSL 卸载并转发。此时代理必须转发真实 Host(nginx 默认即为 proxy_set_header Host $host;,配上 --trusted-host <域名> 让 DSH 自身的 Host 围栏放行);认证通过后,插件按请求的真实 Host(公网域名)补发上游原生浏览器 cookie,上游闸门据此放行。反之,若代理把 Host 写死成 127.0.0.1,插件会认为请求来自本机,从而放行全部流量、不做认证——不要这样配置。X-Forwarded-For 不被采信(客户端可伪造),信任判定只看 TCP 对端地址与 Host。
- 上游兼容层(dsh 0.1.7 基线):dsh rc.8–0.1.1 时代,DSH 前端用浏览器地址栏 hostname 判定 connection.isLoopback,远程浏览器下的 settings mirror 走内存模式,插件配置卡片与 Models 页不可用;本插件当时通过 webServer.tapIndex 注入脚本,在 connection 激活瞬间把该标志覆盖为恒 true。0.1.2 上游引入真实 cookie 认证后能进 UI,但 settings mirror 仍按同一标志判定——LAN 浏览器依旧得到从不读 host 的 memory mirror,设置面板的 Models(提供方目录)会报 "settings are unavailable in this browser"。直接恢复旧的 getter 覆盖会破坏 web boot(A/B 实测 26 个前端插件 pending),因此 0.1.2 起改用注入 window.__DSH_TRANSPORT__ = { ownsHost: true }:connection client 构造时据此把 isLoopback 报为 true(api/rpc 字段缺省时安全回退,且不重写 cordis 服务),LAN 与回环浏览器的全部设置面(含 Models)都正常渲染。当前保留的浏览器侧 shim:该 transport hook 与 crypto.randomUUID polyfill(明文 HTTP 非安全上下文所需)。

开发

npm install
npm run typecheck # tsc --noEmit
npm test # vitest
npm run build # tsc -p tsconfig.json + tsdown,产物输出到 lib/

- tsc 编译 node 侧源码(src/.ts)与类型声明到 lib/、lib/types/。
- tsdown 把前端插件(src/client/index.tsx)打包成浏览器 bundle lib/client.js(window.__ModuleLoader__.load 注册格式)。改前端代码后必须重新构建,profile 里 link: 安装会自动加载新产物。
- 前端插件依赖的 @deepseek-ai/dsh-client-* 包只用于类型与构建,运行时由 DSH 前端模块表提供。

许可证

MIT
预览分享卡片长什么样 ↓GDWhisper/dsh-web-startup-auth
分享 · DeepSeek Harness Hub
GDWhisper/dsh-web-startup-auth

DSHDeepSeek Harness远程 Web 启动 + 用户名/密码认证插件。 | DeepSeek…

回到顶部