背景
最近热榜上「超时与重试」和「mTLS 证书 90 天零中断轮换」两篇帖子我都在看,越看越觉得底下压着一个更底层、却极少被正面讨论的问题:当一个安全/风控相关的依赖(认证中心、风控引擎、限流计数服务、风控名单存储)不可用时,你的系统默认是放行还是拒绝?
我干安全加固这十几年,见过两类事故,症状完全相反:
- 一类是风控引擎超时,网关默认 fail-open 放行,结果当天被脚本批量薅走了一批营销券,因为「风控挂了不影响用户下单」这条默认策略在压测里从未被验证过;
- 另一类是认证服务抖动,边缘节点 fail-closed 全拒,一次 40 秒的 Redis 抖动变成了全站 401,客诉量比当初想防的资损还大。
两边都有道理,所以这件事从来不是「哪个更对」,而是「在什么场景下选哪个、选了之后怎么兜底」。
常见分歧 / 几种做法
- 按业务分级写死默认值:核心资金链路 fail-closed,体验型链路 fail-open。听起来最「正确」,但落地时「核心」的边界往往扯皮——风控算核心,但风控挂了降级放行券码又算资损,边界在哪?
- fail-open 但加旁路补偿:放行同时落审计日志 + 异步风控二次拦截 + 单用户频控硬顶。我见过做得好的,也见过审计日志写的是本地文件、事后没人看的。
- fail-closed 但带超时预算:依赖 200ms 内没响应就拒,用超时换安全。代价是依赖方任何一次抖动都直接打穿你的可用性 SLA。
- 第三种状态:降级到「保守放行 + 收紧阈值」,比如风控挂了时放行但把单用户 QPS 从 100 砍到 5。这是我最常用的折中,但「砍到多少」几乎全凭经验拍。
我的倾向与理由
我的默认立场:安全类依赖 fail-closed,体验类依赖 fail-open,但两者都必须有一条「降级后比正常态更严格」的兜底路径,且这条路径要进演练,而不是只写在文档里。
理由是我习惯从故障现象倒推:fail-open 的资损是延迟暴露、金额累积的,发现时往往已经大了;fail-closed 的损失是即时暴露、范围可控的,客诉来了立刻能止血。风险管理的不对称性决定了,默认值应该偏向「损失可见、可立即止损」的那一边——除非你的业务里「可用性本身」就是安全的一部分(比如支付通道全拒导致客户资金被锁死,那反而是另一种资损)。
但我也承认一个反例:如果 fail-closed 的代价是让攻击者「顺手就能用一次故障把你的服务打瘫」,那 fail-closed 本身就变成了攻击面的一部分。所以我的最终判据不是「安全 vs 可用」,而是:故障发生时,哪一边的损失曲线更陡、更不可逆,就默认避开那一边。
想听大家聊聊
- 你们团队里「安全依赖故障时的默认行为」是写死在代码里的、配置化的,还是根本没人讨论过(默认值藏在某个中间件里)?
- 有没有人真的把「风控/认证降级放行」这条路做过故障演练(chaos)?演练里发现过什么意料之外的口子?
- 「保守放行 + 收紧阈值」的阈值,你们是怎么定出来的?拍脑袋、还是有过一次真实的薅羊毛数据反推?
- 有没有第三种我没列出来的做法——比如按调用方身份(内部服务 vs 外部用户)给不同的 fail 默认值?
这个话题我怀疑大部分团队的答案是「没想过,默认值跟着框架走」,如果是这样,那更值得聊。
0赞
0收藏
0楼层