防护层最后一节关两道门:传输的门(HTTPS——数据在路上不被窃听、不被篡改)与数据的门(深度输入验证——类型、范围、业务规则逐层过关)。前者一次配置长期有效,后者是每个接口的日常功课。
Node 的 https 模块直接替换 http,Koa 不感知差异:
const https = require('https'); const fs = require('fs'); const Koa = require('koa'); const app = new Koa(); const options = { key: fs.readFileSync('./certs/server.key'), cert: fs.readFileSync('./certs/server.crt'), }; https.createServer(options, app.callback()).listen(443);
证书来自 CA 签发(公网域名)或内部 CA(服务间调用)。开发环境可用 mkcert 一类工具生成本地受信证书——curl -k 绕过校验只是调试手段,别写进任何脚本。
生产环境最常见的形态不是 Koa 直连 443,而是 Nginx 或云负载均衡在前终结 TLS,内部转发明文流量到 Koa。此时出现两个必须处理的问题。
问题一:真实客户端 IP。 流量经反代转来,Koa 看到的连接地址是反代内网 IP。X-Forwarded-For 头里有真实 IP,但这个头客户端也能伪造——所以 Koa 默认不信任它,需要显式开启并指定可信代理层数:
const app = new Koa(); app.proxy = true; // 信任代理头(前提:这些头确实来自你控制的反代) app.proxyIpHeader = 'x-forwarded-for'; app.maxIpsCount = 1; // 只信任最右侧一跳,防止客户端自塞头伪装 // 此后 ctx.ip 返回真实客户端 IP,限流、审计日志的 key 才有意义
maxIpsCount 是精髓:设为 1 表示只认"离我最近的那一跳"追加的值,客户端伪造的头会被剥掉。问题二:协议传播。 Koa 需要知道原始请求是 HTTPS,才能正确生成绝对地址与设置 secure Cookie——app.proxy = true 后 ctx.protocol 会读取 X-Forwarded-Proto,7.2 节的 secure Cookie 与 HSTS 头都依赖这个值。
直连与反代两种形态的选择标准一句话:需要证书热轮换、HTTP 重定向、多实例负载均衡,就上反代;小规模内部服务,直连更简单。两种形态下,7.2 节的 HSTS 头照常配置——它告诉浏览器"此后一律用 HTTPS 访问我",是防降级劫持的关键。
第 4.3 节的校验层管"结构合法",这里把验证讲深——完整的数据验证分三道,一道都不能省:
第一道:类型与结构。 是不是数字、是不是数组、必填有没有。4.3 节的 validate 层负责,不再重复。
第二道:范围与格式。 类型对但值越界:
const createSchema = { items: { type: 'array', required: true }, address: { type: 'string', required: true, max: 200 }, }; // 范围检查的典型落点:数量、页长、ID 格式 if (order.qty <= 0 || order.qty > 999) throw new BadRequest('数量超出范围'); if (!/^ORD-\d+$/.test(ctx.params.id)) throw new BadRequest('订单号格式不合法');
范围检查防的不只是脏数据——qty: 1e9 这类值能触发下游库存系统的整数溢出或慢查询,越界输入是资源耗尽攻击的常见入口。
第三道:业务规则。 值合理但组合不合法:取消已发货的订单(409,第 4.2 节写过)、给下架商品下单、用别人的优惠券。这类规则没有通用框架,散落在业务层是正常的——但它们必须与资源归属校验(7.1 节)一起,构成业务层的"准入 twin check":先问是不是你的,再问合不合规。
三道检查的位置随之清晰:第一道在路由级校验层(结构)、第二道一半在校验层一半在业务入口(范围)、第三道在业务层(规则)——越靠前的检查越通用,越靠后的检查越业务,这与洋葱的分层哲学完全同构。

把本章与 7.1 的内容合成一张可执行的上线检查单,评审时逐项打钩:
💡 关键直觉:安全配置的特征是"一次配对长期受益,配错一次长期受损"。app.proxy 配错,限流与审计全失真;HSTS 忘配,降级劫持开着口;参数化漏一处,注入面就留着。自查单的价值就在于把这些"单点、静默、长期"的风险变成合并前的显式检查。
防护层到此全副武装。下一章转战稳态运行:找出真正的性能瓶颈、用压缩缓存与集群撑起流量、让测试与监控守住质量底线。