背景
我在做安全加固时反复撞到一个看似「运维配置」、实则是产品级取舍的问题:当请求链路里的认证服务 / 风控引擎 / 黑名单 / 设备指纹这类安全依赖不可用(超时、熔断、返回 5xx)时,业务侧到底该:
- A. fail-open:放行请求,记日志、事后补审 / 补拦;
- B. fail-closed:直接拒绝,返回 403 / 503;
- C. 分级:核心写操作 fail-closed,只读 / 低风险操作 fail-open;
- D. 兜底降级:用本地缓存的最近一次风控结果 / 静态规则集顶上,跑一段时间再决定。
我见过真实案例:
- 风控服务一次 GC 抖 2s,业务侧配了「风控超时即放行」,那一晚被刷接口薅走一批优惠券,事后追不回来;
- 反过来,某支付网关把「认证服务超时」也按 fail-closed 处理,认证服务一抖动,整个登录页 503,可用性 SLA 直接掉 0.5;
- 还有一家把设备指纹服务熔断后,本地规则集兜底跑了 40 分钟,期间放进来一批黑产账号,事后才发现指纹服务其实早就半死。
常见分歧
- 可用派:安全依赖挂了说明系统已经过载 / 异常,此时「宁可放、不可堵」,否则故障会级联到整个业务面;
- 安全派:安全依赖的语义就是「不确定时默认拒绝」,fail-open 等于把防线交给运气;
- 架构派:不该有这道题——把安全依赖设计成可降级、可离线、可本地兜底,才是正解;
- 业务派:不同接口风险等级不同,一刀切都不可取,应该按接口标注「安全敏感度」再定策略。
我的倾向
我倾向 C(分级)+ D(兜底) 的组合,理由:
- 风险不对称:读接口放行的损失(信息泄露)通常远小于写接口放行的损失(资金 / 数据被改),所以分级是底线;
- fail-open 必须带「可追溯 + 可回收」:放行 ≠ 不管,必须有事后审计钩子(异步风控、对账、冻结),否则就是裸奔;
- fail-closed 必须带「用户友好 + 自动恢复」:拒绝时要给用户明确提示与重试路径,不能是 503 黑屏,且熔断恢复要防「雪崩式重试」;
- D 的兜底必须有时效与置信度:本地规则集 / 缓存结果超过 N 分钟就该降级为更严格的策略,不能无限期信任。
一个可落地的判据(我线上用过):
- 接口标注
risk_level: high / mid / low(写资金、改核心数据 = high;读 + 写非敏感 = mid;纯读 = low); - 安全依赖故障时:
high→ fail-closed + 明确提示;mid→ fail-open + 异步补审 + 限流降速;low→ 直接放行 + 日志采样; - 兜底窗口 ≤ 5 分钟,超时自动升级策略;
- 所有 fail-open 请求打独立 metric,故障恢复后 10 分钟内跑一遍补审。
想听大家
- 你们线上真的怎么定的?有没有「事后被薅了才改」或「可用性被拖垮才改」的血泪案例?
risk_level的标注是人工维护还是接口契约自动推导?你们怎么保证不会漏标?- fail-open 的「异步补审」你们用 Kafka / 本地队列 / 直接调下游?延迟容忍度大概多少?
- 兜底窗口 N 分钟怎么定?有没有基于历史故障时长分布的定量方法?
- 有没有「安全依赖本身也做了多活 / 本地降级」的案例?成本与收益怎么算?
抛砖引玉,欢迎拍砖。
0赞
0收藏
0楼层