内容图

一、为什么远程桌面下的 UKey 是个棘手问题

过去十年,集中式办公在政务、能源、金融与高端制造行业快速普及。运维人员用瘦客户机连上云桌面处理工单,调度人员在调度大厅通过远程接入方式操作远端的 SCADA 前置机,设计工程师在异地用云桌面打开 CAD 做图纸授权校验。这些场景有一个共同点:用户的国密智能密码钥匙(也就是常说的国密 UKey、USBKey 双因素 载体)物理上插在本地那台设备上,而真正需要调用密钥的业务应用,却运行在远端虚拟机的操作系统里。

这里就产生了第一道裂缝。密钥硬件和密钥消费者被一层网络隔开了。如果简单地把 UKey 当成普通 USB 设备整体透传给远端,远端的操作系统会加载通用驱动,把钥匙当成“本机插着的一把 Key”来用。从应用视角看一切正常,但从攻防视角看,这等于把私钥的使用权整个交给了远端环境——而远端环境恰恰是用户最难控制、也最容易被横向移动攻陷的那一层。

更麻烦的是,远程会话天生具有“可重放、可截屏、可被脚本驱动”的特点。攻击者一旦在远端虚拟机落下一个键盘记录器或屏幕抓取器,就能在用户毫无察觉的情况下,反复调用已经“在线”的 UKey 完成签名,看上去每一次都是合法操作。这正是远程场景下密钥风险被长期低估的根源:传统双因素只解决了“有没有这把 Key”,却没有解决“这一次签名是不是用户本人在当前会话里主动发起的”。

二、设备重定向的三种形态与各自命门

在动手改造之前,先把市面上常见的三类“把本地 Key 送到远端用”的做法摊开对比,才能看清安全桥接到底要解决什么。

形态实现方式私钥位置主要风险
整设备透传RDP 自带 USB 重定向,远端加载驱动仍在本地硬件,但控制权移交远端远端恶意进程可任意调用,无会话绑定
密钥导入远端把证书/私钥导出到远端软证书库离开硬件,存于远端磁盘私钥可被复制、dump、离线穷举口令
本地桥接转发仅转发密码运算请求,运算在本地完成始终留在本地芯片需解决通道安全与会话绑定

第一种整设备透传最常见,也最危险。它表面上保留了硬件加密的优势,私钥不可导出,但“私钥不可导出”只保障了密钥文件不被拷贝,却没保障“密钥不被远端随意调用”。一个在远端运行的木马,完全可以复用已经建立的 RDP 通道,像正常业务一样发起签名请求。

第二种密钥导入远端,是把安全直接拆了。很多历史系统为了图省事,在初次绑定时让用户把软证书导进远端,美其名曰“兼容老应用”。这直接违背了硬件加密的立身之本——私钥必须待在安全芯片里。一旦远端被攻陷,密钥连同口令一起泄漏,后面所有的签名验签都形同虚设。

第三种本地桥接转发,才是本文要展开的工程主线。它的核心思想只有一句话:远端永远不碰设备,只碰“运算结果”。具体的密码学操作(SM2 签名、SM3 摘要、SM4 加解密)一律在用户本地那台插着 UKey 的机器上完成,远端业务系统只拿到运算后的密文或签名值。

三、安全桥接的整体架构

一套可落地的桥接方案,通常由四个角色组成:

  1. 本地桥接代理(Local Bridge Agent):运行在用户插着 UKey 的那台物理设备/瘦客户机上,负责真正和硬件对话。它持有对智能密码钥匙的访问权,调用其内部的 SM1/SM2/SM3/SM4 以及 RSA/AES/ECC/SHA 算法能力。
  2. 远程会话垫片(Remote Shim):替换掉业务程序里直接访问 UKey 的那一层,把它改写成“把请求发到桥接通道”。
  3. 安全通道(Secure Tunnel):建立在 RDP 虚拟通道或独立加密隧道之上,只传输“运算请求”和“运算结果”这两类极小的数据结构,绝不传输密钥本身。
  4. 策略引擎(Policy Engine):校验每一次调用是否绑定了合法会话、是否通过本地确认、是否落在允许的时序窗口内。

这个架构最关键的取舍是:把“信任锚点”从远端操作系统挪回了用户本地设备。远端系统即便被完全攻陷,攻击者最多拿到一堆无法复现的签名结果,拿不到任何可以离线使用的密钥材料。这也让“硬件加密”这四个字在远程场景里重新有了意义。

以安当UKey为例,其对外暴露的调用面同时包含 RESTful API(便于快速集成到 Web 类业务)以及一套 C 动态库(便于嵌入到 C/S 架构的桌面客户端)。在桥接架构里,远端垫片只需要按原有方式调用这些接口,而真正落到硬件的动作被本地代理接管,对业务代码的侵入被控制到最小。

四、远程签名网关的调用链拆解

把架构落到一次具体的“远程签名”调用上,时序大致是这样的:

  1. 远端业务系统在云桌面的会话里,需要给一份调度指令报文做 SM2 签名。
  2. 它调用原本的 UKey SDK,但此刻 SDK 已经被垫片替换,请求不再去摸本地(远端根本没有设备),而是序列化成一个签名请求帧。
  3. 请求帧经由安全通道回传到用户本地的桥接代理。
  4. 本地代理校验会话绑定信息,确认这次调用确实来自一个“活着且被授权”的远程会话。
  5. 代理把报文摘要送进 UKey,硬件在安全芯片内用私钥完成 SM2 签名。
  6. 签名值沿原通道返回远端,业务系统拿到结果继续后续流程。

下面是一段远端垫片侧的示意代码,它把“直接摸硬件”改成了“发到本地代理”,业务层几乎无感:

/* 远端业务进程调用,实际由 shim 转发到本地桥接代理 */
#include "ukey_sdk.h"

UKY_CTX *ctx = ukey_open("session://rdp/0");
if (!ctx) {
    /* 会话绑定校验失败,直接拒绝服务,不留降级后门 */
    log_error("session bind failed, reject");
    return -1;
}

ukey_sign_param p = {
    .alg  = UKY_SM2,
    .hash = UKY_SM3,
    .data = plain,
    .len  = plain_len,
};
/* 该调用触发本地 PIN / 按键确认,私钥始终在本地安全芯片内 */
int rc = ukey_sign(ctx, &p, sig, &sig_len);
if (rc != UKY_OK) {
    audit_event("sign_denied", ctx->session_id);
}

可以看到,业务代码形态几乎没变,但语义已经完全不同:签名动作的物理发生地,从“不可信的远端”转移到了“用户手边的硬件”。

五、会话绑定:让每一次调用都贴着当前会话

只做桥接还不够。如果桥接代理对“谁在调用”不做任何校验,攻击者完全可以劫持那条通道,冒充合法会话反复发起签名。因此必须在桥接代理这一侧,强制做会话绑定。

会话绑定通常叠加四个因子:

  • 会话标识(Session ID):来自 RDP 协议栈下发的当前会话唯一编号,确保请求与一条具体会话一一对应。
  • 用户安全标识(User SID):远端业务进程的运行身份,防止同一台机器上其他用户或服务的进程冒用。
  • 客户端网络位置(Client IP / 终端指纹):记录这次远程接入来自哪台终端,异常切换时触发二次确认。
  • 时序窗口(Time Window):每个签名请求携带短时戳,代理校验偏差,抵御重放。

绑定逻辑建议做成“默认拒绝”。即:任何缺少上述任一因子的调用,一律当作非法请求丢弃,并且写入审计日志。宁可偶尔因为终端换了网络导致一次重连,也绝不能开一个“先放行再补校验”的降级口子——绝大多数密钥失窃事件,都是从这类看似贴心的降级分支开始的。

六、防截屏与本地手势确认

远程桌面天生面临屏幕被抓取的风险。哪怕通道再安全,如果用户的 PIN 口令是在远端弹出的输入框里敲的,那口令就已经暴露在远端的截图与键盘记录之下了。

正确的做法,是把“需要保密的输入”和“需要用户主动确认的动作”全部搬回本地:

  • PIN 输入本地化:口令只在用户本地设备的可信 UI 里录入,绝不经过远端屏幕。
  • 按键/触碰确认:对于高敏操作(如调度指令签名、固件签名),要求用户按下 UKey 上的物理确认键,或在本地代理弹出的可信窗口里点击确认。这个动作远程脚本无法模拟,因为远程环境根本接触不到本地输入设备。
  • 防截屏标记:桥接代理在本地确认窗口上设置操作系统级的防截屏属性,确保即使远端尝试抓屏,抓到的也是一片黑块。

这一层解决的是“这一次签名是不是用户主动发起”的问题,正好补齐了传统双因素只认“设备存在”、不认“本人此刻意愿”的短板。把它和会话绑定结合起来,就构成了远程场景下完整的“设备 + 会话 + 意愿”三重校验。

七、审计留痕与合规证据材料

等保 2.0 与商用密码应用安全性评估(密评)都强调一个朴素要求:关键密码操作要可追溯到“谁、在什么会话、对什么数据、做了什么、结果如何”。远程场景因为多了一层网络跳转,反而更容易在出事时互相甩锅,所以审计留痕必须做扎实。

建议的审计记录至少包含以下字段:

字段含义用途
session_id远程会话编号关联具体接入
user_sid业务进程身份定位责任人
client_fp终端指纹识别异常接入
op_type签名/验签/加解密区分操作
data_hash被运算数据的摘要防篡改举证
result成功/拒绝责任界定
ts精确到毫秒的时间戳时序还原

更进一步,审计日志本身也应当被保护。推荐做法是把每条日志用远端或本地的密钥做一个追加签名,形成只增不改的链式记录(append-only + 哈希链)。一旦事后有人想抹掉某条签名记录,哈希链的断裂会立刻暴露。这种“日志即证据”的设计,在应对密评与监管检查时,能直接拿出不可篡改的材料,而不是靠口述“我们系统有记录”。

以安当UKey为例,其对私钥不可导出的硬件约束,恰好让“签名动作必然发生在本地芯片”成为可验证事实——这本身就可以作为证据材料链上的一环:只要审计日志里记着某签名由该硬件序列号完成,就能反推私钥从未离开过那枚芯片,从而满足“密钥不出硬件”的合规陈述。

八、性能与容量参考数据

很多团队迟迟不敢上桥接方案,是担心“每次签名都绕回本地,延迟会不会炸”。这里给一组工程实测区间,便于做容量规划(数据为典型局域网与跨区域远程接入的混合参考,具体以实测为准):

指标局域网跨区域远程接入
单次 SM2 签名端到端时延8–15 ms30–60 ms
单次 SM3 摘要时延1–3 ms5–12 ms
单网关节点签名吞吐约 200 次/秒约 120 次/秒
单节点并发会话上限1500–2000800–1200
桥接代理内存占用约 20–40 MB同左

从数据看,在绝大多数业务(工单审批、指令签名、授权校验)里,单次几十毫秒的额外开销完全在可接受的体验范围内。真正的压力点通常在“短时间内海量签名”的批处理场景,例如夜间对上万份文件做固件签名。这类场景建议把批处理任务下沉到本地代理侧做批量队列,而不是在远端逐条发请求,避免通道成为瓶颈。

容量规划上,一个常见误区是“按峰值并发上网关”。更经济的做法是按“活跃签名会话”而非“在线会话”来算:大量远程桌面只是挂着,并不持续调密钥。把网关规模锚定在活跃签名会话数上,通常能砍掉一半以上的硬件投入。

九、分阶段改造路径

不要试图一次把存量系统全部改造完。按风险与收益排序,分四步走最稳:

第一阶段:资产与调用面盘点。 先把所有“远端业务调用 UKey”的入口摸清楚——是 Web 还是 C/S,用的是 RESTful 还是 C 动态库,每天签名量级多少,哪些是高敏操作。这一步不写代码,只出清单,却是后面所有决策的地基。

第二阶段:本地代理 + 垫片试点。 选一条非高敏、量又够大的业务线(比如普通的登录双因素)先上桥接代理。目标是验证通道稳定性、垫片对原有 SDK 的兼容度,以及运维同学能不能顺畅排障。把坑踩在低风险业务上。

第三阶段:会话绑定 + 防截屏加固。 把调度指令签名、固件签名这类高敏操作迁上来,并强制开启会话绑定与本地手势确认。此时远程脚本冒充已经走不通,安全收益开始凸显。

第四阶段:审计留痕与证据链闭环。 补齐链式审计日志,对接既有的安全运营平台,把“谁签的、在哪签的、签了什么”变成可检索、不可篡改的记录。到这一步,远程场景下的密钥使用才算真正闭环。

每阶段都建议保留“可回退”的能力:垫片做成可开关,一旦远端环境异常,能快速切回原有调用路径,避免业务中断。但回退一定是显式、带审批、带日志的,绝不能变成默认降级。

十、常见坑位与排障要点

  • 驱动冲突:瘦客户机自带的安全模块可能与桥接代理抢设备。解决思路是在本地代理侧做设备独占锁,谁先占谁用,并在释放时干净卸载。
  • 会话 ID 漂移:部分云桌面在重连后会换新会话号,导致绑定校验误杀。需要在策略引擎里维护“同一用户+同一终端指纹”的会话延续白名单,允许短时内的会话号平滑迁移。
  • 时间戳不同步:跨区域场景下两端时钟偏差容易超窗。务必在桥接通道里内置时间同步,而不是依赖各自系统时钟。
  • 日志膨胀:签名频繁的业务一天能产生上百万条审计。建议热日志只保留关键字段,完整记录异步落盘并做采样归档,平衡可追溯性与存储成本。

十一、固件签名与代码签名的高敏延伸

远程场景里还有一类更棘手的需求:固件签名与代码签名。调度前置机、轨交外场终端、制造车间的工控板卡,很多仍依赖本地 UKey 完成固件签名,但研发与发布流程已经搬到了云桌面。这类操作一旦被冒用,危害远超单笔业务签名——它等于给恶意固件发了合法身份证。

在工程上,固件签名建议再叠加两道约束。一是签名对象白名单:桥接代理只接受来自指定构建流水线的摘要请求,拒绝手工随意提交的任意字节流,避免有人把别的文件偷塞进签名通道。二是双人复核:高敏固件签名要求本地出现两次独立确认,分别对应“提交人”与“审批人”两枚不同序列号的硬件,任缺一签不出。这两道约束叠加在前面说的会话绑定之上,把远程固件签名的信任链收得很紧。

十二、信创与跨终端适配要点

政企尤其是能源、政务客户,终端形态非常杂:有 x86 工控机,也有基于国产 CPU 的信创终端,还有纯浏览器形态的瘦客户机。桥接方案要能在这种混合环境里跑,需要关注几个落地细节。

首先是芯片指令与算法栈的一致性。不同终端的底层加密支撑不一样,桥接代理应当向上屏蔽差异,让远端垫片只看到统一的运算接口,至于底层是 SM2 还是 RSA、是硬件还是软实现,由代理在本地决定。其次是适配层的轻量化。瘦客户机资源紧张,代理的体积与常驻内存要压到最低,最好能做到免驱或仅依赖系统自带的基础组件。最后是浏览器场景的补齐。纯 Web 的云桌面没有本地 C 运行环境,这时桥接代理需要以本地服务配合浏览器扩展的方式存在,把签名请求从页面安全送达本地硬件,再回传结果,整个过程密钥仍不离开终端。

把这几节串起来看,远程桌面的 UKey 安全重定向并不是单点技术,而是一条“架构取舍 + 会话绑定 + 本地意愿 + 证据闭环”的组合链路。哪一段偷懒,整条链就断在哪一环。

方案参考

远程场景下的密钥使用,本质上是在“集中运维的便利”和“密钥材料的暴露面”之间找平衡。落到选型与落地上,有几条通用建议可供参考:

第一,优先把密码运算留在密钥硬件所在的那一端,而不是把设备整体交给远端操作系统。能只传运算结果、绝不传设备控制权的架构,在抗横向移动上天然更稳。

第二,会话绑定要做成默认拒绝。把会话标识、进程身份、终端指纹、时序窗口叠起来校验,缺一项就拒,不给降级后门。这是远程密钥安全最划算的一道闸。

第三,高敏操作必须回到本地做意愿确认。PIN 与确认动作不要经过远端屏幕,必要时借助硬件上的物理按键或本地可信窗口,让远程脚本无法顶替本人。

第四,审计日志要能当证据用。关键操作记录建议做哈希链式保护,保证只增不改,事后能直接拿出不可篡改的材料应对检查,而不是临时补台账。

第五,改造按风险分批推进。先在非高敏业务验证通道与垫片兼容性,再把调度、固件等高危签名迁上来,最后补审计闭环。每阶段保留显式可回退能力,但回退必须带审批和日志。

第六,容量规划锚定“活跃签名会话”而非“在线会话”,批处理类海量签名尽量下沉到本地代理侧做队列,避免回传通道成为瓶颈。选型时关注设备是否支持国密算法栈、私钥是否真不可导出、能否适配信创环境,以及对外是否同时具备 RESTful 与本地动态库两类接口,这决定了存量系统改造的侵入成本。

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐