自研远程桌面工具威胁模型与安全设计清单

0 阅读13分钟

前面四篇把"做什么、怎么搭"讲完了。最后这篇聊最硬核也最该被问的那句话:真出事了怎么办?一个远程桌面把你的桌面画面和键鼠都送出去了,如果中间任何一环被攻破,内容会不会泄露?这篇不喊口号,直接摆三种具体威胁情形,逐一看项目是怎么扛的,最后给一张完整的安全设计清单。

一、先摆清楚:我们要防的是什么

谈安全,第一步是定义"威胁模型"——也就是明确:你到底在防谁、防什么。不明确这个,任何"我绝对安全"都是空话。

在展开之前,先给"攻击者"分个级,因为不同能力对应不同防线:最低级的是"被动监听"——只能看路上跑的流量;中级的是"主动篡改/丢弃"——能改能丢能重放;最高级的是"完全控制某一端"(比如你的公司电脑本身中毒)。本项目要扛的是前两级,第三级超出了远程桌面协议的职责,不在本篇讨论。分清楚级别,你才知道下面每道防线在挡谁。

ALSPD-DESK 要保护的核心资产很具体:公司电脑的屏幕画面,以及你从家里发出的鼠标键盘指令。这两样一旦被第三方还原出来,等于把那台机器的操作权交了出去。项目要防的,就是"中间任何环节看到这两样明文"。

同时它明确不试图防什么——比如你的公司电脑本身已经中了木马、或者你本机的密码弱到被猜中。这些属于"端点本身失守",超出了一个远程桌面协议的职责范围。威胁模型的意义,就是老老实实划清"我负责到哪",而不是大包大揽地承诺"我保你万无一失"。

这也是为什么本项目从设计第一天起,就把"三个具体情形"而不是"一句安全"当作验收标准——能对着具体攻击者说清"他拿不到什么",才算真安全。

下面三种情形,覆盖了链路上的三个关键节点:中继(VPS)、公司网络、公网扫描。逐一拆开。

二、情形一:中继(VPS)被入侵了

这是最常被问的情形:我的 VPS 被攻破了,攻击者拿到了那台服务器的完整控制权,会怎样?

先说清攻击者最想要什么:他拿下 VPS,图的是"看到你公司的画面、或操纵你的键鼠"。下面逐层看,这个目标在每一层都被挡住。

先看清攻击者"能拿到什么"。中继在握手阶段确实需要读 HELLO 明文——因为要靠它配对,所以它知道房间号、角色(agent/viewer)、双方随机生成的 nonce。但 nonce 本来就不需保密(真正保密的是来自 password 的 PSK),房间号和角色也只是元数据,不含任何画面或键鼠内容。

握手之后,画面(FRAME)和键鼠(INPUT)全都是端到端密文。攻击者没有 password,就派生不出会话密钥,面对的就是一堆 AES-GCM 密文,解不开。他能做的,只是原样转发这些密文——而这本来就是中继的本职工作,转发密文对他毫无额外收益。

那 relay_token(中继令牌)被拿到会不会出事?令牌只能用来"证明有资格进这个房间",也就是攻击者能用它冒充一端去抢配对。但即便他抢进去了,看到的依然是密文,操作不了内容。令牌是"门禁卡",不是"保险箱钥匙",这把钥匙(password)从没给过中继。

再看日志:项目源码里中继的日志只记录消息类型和字节数,从不记录载荷内容。所以即便攻击者翻日志,也翻不到任何画面或键鼠的明文。结论很干脆:中继被入侵,内容仍然安全——因为内容从没在明面上经过中继。

还有一个更刁钻的问题:如果攻击者不止"看",还能"改"中继转发的密文呢?答案是——改了也没用,而且会立刻暴露。因为内容用的是 AES-GCM,每个密文都带一个认证标签;哪怕只改一个字节,接收端解密时认证标签就对不上,直接报错断开(项目里会把这种错误明确提示成"会话密钥不一致或数据被篡改")。所以攻击者最多让连接断开(一种拒绝服务),却永远拿不到内容,也悄无声息地篡改不了。篡改即暴露,这正是带认证加密的价值。

三、情形二:公司做了 TLS 中间人解密

为什么公司要这么做?很多企业出于审计和威胁检测,会部署透明代理,悄悄把出网的 HTTPS 解密再重加密——员工通常无感知。这不是针对你,而是企业安全的常规操作。问题在于:你的远程桌面在这种环境里"能不能既连得上、又不被看穿"?

第二种情形更"日常":你连回公司电脑时,公司网络对出去的 TLS 流量做了中间人解密(很多企业出于审计和威胁检测,会部署这类 NDR/DLP 设备,透明地拦下 HTTPS 再代理解密)。

这里正好体现"TLS 只是伪装层、端到端加密才是锁"的设计价值。公司设备解开的,只是最外那层 TLS——把 wss:// 这层"马甲"扒了,里面露出来的是应用层的 AES-GCM 密文。公司能看到的,到此为止;里面的画面和键鼠,仍然被端到端密钥锁着,解不开。

更重要的是:连接照样能用。因为公司代理解出来的密文对它是无意义的,但它仍然会正常转发,所以你的远程桌面不受影响。这跟"自签证书 + 严格钉扎"的方案形成对比——那种方案一旦遇到公司中间人解密,TLS 指纹对不上,连接直接失败,项目就死在公司网络上了。本项目故意不把 TLS 钉扎当硬性前置,正是为了在公司网络这种真实环境里还能活下来。

需要划清边界:上面说的是"传输途中"被中间人看。如果公司不是在传输层动手脚,而是直接在"你的公司电脑本身"上装监控(比如终端管控软件截屏),那就属于端点失守,任何远程桌面协议都无能为力——你不可能在"机器已经被对方控制"的前提下,还保证"对方看不到机器上的东西"。威胁模型的意义,就是诚实地承认:本项目保的是"链路",不是"端点"。把链路守牢,端点的事交给你对那台设备的合规与授权去管。

顺带提醒:在公司网络里使用本项目,请先确认公司的 IT 与安全政策是否允许此类工具;并且只在本人拥有、或已获得明确授权的设备上连接。即便传输本身安全,合规仍是你自己的责任。

四、情形三:公网 VPS 被扫描

把中继部署在公网,等于把它放在了"所有人都能敲"的位置。能被敲,就一定会有人敲——自动化的端口扫描每天在公网上扫来扫去,你的 VPS 上线几分钟就可能被扫到。这不是吓唬,是常识。

任何一台公网 VPS 都会被端口扫描,这是常态,无法避免,也不必恐慌。关键是被扫到之后有没有危害。

中继的应对很硬:它只接受"握手成功、且验证过密钥"的连接。握手有时间窗——15 秒内没完成 HELLO 校验就直接断开(close 1008, "handshake timeout")。校验包括角色合法、房间非空、令牌常量时间比较通过、nonce 合法等。扫描器通常只发个 SYN 或半截握手,根本走不完这套流程,就会被踢掉。

即便极少数情况扫描器真把握手走完了、连了上来,它进房间后也只能收到和转发密文——和情形一一样,看不到内容。所以"被扫到"本身是无害的,它既拿不到数据,也进不了任何真实会话。

补一个具体数字让"踢掉"更可信:中继的握手超时设为 15 秒——15 秒内没完成 HELLO 校验,连接直接关闭。扫描器发个 SYN、或半个握手就停,根本走不完这套流程,连"进门"的机会都没有。而且令牌比较用的是常量时间比较(hmac.compare_digest),专门防"时序侧信道"——攻击者没法通过"比对快了慢了"来猜令牌的某一位。这些细节,都是为了让"被扫到"从"可能漏进来的风险"变成"连门口都摸不到"。

想要更硬,还可以加可选加固:失败连接限速、握手超时(已默认开启)、fail2ban 自动封禁反复失败的来源 IP、甚至中继 IP 白名单。这些都不是必须的,但都是"锦上添花"的低成本加固,按需开启即可。

为什么把这些做成"可选"而不是默认开?因为默认开可能误伤正常用户(比如 IP 白名单配错就把自己挡外面),而它们的收益只在"真被针对"时才显现。按需开启,是"不强加负担、但留好武器"的务实姿态。

五、完整安全设计清单(八条)

把上面散落的设计点收拢,项目的安全设计清单一共八条,条条都对应前面某段分析:

  1. 端到端 AES-256-GCM:核心中的核心。中继无密钥,VPS 被入侵也读不到内容。
  2. Scrypt 强密钥派生:密码不当密钥直接用,先拉伸成抗暴力破解的强密钥(PSK)。
  3. 序列号 + GCM nonce 计数器:抗重放。每条消息带递增序号,乱序或重复会被直接拒。
  4. Agent 零入站端口:被控机不监听外来的连接,没有可被主动攻击的入口。
  5. 中继只认认证连接:握手超时即踢,且只转发密文,不解析、不落盘内容。
  6. TLS 仅作伪装层:被中间人解开也只见密文;它存在的意义是"穿墙 + 不显眼"。
  7. 免安装、不依赖管理员权限:减少系统层面的改动,降低部署阻力与攻击面。
  8. 可选加固:中继 IP 白名单 / fail2ban / 连接限速,按需叠加。

这八条不是堆功能,而是"每一层都只补自己该补的洞":应用层锁内容、传输层管穿墙、网络层管入口、运维层管加固。职责分得清,才不会出现"某层以为另一层防了、结果谁都没防"的空白。

把这八条映射回前面三种情形,就清楚它们各自在挡谁:第1、2、3条(端到端加密、强派生、序号计数器)挡的是"中继被入侵后想看/想重放";第4条(零入站端口)挡的是"直接打被控机";第5条(只认认证连接)和第8条(可选加固)挡的是"公网扫描与暴力连入";第6条(TLS 仅伪装)让"公司中间人"既看不了也不致死;第7条(免装免权限)挡的是"部署本身引入的新攻击面"。八条不是罗列,是一张覆盖三种情形的防守网。

顺带一提,安全不只发生在传输层。操作侧同样有四层保命措施——急停热键(随时一键停止注入)、只读模式(默认不注入键鼠)、空闲自动断连、本机活动检测(本机有人动鼠标就让步)。它们防的是"注入失控"这类端点操作风险,和上面的传输安全互为表里。传输守住了"链路",操作守住了"行为",才算把一把钥匙的两头都攥牢。

六、为什么证书钉扎不作为硬性前置条件

先说清"证书钉扎"是什么:正常 TLS 靠证书链里的 CA 来确认服务器身份;钉扎则是"我只认这一张特定指纹的证书",别的哪怕有合法 CA 背书也不认。它更强,但也更脆——一旦服务器证书换了(自签证书常换),所有钉扎的客户端就全连不上,得逐个改配置。

最后解释一个看似矛盾、实则关键的决定:项目支持证书指纹钉扎(pinned_fingerprint),但默认留空、不强制。

钉扎的作用是:在 TLS 握手后比对服务器证书指纹,不符就立刻断开,防止连到"伪装成你 VPS"的中间人。听着很安全,为什么不做成硬性要求?

因为前面情形二已经说明:公司网络的 TLS 中间人解密非常普遍。如果强制钉扎,公司代理解密 TLS 时证书必然对不上,连接直接失败——而你的远程桌面恰恰最常用在公司网络里。为了一个"防伪装"的强约束,把项目自己在最主要的使用场景里搞死,是本末倒置。

所以项目的取舍是:端到端加密已经锁住了内容,TLS 钉扎只是"额外确认服务器身份"的加分项,不是安全的前置条件。默认不钉扎,项目在公司网络里照样能连、照样安全;如果你处在"确定没有中间人、且想更严格确认服务器"的环境,再去配置指纹钉扎即可。配置项留空即等于"不钉扎、信任应用层端到端加密"——这正是对真实部署环境最诚实的适配。

那什么时候反而该开启钉扎?当你明确知道自己处在"没有 TLS 中间人、且想额外确认连的就是那台 VPS"的环境——比如中继是你完全掌控、证书固定的一台机器。这时填好指纹,等于多一道"确认服务器身份"的保险。但记住它是加分项不是必选项:绝大多数日常使用里,应用层端到端加密已经锁死了内容,钉不钉扎,安全性是同级的。别让一个"可选加固"变成"连不上的绊脚石"。

回到开头那句话:威胁模型的价值,不在于宣称"我刀枪不入",而在于清楚地说出"哪道防线挡住了哪类攻击者"。ALSPD-DESK 的三道情形分析合起来只指向一个结论——只要你的 password 够强、只在授权设备上用,那么无论中继失守、公司解密还是公网扫描,你的桌面内容都不会以明文形式泄露。把钥匙攥在自己手里,才是这套设计真正的底气。