掘金 后端 ( ) • 2024-04-08 11:42

接口安全密钥交换

分为 web/wap(轻客户端),android/ios(受信任客户端) 两大类。

  • 针对 web/wap,首先通过 csrf 获取 RSA public key,然后通过 RSA public key,解密服务端对应你当前 session 的 AES Token,之后每次请求都是这个 AES Token 加密。
    • 首先 csrf 一定要内嵌在页面,不能放在 cookie,否则意义不大。
    • 这样 csrf 可以起到一定的保证页面是服务端渲染生成的效果
    • csrf 需要加密,每次返回的不一样(将时间戳嵌入进去),但是其实对应的后台 csrf token 是同一个。
    • 公钥需要轮换:这是一个定时任务,就是后台保存的 wap/web 密钥对,定时更新,上一个设置过期时间为 1 个月(我们前端 session 公钥过期时间最多是 2 周,无续期,保险点 1 个月)
  • 针对 android/ios,public key 针对每个版本会生成一个新的带到 app 里面服务端记录好,直接解密服务端对应你当前 session 的 AES Token,之后每次请求都是这个 AES Token 加密。
    • 由于 app 一般是受信任客户端,并且每个版本 public key 不一样,一般不用 csrf
    • 版本强制升级,也可以通过这个机制去实现。

意义:

  • https 是为了防止 wifi 劫持抓包直接能看到 http header 和 body
  • 接口加密是为了防止机器人爬取,请求伪造,客户端模拟
  • android/ios 通过 public key 基本能确定是哪个版本并且是我们信任的客户端,浏览器不能,所以加入 csrf token 在一定程度上确保一定是我们渲染的页面发的请求

安全 Header

  • Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
    • 这个头部用于启用HTTP严格传输安全(HSTS),它告诉浏览器只能通过HTTPS来访问网站。
    • max-age=31536000 指定浏览器应该在接下来的31,536,000秒(1年)内记住只通过HTTPS访问站点。
    • includeSubDomains 指令扩展了这个规则,使其也适用于当前域名的所有子域。
    • preload 指令表示网站想要被包含在预加载的HSTS列表中,这些列表内置于浏览器中,即使是第一次请求也会强制使用HTTPS。
  • X-Content-Type-Options: nosniff
    • 这个头部是一个安全功能,用于防止浏览器尝试猜测("嗅探")资源的MIME类型,它强制浏览器遵守服务器提供的Content-Type头。
    • nosniff选项可以防止一些基于MIME类型混淆的攻击,例如防止浏览器将非脚本文件解释为脚本文件。
  • X-Frame-Options: SAMEORIGIN
    • 这个头部可以防止页面被其他站点通过、、或嵌套,从而防止点击劫持攻击。
    • SAMEORIGIN仅允许来自同一源的页面将当前页面作为、等嵌入。
  • Content-Security-Policy: 内容很长,这里省略
    • 这个拦截可能会导致某些三方埋点,图片等等显示失败,需要监控(即最后加上 report-uri /api/csp-report-endpoint?version=5)这个上报的都是被拦截的,包括拦截的那些 js,css,jpg,长链接,视频资源等等
    • 这个 Header 变化很频繁,例如搜索引擎跳转你的网页,都会嵌入 js 等,以及投放的广告渠道商等等
    • /api/csp-report-endpoint 需要自己实现
    • 加入 version 参数,用于在你修改添加了新的白名单后,增加版本号,老的版本号的上报可以忽略(因为加这个 header 一般在 CDN 加,比如 Cloudflare,但是一般有很长缓存)

一个允许 google 和 facebook 所有 Content-Security-Policy 示例:

default-src 'self' data: 'unsafe-inline' blob: 'unsafe-eval' *.google-analytics.com *.googletagmanager.com *.gstatic.com *.googleapis.com *.google.co *.google.com *.google.ad *.google.ae *.google.com.af *.google.com.ag *.google.al *.google.am *.google.co.ao *.google.com.ar *.google.as *.google.at *.google.com.au *.google.az *.google.ba *.google.com.bd *.google.be *.google.bf *.google.bg *.google.com.bh *.google.bi *.google.bj *.google.com.bn *.google.com.bo *.google.com.br *.google.bs *.google.bt *.google.co.bw *.google.by *.google.com.bz *.google.ca *.google.cd *.google.cf *.google.cg *.google.ch *.google.ci *.google.co.ck *.google.cl *.google.cm *.google.cn *.google.com.co *.google.co.cr *.google.com.cu *.google.cv *.google.com.cy *.google.cz *.google.de *.google.dj *.google.dk *.google.dm *.google.com.do *.google.dz *.google.com.ec *.google.ee *.google.com.eg *.google.es *.google.com.et *.google.fi *.google.com.fj *.google.fm *.google.fr *.google.ga *.google.ge *.google.gg *.google.com.gh *.google.com.gi *.google.gl *.google.gm *.google.gr *.google.com.gt *.google.gy *.google.com.hk *.google.hn *.google.hr *.google.ht *.google.hu *.google.co.id *.google.ie *.google.co.il *.google.im *.google.co.in *.google.iq *.google.is *.google.it *.google.je *.google.com.jm *.google.jo *.google.co.jp *.google.co.ke *.google.com.kh *.google.ki *.google.kg *.google.co.kr *.google.com.kw *.google.kz *.google.la *.google.com.lb *.google.li *.google.lk *.google.co.ls *.google.lt *.google.lu *.google.lv *.google.com.ly *.google.co.ma *.google.md *.google.me *.google.mg *.google.mk *.google.ml *.google.com.mm *.google.mn *.google.com.mt *.google.mu *.google.mv *.google.mw *.google.com.mx *.google.com.my *.google.co.mz *.google.com.na *.google.com.ng *.google.com.ni *.google.ne *.google.nl *.google.no *.google.com.np *.google.nr *.google.nu *.google.co.nz *.google.com.om *.google.com.pa *.google.com.pe *.google.com.pg *.google.com.ph *.google.com.pk *.google.pl *.google.pn *.google.com.pr *.google.ps *.google.pt *.google.com.py *.google.com.qa *.google.ro *.google.ru *.google.rw *.google.com.sa *.google.com.sb *.google.sc *.google.se *.google.com.sg *.google.sh *.google.si *.google.sk *.google.com.sl *.google.sn *.google.so *.google.sm *.google.sr *.google.st *.google.com.sv *.google.td *.google.tg *.google.co.th *.google.com.tj *.google.tl *.google.tm *.google.tn *.google.to *.google.com.tr *.google.tt *.google.com.tw *.google.co.tz *.google.com.ua *.google.co.ug *.google.co.uk *.google.com.uy *.google.co.uz *.google.com.vc *.google.co.ve *.google.co.vi *.google.com.vn *.google.vu *.google.ws *.google.rs *.google.co.za *.google.co.zm *.google.co.zw *.google.cat *.googleadservices.com facebook.net *.facebook.net facebook.com *.facebook.com; report-uri /api/csp-report-endpoint?version=5

一些反思

  • 针对渲染的页面,内嵌 csrf token(注意不能放在 cookie,否则意义不大),至于服务器渲染,这个我们也是前后端分离,前端自己维护自己的 nodejs 服务器。前后端分离,但是最好还是有一个类似于中台的前端服务器前端自己维护,这样 SEO 更好做。
  • 这些只是加固了安全性,但是并不能保证 100% 安全。但是复杂度已经很高了,目前够用了。
  • 并且在这些机制的基础上,去做 2FA 或者 MFA 也更好做,有利于减少 2FA 对于用户的打扰。