随着 Serverless 技术的普及,微信云开发(WeChat CloudBase)已成为小程序开发的“新基建”。它通过免运维、低成本的特性极大释放了前端生产力。然而,在大型企业的实际应用中,业务逻辑往往无法完全脱离自建的后端服务(如 Java/Go 集群)。
这就形成了一种典型的混合云架构:“微信云函数作为网关 + 企业私有服务器作为核心”。在这种架构下,如何确保数据在跨越“微信内网”与“企业内网”之间的公网鸿沟时依然安全?本文将深入剖析这一场景下的现代网络安全实践。
一、 全链路安全交互流程
现代企业大型系统的一个标准的、金融级的安全交互流程如下:

二、 信任的起点:云开发的“天然鉴权”
在传统开发模式中,开发者需要维护一套复杂的登录态:wx.login 换取 Code,后端换取 OpenID 和 SessionKey,再生成自定义 Token。这不仅繁琐,还面临 SessionKey 过期同步的难题。
云开发通过“基础设施即代码”的理念,重构了这一流程:
- 私有链路:小程序与云函数之间通过微信私有协议通信,天然防抓包。
- 身份注入:请求到达云函数时,微信网关已完成了身份校验,并将
OpenID等用户信息直接注入上下文(Context)。
本质:这是一种 “信任下放” 。服务端放弃了对“你是谁”的重复检查,转而完全信任微信基础设施提供的身份断言。这解决了“第一公里”的安全与效率问题。
三、 信任的断点:跨越公网的挑战
当业务复杂度上升,云函数往往只承担“BFF 层(Backend for Frontend)”的角色,核心业务逻辑(如支付结算、库存扣减)仍需转发至公司内部的服务器。
此时,请求必须走出微信的温室,穿越不可信的公网(Internet)。
- 风险点:虽然 HTTPS 解决了传输通道的加密,但在 SSL 卸载后的内网传输、日志记录以及极端的中间人攻击场景下,明文 Payload 依然面临泄露风险。此外,接口暴露在公网,随时可能面临伪造请求和重放攻击。
因此,我们需要在云函数与企业后端之间,建立一套 “零信任” 的防御体系。
四、 构建纵深防御体系
为了填补信任断点,我们引入一套组合解决方案:身份认证(签名)+ 数据机密性(加密)+ 运行安全(Fail Fast)。
1. 身份认证:共享密钥签名 (HMAC)
解决问题:防止伪造请求。确保只有我的云函数能调用我的后端。
- 机制:双方预共享一个
SecretKey。云函数发送请求时,利用HMAC-SHA256算法对请求体、时间戳、随机数进行签名。 - 防重放:引入
Timestamp和Nonce。后端校验时间戳是否在 60 秒内,并检查 Nonce 是否重复,从而拦截黑客截获的旧请求。
2. 数据机密性:信封加密 (Envelope Encryption)
解决问题:防止数据泄露。即使流量被劫持,黑客也无法通过 HTTPS 之外的手段看到数据内容。
- 机制:采用 RSA + AES 混合加密。
- AES(对称加密):负责加密庞大的业务数据(Payload),效率高。
- RSA(非对称加密):负责加密 AES 的密钥(SessionKey),安全性高。
- 流程:云函数随机生成 AES Key 加密数据 -> 用后端的 RSA 公钥加密 AES Key -> 打包发送。
3. 运行安全:快速失败 (Fail Fast)
解决问题:防御 DoS 攻击,保护计算资源。
- 原则:先验签,后解密。
- 逻辑:RSA 和 AES 解密是 CPU 密集型操作。如果后端先解密再验签,黑客发送大量垃圾密文就能耗尽服务器 CPU。因此,必须先校验签名(计算成本极低),一旦签名不对,直接在拦截器层丢弃请求,不给恶意流量消耗核心资源的机会。
五、灵魂拷问
5.1 在微信云函数等待服务端响应时,为什么不需要校验签名,保证响应一定是来自于真实的后端服务器

让我们回溯一下用于AES加密的SessionKey 的旅程:
- 云函数生成了
SessionKey,用于AES加密 - 云函数用服务端的 RSA 公钥 加密了
SessionKey发送出去。 - 只有持有 RSA 私钥的服务端,才能解开这个信封,拿到
SessionKey,并AES解密消息
推论:
- 如果云函数收到的响应数据,能够用
SessionKey成功解密,且数据格式正确。 - 那么,加密这段数据的人,一定拥有
SessionKey。 - 而在网络上,除了云函数自己,只有真正的服务端(因为只有它有私钥)能拿到
SessionKey。 - 结论:不需要额外的签名,“能用 SessionKey 正确加密”这件事本身,就是对服务端身份的证明。
结论:
- 源头独享:AES 密钥(SessionKey)是云函数(客户端)临时生成的,只有云函数自己知道。
- 传输独占:这个密钥被装进了 RSA 信封(用服务端公钥加密)。在这个世界上,只有服务端(持有私钥)能拆开信封拿到密钥。
- 结果倒推:既然回来的响应数据能用这个 AES 密钥解开,说明发送方一定拿到了密钥。
- 唯一结论:发送方只能是服务端。
这就是“认证”! 虽然没有显式的“签名(Signature)”字段,但“能正确加密”这个行为本身,就是身份的证明。
5.2 基于5.1 既然解密就能认证,那为什么请求的时候(云函数->服务端)不也这么干?为什么要多此一举搞个签名?
这是因为请求和响应面临的安全场景和性能需求完全不同:
A. 请求阶段(云函数 -> 服务端)
- 面临威胁:服务端暴露在公网,面临 DDoS 攻击、垃圾请求轰炸。
- 性能瓶颈:RSA 解密(拆信封)是非常慢、非常消耗 CPU 的。
- 为什么必须签名:
- 如果只靠“解密成功来认证”,服务端就必须对每一个黑客发来的垃圾请求都尝试做一次昂贵的 RSA 解密,解完发现是乱码才知道是黑客。这时候 CPU 早就爆了。
- 签名的作用是“低成本过滤”:HMAC 运算极快。服务端先算签名,不对直接扔掉。签名是为了保护服务端的计算资源(Fail Fast)。
B. 响应阶段(服务端 -> 云函数)
- 面临威胁:云函数是客户端,它只跟服务端建立了一个连接,它不会收到成千上万的随机攻击请求。它只在等待它发出的那一个请求的回复。
- 性能瓶颈:云函数只有 AES 解密(对称解密),速度极快,没有 RSA 操作。
- 为什么不需要签名:
- 云函数不需要“防 DDoS”。
- 云函数本来就要解密数据才能用。
- 解密即认证:既然解密成本不高,且解密成功就能确认身份,那就没必要再多算一次签名了。
总结:
- 请求阶段:采用 “显式认证” (Signature)。
- 目的:为了快速拒绝非法请求,保护服务端资源。
- 响应阶段:采用 “隐式认证” (Decryption as Auth)。
- 目的:利用密钥的独占性来确认身份,简化流程,效率最高。
这就是现代加密通信协议(包括 TLS 握手内部逻辑)中非常经典的“非对称设计”哲学。其实解密本身也能达到身份认证的能力,但是加解密是CPU密集操作,服务端暴露在公网下,需要防范黑客攻击,需要支持Fast Fail,所以引入了签名,签名的作用是“低成本过滤”来保护服务器不被攻击。
六、 结语
在微信云开发的混合架构中,我们并没有“放弃”鉴权,而是进行了职责分离:
- 微信侧:负责处理复杂的 C 端用户登录态维护,提供可信的身份断言。
- 企业侧:负责处理高价值的 B 端服务间通信,通过签名与加密构建坚固的护城河。
这种架构既保留了云开发“快”的优势,又守住了企业级安全“稳”的底线,是现代企业应用上云的最佳实践之一。
大白话版
1)为了简化小程序鉴权流程,我们可以采用云开发简化用户登陆检查,这样请求直达微信云函数。原理是基于微信的内部私有协议,依靠微信云网关保证请求一定是来自于登陆后的合法用户,从而简化C端用户登录态的维护,本质是使用微信的基建能力来保证。
2)在大型企业中,业务代码仍然不放在微信的云开发环境中,云函数只做请求转发,拿到微信的请求后将请求转发志公司自己的服务器
3)但是由于转发会走公网,即便是用Https请求也不安全。所以当请求从微信云服务发经由公网发送至后端服务器时,还需要考虑安全
4)从安全角度,首先引入了共享密钥,支持签名,从而实现身份认证的鉴权能力保证只有云函数能调用到后台服务器
5)再深一步考虑安全,签名只能解决认证问题,但是请求消息体仍然在网络上传输,所以需要引入加密功能,实现支持点对点通信,按常理应该可以直接使用RSA非对称加密对请求消息直接进行加密,后端服务器解密即可,但是由于RSA有性能瓶颈,所以采用了RSA+AES结合,对于消息体采用AES进行加密,然后加AES的密钥通过RSA加密一起发送给后端,后端先通过私钥解密AES密钥,然后再用该密钥解密请求的消息体,再执行业务逻辑
6)流程上:由微信维护C端请求合法,完成用户登录态的维护;然后将请求转发至后端,后端和微信云开发通过共享密钥进行身份认证,保证只处理云函数的请求。然后再通过RSA+AES对请求的消息内容进行解密,然后再进行处理