7.3 HTTPS 与输入验证


7.3 HTTPS 与输入验证

防护层最后一节关两道门:传输的门(HTTPS——数据在路上不被窃听、不被篡改)与数据的门(深度输入验证——类型、范围、业务规则逐层过关)。前者一次配置长期有效,后者是每个接口的日常功课。

Koa 直连 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 绕过校验只是调试手段,别写进任何脚本。

真实拓扑:反代终结 TLS,Koa 专注业务

生产环境最常见的形态不是 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 = truectx.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:输入数据的净化漏斗

图 7-1:输入数据的净化漏斗

上线前安全自查单

把本章与 7.1 的内容合成一张可执行的上线检查单,评审时逐项打钩:

  • 全站 HTTPS(直连或反代终结),HTTP 流量 301 到 HTTPS;
  • HSTS 头已配置,maxAge 不低于半年;
  • app.proxy 与 maxIpsCount 已按真实反代拓扑设置,ctx.ip 可信;
  • 安全头按服务形态配置(页面服务全套,纯 API 至少 HSTS 加 noSniff);
  • Cookie 会话有 SameSite 与 CSRF token;Header 凭证确认无 CSRF 面;
  • 所有写操作接口有限流(429),登录接口独立收紧;
  • 所有 id 类输入有归属校验,探测性访问回 404;
  • 数据库访问全部参数化,全项目 grep 不到字符串拼 SQL;
  • 上传接口三道门槛齐备(大小、类型、随机命名);
  • 错误响应不泄漏堆栈与内部细节(2.4 节纪律)。

💡 关键直觉:安全配置的特征是"一次配对长期受益,配错一次长期受损"。app.proxy 配错,限流与审计全失真;HSTS 忘配,降级劫持开着口;参数化漏一处,注入面就留着。自查单的价值就在于把这些"单点、静默、长期"的风险变成合并前的显式检查。

本节要点回顾

  • https 模块一行切换:证书喂给 createServer,Koa 不感知传输差异;
  • 反代形态两件事:app.proxy 加 maxIpsCount 拿可信 IP,X-Forwarded-Proto 传播协议;
  • 验证三道漏斗:结构在校验层、范围在校验与业务入口、规则在业务层;
  • 越界输入是资源攻击入口:范围检查防的是溢出与慢查询,不只是脏数据;
  • 业务层双查:先归属(是不是你的)后规则(合不合规);
  • 上线十项自查:传输、头、代理、限流、越权、参数化、上传、错误泄漏逐项过。

防护层到此全副武装。下一章转战稳态运行:找出真正的性能瓶颈、用压缩缓存与集群撑起流量、让测试与监控守住质量底线。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U