安全设计面试
安全设计面试
【中等】如何设计一个接口签名验证机制?⭐⭐⭐
签名(防篡改)
要点:参数排序 + 密钥 = 签名,两边算法一致就安全。
- 做法:客户端将所有请求参数(含时间戳、随机数)按字母排序后拼接,末尾附上双方约定的密钥(Secret),然后计算哈希(如 HMAC-SHA256)得到签名,放在请求头中。
- 服务端校验:用同样的规则重新计算签名,比对客户端签名。一致则参数未被篡改。
时间戳(防过期)
要点:时间戳差值超窗口,请求直接算过期。
- 做法:请求参数中携带客户端生成请求的 Unix 时间戳(timestamp)。
- 服务端校验:用当前时间减去
timestamp,如果差值超过允许的时间窗口(如 5 分钟),则请求过期,拒绝。
随机数(防重放)
要点:随机数存 Redis,窗口期内只一次。
- 做法:请求参数中携带客户端生成的唯一随机字符串(nonce),如 UUID。
- 服务端校验:在通过时间戳校验后,检查 Redis(或其他缓存)中是否已存在该
nonce。- 如果存在 → 重复请求,拒绝。
- 如果不存在 → 存入 Redis,设置过期时间等于时间窗口(5 分钟)。
【中等】如何实现敏感词过滤功能?⭐⭐⭐
构建敏感词库 + 快速多模式匹配算法,在文本中检测并替换敏感词。
业界常用 Trie + DFA 实现敏感词过滤功能(其实就是 AC 自动机的原理):Trie 构建词库,DFA 提供状态转移,一次扫描文本即可匹配所有敏感词。
实现步骤
- 构建 Trie 树:所有敏感词插入 Trie 树。
- 构建失败指针:BFS 遍历 Trie 树,为每个节点设置失败指针,将 Trie 转化为 DFA(确定有穷自动机)。
- 扫描:文本逐字符在自动机上转移,到达敏感词结尾即标记替换。
【中等】接口中的敏感数据(如身份证号、手机号)应该如何保护?⭐⭐⭐
核心原则:传输通道加密 + 数据内容加密 + 存储加密 + 密钥安全。
传输加密:双重保险
基础保障:HTTPS(TLS)
要点:HTTPS 是底线,通道不裸奔。
作用:加密整个传输通道,防止中间人窃听、篡改。
要求:全线启用 HTTPS,禁用弱加密套件。
进阶保障:应用层加密(字段级)
- 要点:公钥加密传,私钥解密看,字段级防护更保险。
- 场景:防止内网嗅探、HTTPS 卸载后的风险,或部分参数需要在 URL/日志中可见但需保护内容。
- 做法:
- 客户端使用服务器公钥(RSA)对敏感字段(如身份证号)进行加密。
- 服务端使用私钥解密得到明文。
存储加密:核心防线
算法选择:对称加密(AES-256)
- 要点:AES 加密存密文,IV 随机不重复。
- 原因:对称加密性能好,适合大量数据。
- 做法:
- 存储前,用 AES 密钥对敏感字段加密,得到密文存入数据库。
- 读取时,用相同密钥解密。
- 注意:
- 密钥绝不能硬编码在代码里。
- **初始化向量(IV)**应随机生成并与密文一起存储。
密钥管理:KMS/HSM
- 要点:密钥托管 KMS,轮换审计不放松。
- 要求:密钥应定期轮换,使用专门的密钥管理服务(如 AWS KMS、阿里云 KMS)或硬件安全模块(HSM)。
附加保护措施
- 脱敏显示:展示必须脱敏,日志同样处理——在界面、日志中只显示部分内容(如
138****1234)。 - 最小化收集:能不存就不存,能匿名就匿名——只收集业务必需的数据,不存无关敏感信息。
- 访问审计:访问留痕迹,审计可追溯——记录谁、何时、为什么访问了敏感数据。
【中等】加密后的数据怎么支持模糊搜索?⭐⭐
方案一:分词加密(最常用)
要点:数据分词存密文,搜索分词去匹配,索引加速效果好。
- 原理:
- 对原始数据进行分词(如手机号
13812345678拆成138,1381,13812... 或固定长度组合)。 - 对每个分词进行确定性加密(每次加密结果相同,如 AES 确定模式)。
- 将分词密文存入辅助字段,建立索引。
- 搜索时,对搜索词做相同分词和加密,用加密后的分词去索引中匹配。
- 对原始数据进行分词(如手机号
- 优点:
- 支持模糊搜索:通过匹配部分词实现模糊效果。
- 性能较好:使用索引精确匹配。
- 缺点:
- 安全性略降:确定性加密和分词暴露了部分信息(攻击者可统计频率)。
- 存储增加:需额外字段。
方案二:数据库解密搜索(迫不得已)
要点:解密再查询,简单但巨慢,慎用。
- 原理:
- 在数据库层面使用可解密的函数(如 MySQL 的
AES_DECRYPT)。 SELECT * FROM user WHERE AES_DECRYPT(encrypted_phone, key) LIKE '%138%'。
- 在数据库层面使用可解密的函数(如 MySQL 的
- 优点:
- 实现简单,不改变现有逻辑。
- 缺点:
- 性能极差:无法使用索引,全表扫描解密。
- 密钥暴露风险:密钥需传递给数据库,易泄露。
方案三:外置搜索引擎(专业方案)
要点:专业的事交给 ES,加密索引两不误。
- 原理:
- 将明文数据发送给专业搜索引擎(如 Elasticsearch),利用其内置的加密功能或插件(如 ES 的 Encrypted 字段)。
- ES 对数据加密索引,搜索时同样加密查询词进行匹配。
- 优点:
- 功能强大:支持复杂搜索、分词、排序。
- 安全可控:专业的加密方案。
- 缺点:
- 引入新组件:增加架构复杂度。
- 成本较高。
【中等】如何防止接口被恶意刷量?⭐⭐⭐
第一道防线:认(身份识别)
- 验证码:图形、滑动、点选等,区分人和机器。
- 设备指纹:通过 JS 采集设备信息,识别同一设备的恶意行为。
- 登录态:要求用户登录,增加匿名刷量的门槛。
- 要点:“是人是机,先验明正身。”
第二道防线:控(访问控制)
- IP 黑白名单:直接封禁已知恶意 IP。
- 用户黑白名单:对恶意账号进行限制或封禁。
- 地域限制:仅允许业务覆盖的区域访问。
- 要点:“黑名单直接封,白名单放心过。”
第三道防线:限(流量限制)—— 经典限流
- 接口限流:按 IP、用户、设备维度,限制单位时间内的访问次数(如每秒 5 次)。
- 资源限流:限制单一用户对核心资源(如短信验证码)的获取频率(如 1 分钟 1 条)。
- 并发限流:限制同一用户的并发连接数。
- 要点:“频率超限就拒绝,令牌桶和漏桶齐上阵。”
第四道防线:罚(惩罚与追溯)
- 队列削峰:请求先入消息队列,后端平滑处理,防止瞬间流量打垮系统。
- 日志告警:记录异常行为,触发告警,人工介入。
- 临时封禁:对异常 IP 或用户实施临时封禁(如封禁 24 小时)。
- 要点:“日志留痕,告警通知,封禁伺候。”
【困难】如何设计缓存与数据库的一致性方案?⭐⭐⭐⭐
先明确前提:缓存与 DB 是两个存储,无法原子更新,只能追求最终一致,关键是缩短不一致窗口 + 兜底修复。
更新策略对比
| 策略 | 做法 | 问题 |
|---|---|---|
| 先更新缓存,再更新 DB | 两步都成功才一致 | DB 写失败则缓存脏;并发下交叉写覆盖,不推荐 |
| 先更新 DB,再更新缓存 | 同上 | 并发交叉写仍可能脏,不推荐 |
| 先更新 DB,再删缓存(Cache-Aside) | 读时回源重建缓存 | 业界标准方案;极端时序下仍有小概率脏读 |
| 先删缓存,再更新 DB | 读时回源 | 并发读会把旧值写回缓存,需延迟双删弥补 |
Cache-Aside 的工程增强
- 延迟双删:更新 DB 后再异步延迟(如 500ms)删一次缓存,覆盖“并发读回写旧值”窗口。
- 订阅 Binlog 异步删除:Canal 监听 binlog → MQ → 删缓存,业务代码零侵入,删除失败可重试(推荐)。
- 兜底:缓存设置较短 TTL(如 5 分钟),即使删除失败也能自愈;关键数据配合对账任务。
- 幂等与顺序:删除操作天然幂等;同一 key 的更新事件按主键 hash 到同一 MQ 分区保序。
强一致需求的替代方案
- 读写锁:更新时加分布式锁阻止并发读回源,牺牲性能换一致(强一致金融字段可用)。
- 不缓存:一致性要求极高且读量不大的数据直接读 DB。
记忆点:写 DB 删缓存,Binlog 兜底删,TTL 自愈保底线,强一致加锁或不缓存。
量化与踩坑:Cache-Aside 不一致窗口通常毫秒~秒级,叠加 TTL 后最长不一致 = TTL;延迟双删的延迟值应覆盖“读请求回源写回”的耗时(一般几百 ms)。曾有线上事故:删缓存与更新 DB 顺序写反(先删缓存后更新 DB),并发读把旧值回写缓存,商品价格错误展示 5 分钟导致低价下单损失——先更新 DB 再删缓存的顺序不可颠倒。
失效场景:缓存删除成功但更新 DB 失败时,下次读回源重建的仍是旧值(DB 未变),此时无脏读但更新丢失需业务层重试;极端时序(读回源在删缓存之后、DB 更新之前完成)概率极低但存在,靠 TTL 收敛。
拓展追问
- 追问 1:为什么是删缓存而不是更新缓存?
删除更简单且天然幂等,并发写场景下更新缓存可能因线程调度顺序导致旧值覆盖新值;另外写多读少时更新缓存是浪费(更新了没人读)。若需更新(如复杂聚合值),用“删除 + 下次读重建”等价实现。 - 追问 2:Binlog 删缓存方案下,如何保证同一 key 的删除顺序?
Canal 消费端按主键 hash 到固定分区(同一行变更永远进同一分区),分区内单线程顺序消费,避免乱序删除导致旧事件覆盖新状态;消费失败重试需按序阻塞该分区。 - 追问 3:读写锁方案的锁粒度怎么定?性能代价多大?
按 key 加锁(而非全局锁),更新时持写锁阻塞该 key 的读回源;代价是该 key 的读 RT 从缓存级(1ms)退化为 DB 级(几 ms~几十 ms),仅适合强一致要求且读量不大的 key;高频读 key 上锁会成为瓶颈。
场景题
商品价格中心:价格变更日均 10 万次,商品详情读峰值 10 万 QPS,要求价格变更 5 秒内全渠道生效(App/小程序/门店屏)。请设计一致性方案。
分析要点:写路径:更新 DB + 同步删缓存(双保险),同时 Canal 监听 binlog 异步兜底删除(覆盖删缓存失败);读路径:缓存未命中时单飞(singleflight/互斥锁)重建防击穿;多级缓存注意各层失效:Redis 删除后还需广播本地缓存失效事件(或本地缓存 TTL 设 1~2 秒自愈);TTL 设 1 小时兜底自愈。5 秒生效约束下不能用长 TTL 方案,核心是“主动删除 + 广播失效”;门店屏等推场景用主动推送而非依赖缓存过期。
【中等】如何实现一个滑动验证码功能?如何防止被机器识别破解?⭐⭐
实现原理
- 生成(服务器)
- 动作:随机生成一张背景图和一张滑块图,并记录缺口的目标位置(x 坐标)。
- 关键:缺口的形状、位置每次都变,防止模板匹配。
- 交互(前端)
- 动作:用户拖动滑块拼合缺口。
- 关键:前端不仅要记录最终位置,还要记录整个拖动过程的轨迹(鼠标坐标、速度、时间戳)。
- 双重校验(服务器)
- 位置校验:最终坐标是否接近目标位置(允许微小误差)。
- 行为校验:轨迹是否符合真人操作特征(加速度、停顿、抖动)。
四层防护防破解
机器破解的核心难点在于:不仅要算对位置,还要演得像人。
缺口识别对抗(防模板匹配)
- 破解手段:机器用 OpenCV 模板匹配找缺口。
- 防护手段:
- 背景干扰:增加复杂背景、干扰线、噪点 。
- 缺口变形:滑块形状随机旋转、缩放 。
- 伪缺口:增加多个类似缺口迷惑机器 。
- 要点:“缺口形状天天变,模板匹配不好辨。”
轨迹校验对抗(防机械滑动)
- 破解手段:机器用匀速直线滑动。
- 防护手段:
- 加速度检测:真人滑动是先快后慢(匀加速→匀减速),机器常是匀速 。
- 停顿检测:真人会在中途停顿(观察位置),机器常一气呵成 。
- 抖动检测:真人手眼配合有微小抖动(±2 像素),机器轨迹过于平滑 。
- 要点:“匀速直线是机器,有快有慢才像人。”
行为上下文对抗(防脚本模拟)
- 破解手段:机器直接调用接口模拟轨迹。
- 防护手段:
- 初始位置随机:真人点击滑块不总在正中心,而是在滑块区域内随机 。
- 滑动前停顿:真人会先观察(停顿 0.1-0.5 秒),机器常立即滑动 。
- 设备指纹:校验浏览器指纹、Canvas 指纹,识别是否为真实浏览器 。
- 要点:“点击位置不固定,观察片刻再行动。”
动态策略对抗(防持续攻击)
- 破解手段:机器不断换 IP、换设备重试。
- 防护手段:
- 频次限制:同一 IP/设备短时内失败多次,直接拦截 。
- 智能切换:检测到疑似攻击,自动升级为点选验证码或短信验证 。
- 要点:“发现异常就升级,让你破解白费力。”
【中等】短信验证码如何防止被恶意轰炸?⭐⭐
| 层次 | 手段 | 目标 |
|---|---|---|
| 限 | 频次、IP、设备限制 | 控制速度,不让刷 |
| 验 | 滑动验证码 | 区分人机,拦住脚本 |
| 控 | 总量封顶、前置校验 | 不合逻辑就不发 |
| 罚 | 临时封禁、递增等待 | 增加攻击成本 |
| 断 | 监控告警、手动熔断 | 保住预算,快速止损 |
限(频率控制)
- 发送频次限制:
- 同手机号:60 秒内只能发 1 次,24 小时内不超过 5-10 次。
- 同 IP:1 分钟内同一 IP 不能发超过 3 条。
- 同设备:设备指纹维度限制。
- 要点:“手机号限频,IP 也限频,双重保险。”
验(前置验证)
- 发送前必须通过验证码:点击“获取验证码”前,先完成滑动验证码或点选验证。
- 作用:拦截 99%的自动化脚本攻击。
- 要点:“想发短信?先证明你是人。”
控(业务逻辑控制)
- 每日总量封顶:单个手机号每天最多收 10 条,达到上限当天不再发送。
- 发送前校验:如注册场景,先检查手机号是否已注册,已注册则提示“该手机已注册”,不发送验证码。
- 要点:“到量就停,不合逻辑也不发。”
罚(异常惩罚)
- 临时封禁:检测到异常高频发送(如 1 分钟请求 10 次),对该 IP 或手机号临时封禁 30 分钟。
- 增加等待时间:第二次发送等待 60 秒,第三次等待 120 秒,指数级递增。
- 要点:“越界就罚,越罚越等。”
断(降级熔断)
- 监控告警:监控短信发送成功率、失败率、总条数。发现异常激增,触发告警。
- 手动熔断:紧急情况下,运维可一键关闭短信发送功能,或切换备用通道。
- 要点:“异常激增即告警,一键熔断保成本。”
【中等】如何在涉及金钱的场景,避免因人为配置失误(如折扣粒度配错、优惠金额配错),导致资金损失?⭐⭐
产品维度防呆设计:审、看、控
审(多重审核)
要点:多重审核层层过,配置变更需签字。
- 多重审核:敏感配置(如折扣、满减)必须经过运营→主管→财务多重审核,才能生效。
- 配置即代码:将复杂配置转化为结构化表单,审批人能看到前后差异对比,避免肉眼漏看。
看(预览和评估)
要点:预览效果先看看,影响范围算清楚。
- 配置预览:在配置页提供实时预览,展示生效后的效果(如“满 100 减 50”后的订单实付金额)。
- 影响范围评估:自动计算配置会影响多少商品、多少用户、预估成本,让运营心里有数。
控(权限与复核)
要点:权限分离保安全,二次确认防手滑。
- 权限分离:配置权限与审批权限分离,运营只能提交,不能直接发布。
- 敏感操作复核:关键配置(如全场五折)需输入支付密码或短信验证码二次确认。
技术维度防御性编程:校验、版本、流控、观测
数据校验
- 边界校验:折扣率必须介于 0 到 1 之间(如 0.5 表示五折),金额必须为正整数。
- 冲突校验:
- 优惠金额 ≤ 订单金额;
- 如果同时存在多种优惠,是否允许叠加;
- 叠加优惠后实付 ≥ 0;
- 不出现负金额。
- 单元测试覆盖:核心优惠计算逻辑要有自动化测试,防止代码逻辑与配置冲突。
版本与回滚
- 配置版本管理:每次配置变更都生成新版本,支持一键回滚到上一稳定版本。
- 灰度发布:先对 1%用户生效,观察无异常后再全量。
限流与熔断
- 限流保护:如果错误配置导致瞬间大量请求(如 0 元购),限流能保护下游订单系统不被冲垮。
- 熔断机制:监控到错误率或收入异常,自动熔断优惠活动。
监控与告警
- 实时监控:监控核心指标(如客单价、优惠总额、GMV),设置上下限阈值。
- 异常告警:一旦指标偏离超过 20%,立即通过短信、电话通知负责人。
风控
- 限制优惠单日次数:限制单用户单日最多享受优惠次数,或采用风控识别异常用户,防止薅羊毛。
【中等】如何保证 JWT 安全?⭐⭐⭐⭐
保证 JWT 安全需要从签名、传输、存储、生命周期、数据内容等多个维度进行防护。
要点:加密签名防篡改,HTTPS 防截获,短生命周期减损失,安全存储避 XSS,黑名单与刷新机制保可控。
- 使用强签名算法并保护密钥:选择 RS256(非对称)或 HS256(对称),避免使用已弃用的算法(如 none)。私钥或对称密钥需妥善保管,定期轮换。
- 设置合理的过期时间:JWT 应设置较短的过期时间(如 15 分钟),配合 Refresh Token 机制,降低被盗用后的风险窗口。
- 强制 HTTPS 传输:防止中间人截获令牌。所有涉及 JWT 的请求必须通过 TLS 加密通道。
- 避免在 JWT 中存放敏感数据:Payload 是 Base64 编码,可被轻松解码,切勿存放密码、身份证号等明文敏感信息。如需存储,应使用 JWE(JSON Web Encryption)进行加密。
- 选择安全的存储位置:Web 端推荐将 JWT 存储在 HttpOnly Cookie 中,并设置 Secure 和 SameSite 属性,防止 XSS 和 CSRF 攻击。移动端可存储在安全存储区(如 Keychain)。
- 服务端维护令牌黑名单:对于登出、修改密码等场景,需将对应的 JWT 加入黑名单(如 Redis 缓存),直至过期,防止继续使用。
- 防重放攻击:可在 JWT 中加入 jti(唯一标识)并缓存,在一段时间内拒绝相同 jti 的请求,或结合时间戳和 nonce 机制。
- 限制 JWT 大小:避免在令牌中存放过多信息,以免影响网络传输性能。常用的做法是只存必要字段(如用户 ID、角色),其他信息通过缓存获取。
- 双 Token(Access Token + Refresh Token):Refresh Token 应长期有效但仅用于换取新的 Access Token,且需安全存储。每次刷新时可更换 Refresh Token 值,降低被盗风险。
- 监控与告警:记录异常 JWT 使用行为(如异地登录、短时间内多次刷新),及时触发安全策略。
方案权衡与踩坑:黑名单机制把无状态 JWT 又变回有状态(每请求多一次 Redis 查询,约 1ms),这是登出/踢人可控性的必要代价;Access Token 设 15 分钟则黑名单最多存 15 分钟 TTL,内存可控。曾有线上事故:JWT 未验证 alg 头,攻击者把算法改为 none 绕过验签获取管理权限——验签时必须显式指定期望算法,拒绝 alg 与预期不符的 Token。
失效场景:Refresh Token 泄露且未轮换时,攻击者可长期续期 Access Token;黑名单依赖 Redis,Redis 故障时需决策“拒绝所有请求”还是“放行并承担风险”,资金类系统应选拒绝。
拓展追问
- 追问 1:HS256 与 RS256 如何选?
单系统内部用 HS256(对称,性能好);多服务/跨组织验签用 RS256(私钥只在认证中心,公钥可分发,泄露公钥无法伪造 Token)。关键区别:对称密钥泄露即全线失守,非对称天然适合分布式验签。 - 追问 2:Refresh Token 轮换如何防被盗用?
每次刷新颁发新 Refresh Token 并作废旧的;若已作废的 Refresh Token 再次出现(说明被盗后双方都在用),立即废止该用户全部 Token 并强制重新登录——轮换 + 重放检测是标配。 - 追问 3:JWT 存 Cookie 还是 localStorage?
Cookie(HttpOnly + Secure + SameSite)防 XSS 窃取但有 CSRF 风险(需 CSRF Token 或 SameSite=Strict 配合);localStorage 无 CSRF 但 XSS 可直接读取。安全优先选 HttpOnly Cookie,纯 API 前后端分离可用 Authorization 头 + 短有效期。
场景题
金融 App:用户 500 万,监管要求改密/挂失后登录态 1 分钟内全部失效,同时要求验签性能不能拖慢交易接口(当前 P99 50ms)。请设计 JWT 方案。
分析要点:Access Token 15 分钟(RS256 非对称验签)+ Refresh Token 30 天并轮换;失效时效要求:纯等过期不可接受(最长 15 分钟),需 Redis 黑名单(按 userId+签发时间戳作 key,TTL=Token 剩余寿命),验签后查黑名单增加约 1ms,交易接口 P99 影响可控;改密时写入用户级黑名单键,所有该用户旧 Token 一次性失效;Redis 故障时资金接口拒绝服务(监管优先级高于可用性),非资金接口可降级放行并告警。
【中等】如何防止 CDN 链接被盗刷?⭐⭐
要点:签名防伪造,时间戳限时,IP 频次控流量,私有 Bucket 加监控,多层防护断盗刷。
基础访问控制
- Referer 防盗链:检查 HTTP 请求头中的 Referer,仅允许特定来源访问。易被伪造,作为基础防护。
- IP 黑白名单:对已知恶意 IP 或区域直接拦截,或仅允许可信 IP 访问。
- User-Agent 限制:屏蔽非标准或恶意 UA,如空 UA、爬虫 UA。
签名鉴权机制
- URL 时间戳签名:在 URL 中嵌入过期时间和签名(如 MD5),服务端验证签名和时效性,过期或篡改的请求直接拒绝。此为 CDN 厂商通用方法(如阿里云 URL 鉴权)。
- 动态令牌:每次请求携带临时 token,服务端验证通过后才返回内容。适用于高安全场景。
频次与用量控制
- 单 IP 频次限制:对同一 IP 的访问频率进行限流,超出阈值则返回 429 或封禁。
- 并发连接限制:限制同一 IP 的并发连接数,防止多线程下载。
- 流量封顶:在 CDN 控制台设置带宽峰值或流量上限,达到阈值自动熔断,避免巨额账单。
- 区域访问控制:若业务仅面向特定地区,可限制其他国家/地区的 IP 访问。
【困难】有哪些常见的安全漏洞?什么原因导致的,有什么样的危害,如何应对?⭐⭐⭐⭐
XSS(跨站脚本)
- 攻:未对输出到 HTML 的内容进行转义,导致恶意脚本在用户浏览器执行。
- 危:窃取 Cookie、会话劫持、钓鱼攻击。
- 防:
- 对特殊字符进行 HTML 转义
- 将 Cookie 标记为 HttpOnly
CSRF(跨站请求伪造)
- 攻:未验证请求来源,攻击者诱导用户在已登录状态下执行非预期操作。
- 危:修改密码、转账、发表内容等。
- 防:
- 使用 CSRF Token(表单或请求头)
- 设置 SameSite Cookie 属性
- 关键操作多重验证
SSRF(服务端请求伪造)
- 攻:服务端接收用户提供的 URL 并发起请求,未对目标进行限制。
- 危:访问内网资源、端口扫描、绕过防火墙。
- 防:
- 对请求目标进行白名单验证
- 禁用不必要的协议
- 限制返回信息
- 使用统一网络出口并设置访问控制
DDoS(分布式拒绝服务攻击)
- 攻:攻击者向目标发送海量请求
- 危:服务中断
- 防:
- 事前高防+限流
- 事中清洗+扩容
- 事后溯源+加固
文件上传漏洞
- 攻:未对上传文件类型、内容、大小进行严格校验,允许上传可执行脚本。
- 危:上传 WebShell 控制服务器、存储恶意文件传播。
- 防:
- 校验文件类型、内容、大小
- 重命名文件并存储于非 Web 可访问目录
- 使用病毒扫描
越权访问
- 攻:未对用户身份和权限进行验证,或验证不严格。
- 危:水平越权访问他人数据,垂直越权执行管理员功能。
- 防:
- 每个接口进行权限校验(RBAC)
- 基于用户 ID 和资源归属进行二次验证
- 使用安全的会话管理
敏感信息泄露
- 攻:硬编码密钥、错误堆栈暴露、传输未加密、日志中打印敏感数据。
- 危:账号密码泄露、密钥暴露导致系统被控。
- 防:
- 密钥存储于配置中心或 KMS
- 生产环境关闭详细错误信息
- 强制 HTTPS
- 日志脱敏
SQL 注入
- 攻:未对用户输入进行过滤或参数化,直接拼接 SQL 语句。
- 危:数据库被偷取、篡改、删除,甚至通过数据库执行系统命令。
- 防:
- 参数绑定:使用预编译语句(PreparedStatement)、ORM 框架内置参数化查询;
- 过滤、校验:严格输入校验;最小化数据库权限。
XXE(XML 外部实体)
- 攻:解析 XML 时启用了外部实体加载,攻击者可读取本地文件或发起 SSRF。
- 危:读取任意文件、内网探测、拒绝服务。
- 防:
- 禁用 XML 外部实体(如 DocumentBuilderFactory.setExpandEntityReferences(false))
- 使用 JSON 替代 XML
通用防御
- 安全开发生命周期:需求阶段进行风险评估,设计、编码阶段遵循安全规范,测试阶段进行黑盒扫描和渗透测试。
- 使用成熟安全框架:Spring Security、Apache Shiro 等,避免自行实现认证授权。
- 依赖管理:定期扫描安全漏洞(使用 OWASP Dependency Check),及时升级修复。
- 纵深防御:网络层防火墙、WAF、主机入侵检测、数据加密、最小权限原则。
- 监控与响应:实时审计异常行为,建立漏洞响应机制,定期演练。
权衡与踩坑:安全是成本与体验的权衡——全站强制 MFA 安全性最高但转化率受损,通常只对资金/敏感操作升级验证;纵深防御每层都有成本,优先投入高威胁面(对外接口、支付链路)。曾有线上事故:管理后台未做水平越权校验,客服通过遍历订单 ID 导出了十万条用户数据——越权是最常见也最容易被忽视的漏洞,每个接口都要校验资源归属。
量化参考:OWASP Top 10 中注入与失效的访问控制常年居前两位;依赖漏洞(如 Log4Shell)爆发时,有依赖扫描能力的团队小时级响应,没有的团队数天才发现——依赖扫描是性价比最高的安全投入。
拓展追问
- 追问 1:XSS 和 CSRF 的本质区别是什么?防护思路为何不同?
XSS 是“恶意脚本跑在用户浏览器”(信任了用户输入),防护是输出转义 + CSP;CSRF 是“攻击者借用用户浏览器已有的登录态”(信任了请求来源),防护是 Token/同源策略。两者常被混淆,但防御层完全不同。 - 追问 2:水平越权如何在架构层系统性防护?
统一鉴权切面:所有资源访问经过“当前用户 vs 资源归属”校验(拦截器/AOP),而非依赖每个开发者自觉;资源 ID 用不可枚举值(雪花 ID 而非自增 ID)降低遍历风险;审计日志记录跨归属访问尝试。 - 追问 3:安全扫描发现高危依赖漏洞,但升级会导致不兼容,怎么办?
分级响应:先评估漏洞可利用性与暴露面(外网可达的接口才是高危),无法立即升级时用 WAF 规则/配置关闭受影响功能作为临时缓解,排期升级;建立漏洞 SLA(高危 24h 内响应)而非积压。
场景题
某电商平台上线大促前安全评审:新增“分享得红包”活动(用户把活动链接分享给好友,好友点击后双方得红包)。请识别安全风险并给出防护方案。
分析要点:风险识别:① 脚本批量刷红包(黑产用多账号互点);② 分享链接被伪造(遍历用户 ID 领取);③ XSS(分享文案用户可控)。防护:领取接口签名 + 时效(链接含一次性 token);风控前置(设备指纹 + 新号限领 + 同 IP 限频);金额上限(单日领取封顶)+ 异常监控(领取速率突增自动熔断活动);文案输出转义 + CSP。核心思路:营销活动 = 钱,必须按资金链路标准做风控,而非普通接口。
【困难】如何设计一个 OAuth 2.0 服务?⭐⭐⭐
OAuth 2.0 是一种授权框架,允许第三方应用(客户端)在资源所有者(用户)授权后,有限度地访问其受保护资源,而不需要泄露用户凭证。设计一个 OAuth 2.0 服务需要围绕其核心角色、授权模式、安全性和扩展性展开。
OAuth 2.0 核心角色
- 资源拥有者:用户,授权客户端访问其资源。
- 客户端:第三方应用,需获取授权。
- 授权服务器:核心,负责用户认证、客户端管理、颁发令牌。
- 资源服务器:托管受保护资源,验证令牌并响应请求。
授权模式(四种)
- 授权码模式(最常用,最安全)
- 流程:客户端重定向用户至授权服务器 → 用户登录授权 → 授权服务器返回授权码(code) → 客户端用 code + 密钥换取访问令牌(access token) → 访问资源。
- 适用:有后端的 Web 应用。
- 隐式模式(简化,已废弃)
- 流程:直接返回 access token(URL 片段),适用于纯前端应用,但安全性低,现已由授权码 + PKCE 替代。
- 密码模式(直接使用用户名密码,已废弃)
- 流程:客户端收集用户名密码,直接向授权服务器换令牌。
- 适用:高度信任的客户端(如官方应用),但违背 OAuth 初衷。
- 客户端凭证模式
- 流程:客户端使用自己的凭证(client_id + secret)直接获取令牌,代表客户端自身访问资源。
- 适用:服务器到服务器的调用,无用户参与。微服务内部调用,定时任务访问 API 都是这样的场景。
【困难】如何设计防越权体系?水平越权和垂直越权分别如何防护?⭐⭐⭐⭐⭐
越权的本质是认证只回答了“你是谁”,没回答“你能不能碰这个资源”。防护核心是把权限校验从“开发者自觉”变成“架构强制”。
| 越权类型 | 表现 | 典型漏洞点 |
|---|---|---|
| 水平越权 | 同级别用户访问他人资源 | 接口只验登录态,不验资源归属 |
| 垂直越权 | 低权限角色执行高权限操作 | 前端藏按钮当权限、角色字段来自客户端 |
水平越权防护:资源归属校验
- 统一鉴权切面:所有资源操作经网关/拦截器/AOP 统一校验“当前用户 ID vs 资源 owner ID”,而不是每个 Controller 手写——漏一个接口就是事故。
@PreAuthorize("@auth.isOwner(#orderId)") // 鉴权逻辑收敛在统一组件
@GetMapping("/orders/{orderId}")
public Order getOrder(@PathVariable Long orderId) { ... }- 数据层兜底:SQL 强制带归属条件(
WHERE user_id = #{currentUserId}),即使上层漏校验也拿不到他人数据。 - ID 不可枚举:资源 ID 用雪花 ID 或加盐 Hash,提高遍历攻击成本(防枚举不能替代归属校验)。
垂直越权防护:RBAC/ABAC 权限模型
- 服务端强制校验:权限判断只能依据服务端会话/Token 中的角色,绝不信任前端传参或隐藏菜单;接口入口统一注解声明(如
@RequiresPermission("admin:user:delete"))。 - RBAC 打底,ABAC 补充:RBAC 适合角色固定的常规场景;涉及数据范围、环境、时间等动态条件时用 ABAC 策略引擎;生产中常用 RBAC 管功能权限 + 数据权限规则管行级范围的混合模式。
- 默认拒绝:未显式授权的资源一律拒绝,权限变更实时生效(角色回收即时踢会话或短 TTL Token)。
测试与度量:越权靠测出来
- 自动化越权扫描:用 A 用户 Token 遍历调用 B 用户资源接口,纳入 CI 回归;接口上线前强制跑越权用例。
- 审计异常访问:跨归属访问尝试记录日志并告警,越权尝试往往是攻击前兆。
权衡与踩坑:统一鉴权每请求增加 1~2ms,内部高频接口可白名单豁免但必须审计。曾发生事故:订单详情接口只验登录态不验归属,攻击者遍历自增订单 ID 批量爬走他人订单——排查发现同期上线的十几个接口全靠手写校验、漏了三个;修复后收敛到统一切面 + 订单 ID 改雪花 ID。越权防护的关键不是“有没有校验”,而是“校验是否不可绕过”。
拓展追问
- 追问 1:资源归属校验放在网关还是业务服务?
角色级粗粒度校验(垂直)可前置到网关,减少无效流量;但资源归属(水平)通常要查 DB/缓存,且涉及业务语义(如“同团队成员可看”),更适合放在服务层统一切面;两层配合:网关兜底角色、服务层精校归属。 - 追问 2:RBAC 角色爆炸(几百个角色)怎么办?
引入角色继承与权限组:基础角色 + 附加权限包组合,或用 ABAC 策略替代细粒度角色(按部门、数据范围等属性动态判定);角色数量失控通常是把“业务分工”误建模成了“权限”。 - 追问 3:如何发现存量接口的越权漏洞?
流量回放对比:用不同权限账号重放线上流量,比对返回差异;结合代码扫描识别“接收资源 ID 入参但无归属校验”的接口模式;存量整改按接口敏感度分级,资金/个人信息接口优先。
场景题
某 SaaS 平台被用户投诉“能看到别家公司的数据”:多租户 CRM 系统,租户间共享同一套表(tenant_id 字段区分)。请分析根因并设计整改方案。
分析要点:应急:先按租户维度紧急审计近 30 天跨租户访问日志,评估泄露范围并通知受影响客户;根因:无租户上下文隔离机制,各接口手写 tenant_id 条件,部分老接口漏写或参数来自前端传参(可伪造);长期方案:登录态注入租户上下文(ThreadLocal/拦截器),数据层框架自动追加租户条件(类似行级安全),禁止手写;越权扫描用例覆盖跨租户访问纳入 CI;权衡:框架自动注入对复杂跨租户查询(运营后台)需显式豁免通道,改造期间新老双轨运行需回归全部核心接口——多租户系统租户隔离必须是框架能力而非代码约定。
【困难】如何设计密钥管理体系?密钥如何存储、分发与轮换?⭐⭐⭐⭐
密钥管理的第一原则:密钥永远不该出现在代码、配置文件和日志里。体系围绕存储、分发、轮换三件事设计。
密钥分层:KEK/DEK 信封加密
| 层级 | 名称 | 职责 | 特点 |
|---|---|---|---|
| 根密钥(Root Key) | KMS/HSM 内置 | 加密 KEK | 永不出 HSM,硬件级保护 |
| 主密钥(KEK) | Key Encryption Key | 加密 DEK | 轮换成本低(只需重加密 DEK) |
| 数据密钥(DEK) | Data Encryption Key | 加密业务数据 | 随数据存密文版本,海量可并存 |
好处:轮换 KEK 只需重加密少量 DEK,不用重加密海量业务数据——这是信封加密(Envelope Encryption)的核心价值。
存储与分发
- 存储:根密钥在 HSM/KMS 中永不明文导出;DEK 密文与业务数据同存,元数据记录所用 KEK 版本。
- 分发:应用启动时通过 KMS SDK 认证后获取解密能力,或用 Vault 等动态颁发短期凭据(租约到期自动失效);严禁把密钥写进配置中心明文、Git 仓库或镜像——配置中心普遍缺细粒度审计,泄露即全员可见。
- 最小权限:每个应用只能解密自己业务域的 DEK,KMS 按 key 粒度授权并记录每次加解密调用。
轮换策略
- KEK 定期轮换(如 90 天):新数据用新版本加密,旧数据仍用旧版本解密,历史版本永不删除(存量密文还要用)。
- DEK 轮换:新写入换新密钥,存量按需后台异步重加密(数据量大时分批低峰执行)。
- 应急轮换:怀疑泄露时立即轮换 + 吊销旧凭据,这是把密钥放 KMS 的另一个理由——集中才能快速吊销。
踩坑:曾有线上事故:OSS AccessKey 硬编码在配置中心,离职员工凭旧权限导出导致密钥泄露,只能紧急轮换全量凭据并审计调用记录——密钥进配置中心 = 密钥进所有人的视野。
一句话总结:密钥分层托管 KMS,信封加密降轮换成本,密钥不落盘不进配置中心,轮换靠版本并存而非一刀切。
拓展追问
- 追问 1:密钥轮换期间如何保证读写不中断?
密文携带密钥版本号,解密按版本找对应密钥;轮换是“新写新密钥、旧读旧密钥”的渐进过程而非切换瞬间,双版本并存期覆盖存量迁移窗口;读路径对调用方完全透明。 - 追问 2:为什么不能把密钥放配置中心?配置中心不就是干这个的吗?
配置中心的设计目标是配置分发而非机密保护:通常缺访问粒度审计、缺自动轮换、权限模型粗(能读项目配置即能读所有配置);密钥应放 KMS/Vault 这类有租约、审计、轮换能力的专用系统,配置中心最多存“指向密钥的引用”。 - 追问 3:多环境(测试/预发/生产)密钥如何隔离?
每环境独立 KMS 实例或独立密钥空间,测试环境绝不能用生产密钥(哪怕脱敏数据);测试环境用低权限密钥 + 短租约,泄露影响面天然受限。
场景题
安全团队扫描发现:某核心支付服务的数据库加密密钥硬编码在代码仓库,且仓库曾短暂对全员开放读权限。如何处置?
分析要点:应急:立即轮换该密钥(新数据切新密钥)、排查仓库开放期间访问日志确认暴露面、限制存量密钥仅解密权限;根因:历史设计图省事硬编码,代码扫描门禁未覆盖密钥检测;长期方案:密钥全量迁 KMS 信封加密,应用改 SDK 取密钥;CI 加密钥扫描(gitleaks 类工具)阻断提交;存量密文分批重加密到新密钥后吊销旧密钥;权衡:全量重加密耗时长、占 IO 资源,需低峰分批执行,但密钥已视同泄露,安全优先于成本——密钥治理欠的债,迟早要以事故形式还。
【中等】数据脱敏有哪些方案?静态脱敏与动态脱敏如何选型?⭐⭐⭐
脱敏的目标是在保留数据可用性的前提下消除敏感性——测试能用、客服能看,但拿不到真实隐私。
| 脱敏方式 | 原理 | 示例 | 特点 |
|---|---|---|---|
| 掩码 | 部分字符替换为 * | 138****5678 | 最常用,展示场景首选 |
| 哈希/加盐哈希 | 不可逆映射 | 身份证 → SHA256 值 | 保留关联性(同值同结果),防彩虹表需加盐 |
| 替换/伪造 | 映射为假数据 | 姓名 → 随机姓名 | 保持格式,适合测试环境 |
| 截断/泛化 | 降低精度 | 地址只留省市、生日留年份 | 统计场景够用 |
| 置乱/加密 | 打乱或可逆加密 | 打乱顺序 | 需保留业务语义时使用 |
静态脱敏 vs 动态脱敏
| 维度 | 静态脱敏 | 动态脱敏 |
|---|---|---|
| 时机 | 数据导出/复制时一次性处理 | 查询返回时实时处理 |
| 原库影响 | 不动原库,生成脱敏副本 | 原库存明文,出口处脱敏 |
| 典型场景 | 生产数据导入测试/开发环境、数据交付第三方 | 客服后台、运维查询、日志展示 |
| 一致性 | 副本滞后,与生产有时间差 | 实时一致 |
| 代价 | 需要 ETL 流程与副本存储 | 每查询有处理开销,依赖出口统一 |
选型原则:数据要离开生产环境(进测试库、给外包)必须静态脱敏且不可逆;数据留在生产系统内但查看者权限不足,用动态脱敏按角色展示不同粒度(客服看掩码、风控看全量)。
踩坑:① 动态脱敏做在出口而非前端——接口返回明文只靠前端打码,抓包即破;② 日志是重灾区:DTO 的 toString() 把完整手机号打进日志,需在日志框架层配敏感字段过滤器;③ 加盐哈希忘了管盐,盐泄露等于没脱。脱敏不是加密:脱敏追求不可还原,加密追求可还原,别混用。
【困难】什么是零信任架构?如何在企业内落地?⭐⭐⭐
零信任(Zero Trust)的核心信条:永不信任,持续验证(Never Trust, Always Verify)——不再因为“你在内网”就信任你,每次访问都要重新验证身份、设备和权限。
零信任 vs 传统边界安全
| 维度 | 传统边界安全(护城河模型) | 零信任 |
|---|---|---|
| 假设 | 内网可信,外网危险 | 任何位置都不可信 |
| 防护重心 | 网络边界(防火墙/VPN) | 身份、设备、每次请求 |
| 访问决策 | 一次认证,长期有效 | 持续验证,动态评估 |
| 失陷后果 | 一点突破,内网横移 | 单点失陷,横向受限 |
驱动力:远程办公与云化让“内网边界”消失;边界模型下 VPN 凭证被盗即可横移全网,零信任把爆炸半径限制在单个应用。
落地路径(BeyondCorp 模型)
Google BeyondCorp 是标杆实践:取消特权内网,所有应用访问经统一接入网关,基于身份 + 设备状态动态授权。落地四步:
- 统一身份:全员全设备接入 IAM/SSO,身份是一切决策的锚点。
- 设备信任评估:采集设备合规状态(补丁、杀毒、是否受管)计算信任分。
- 统一接入网关:所有应用藏在网关后,按“身份 + 设备 + 上下文”逐请求授权,动态增删权限。
- 持续验证:会话期持续监测异常(异地登录、设备状态变化),风险升高即要求二次认证或降权。
落地权衡:零信任是架构理念而非单一产品,落地成本高(IAM、设备管理、网关改造缺一不可);中小企业不必全面铺开,可从远程办公接入这个最痛的点切入,先做接入层零信任,再逐步收敛内网可信范围;服务间的东西向零信任(mTLS + 服务身份)可作为第二阶段。
一句话总结:零信任把安全边界从网络搬到身份——位置不再产生信任,每次访问都是重新考试。
拓展追问
- 追问 1:零信任要求持续验证,如何避免每次请求都做重认证拖垮性能?
验证结果缓存为短期凭证(如 15 分钟有效令牌),常规请求验令牌即可;仅敏感操作(改密、转账、导出)触发实时二次验证;设备信任分变化才重新评估——持续验证是“持续可评估”,不是“每次都全量认证”。 - 追问 2:零信任和 VPN 的根本区别?
VPN 授予的是网络层通道——接入即拥有内网大范围可达性,凭证被盗后横移畅通;零信任授予的是应用级授权——每个应用单独鉴权,即使某凭证泄露,攻击者也只影响该应用,且行为异常会被持续验证拦截。 - 追问 3:员工设备不可信(私人电脑接入)怎么办?
分级策略:受管设备全量访问,非受管设备只能走沙箱化访问(浏览器隔离/虚拟桌面),数据不落本地;信任分决定权限边界,而非二元准入。
场景题
某公司全面远程办公,2000 员工经 VPN 接入内网。近期发现一名员工设备中毒,VPN 凭证被盗,攻击者进入内网后扫描到财务系统。如何整改?
分析要点:应急:隔离中毒设备、吊销被盗凭证、VPN 增加 MFA、排查横移痕迹;根因:典型边界模型缺陷——VPN 接入即视为可信,内网平铺无隔离,一点突破全网暴露;长期方案:按 BeyondCorp 路径改造——统一 IAM + 设备合规检查 + 零信任接入网关按应用授权,财务等高敏系统加动态信任评估(异常时间/地点访问触发二次验证);权衡:VPN 改造简单但横移风险无解,零信任投入大但把爆炸半径收敛到单应用——远程办公规模越大、数据越敏感,零信任 ROI 越高,可先拿财务、HR 等高敏系统试点。
【中等】如何保障软件供应链安全?⭐⭐⭐
供应链安全关注你引入的一切第三方东西是否可信——依赖、镜像、构建环境、分发渠道,任何一环被污染都会传导到你的系统。
| 环节 | 风险 | 防护手段 |
|---|---|---|
| 第三方依赖 | 依赖带漏洞、被投毒(仿冒包名) | SCA 扫描(Dependency-Check/Snyk)纳入 CI,高危阻断合并;锁定版本 + 镜像源代理 |
| 容器镜像 | 基础镜像带 CVE、镜像被篡改 | 镜像安全扫描(Trivy)、只从私有仓库拉取、定期重建基础镜像 |
| 制品完整性 | 传输/仓库被篡改 | 制品签名 + 部署前验签(Sigstore/cosign、Notary) |
| 资产盘点 | 漏洞爆发时不知道谁在用 | SBOM(CycloneDX/SPDX)随版本生成,漏洞通报分钟级反查影响面 |
DevSecOps 视角:安全检查必须嵌进流水线而非事后补救——提交时扫密钥(gitleaks)、合并时扫依赖(SCA)、构建时扫镜像、部署时验签名,每道门禁自动阻断而非告警了事。
量化与踩坑:Log4Shell 爆发时,有 SBOM 的团队分钟级定位受影响服务,没有的团队人肉排查数天仍不敢说查全;依赖扫描每天跑 + 高危漏洞 SLA 机制(高危限期修复,否则阻断发布)是性价比最高的投入。曾见团队依赖锁文件不提交,某次构建自动升级引入带漏洞版本——版本不锁定,供应链就是盲盒。扫描误报需人工豁免流程,否则团队会想办法绕过门禁。
一句话总结:供应链安全 = 扫描左移进流水线 + SBOM 摸家底 + 签名验签保完整,漏洞爆发时的响应速度取决于平时的盘点深度。
【中等】如何设计安全审计日志?哪些操作必须留痕?⭐⭐⭐
审计日志回答三个问题:谁、在什么时候、对什么资源做了什么、结果如何——既是合规要求(等保/GDPR),也是安全事件的追溯底线。
日志字段模型(5W1H)
| 字段 | 说明 |
|---|---|
| Who | 操作者身份(用户/服务账号)+ 来源 IP/设备 |
| When | 操作时间(统一时钟源,NTP 对齐) |
| What | 操作类型 + 目标资源标识 + 变更前后值 |
| Result | 成功/失败 + 失败原因(失败尝试更要留痕) |
必须留痕的操作
- 权限类:授权、回收、角色变更、密码重置、登录异常。
- 敏感数据类:个人信息查询/导出/解密(尤其批量),每条都可追溯到人。
- 资金类:支付、退款、提现、对账调整——资损调查的第一手证据。
- 配置与发布类:生产配置变更、发布上线、数据库 DDL。
- 管理员操作:后台一切增删改,管理员是高危身份,行为全量留痕。
设计要点
- 统一切面采集:AOP/拦截器在框架层埋点,不依赖业务代码自觉,避免漏记。
- 防篡改:日志写入独立存储(WORM/只追加),应用账号无删除权限;防“删库前先删日志”。
- 敏感字段脱敏:审计对象是行为不是明文——记录“导出了用户表 1 万条”,而不是把 1 万条数据写进日志。
- 保留与检索:按合规要求留存(通常六个月以上),冷热分层控制存储成本,保留告警能力(如单账号短时间大量导出)。
踩坑:审计日志与业务日志混存,业务清日志时把审计记录一起删了,事故追溯断链——审计日志必须独立于业务日志的生命周期管理。审计不是全记:高频读接口全量留痕成本不可接受,按风险分级只记高敏操作。
一句话总结:审计日志按 5W1H 建模、切面统一采集、防篡改独立存储,高敏操作全量留痕,普通操作按风险分级。
【困难】证书与 mTLS 如何管理?大规模服务的证书轮换如何自动化?⭐⭐⭐
mTLS(双向 TLS)让服务间调用互相验证身份——不仅服务端证明“我是真的”,客户端也要出示证书,是零信任东西向流量的基石。难点不在开启,而在大规模下的证书生命周期管理。
| 环节 | 手工管理的痛 | 自动化方案 |
|---|---|---|
| 签发 | 人工生成 CSR、CA 签发,流程数天 | cert-manager/自建 CA 自动签发,证书即代码 |
| 分发 | 证书文件拷到每台机器 | 边车/SDK 自动注入(服务网格 Sidecar 透明处理) |
| 轮换 | 忘换直到过期炸线上 | 短有效期(天级)+ 到期前自动续期,双证书灰度切换 |
| 监控 | 过期才发现 | 到期水位告警(提前 30 天)+ 握手失败率监控 |
大规模自动轮换的关键设计
- 短有效期是前提:证书有效期从天级而非年级——长有效期是“过期事故”的温床,短有效期逼出自动化。
- 双证书并存切换:轮换期新旧证书同时被信任,灰度验证无握手失败后再吊销旧证书,避免切换瞬间断流。
- 边车透明卸载:服务网格(如 Istio)由 Sidecar 完成 TLS 握手与证书续期,业务代码零改造;无网格场景用 SDK 封装。
- CA 分层:根 CA 离线保护,中间 CA 负责日常签发,根密钥泄露风险隔离。
踩坑:经典事故是长有效期证书无人认领,某天过期导致全站 HTTPS 不可用——现象是客户端大量握手失败、监控显示连接错误率飙升,排查到最后发现是三年前手工申请的证书;修复靠提前监控 + 自动化根除。证书是会被遗忘的基础设施,唯一可靠的记忆是监控系统。
一句话总结:mTLS 规模化靠“短有效期 + 自动续期 + 双证书灰度”三板斧,证书管理从人肉流程变成自动化系统。
拓展追问
- 追问 1:为什么短有效期证书反而更安全?续期压力大吗?
有效期越短,证书私钥泄露后的可用窗口越小,也越没有动力去偷一张几天就过期的证书;续期由控制器自动完成(如 ACME 协议),无额外人力,压力在系统而非人——这正是把风险从“人的记忆力”转移到“系统可靠性”。 - 追问 2:证书自动续期服务自身挂了怎么办?
续期服务是单点,需高可用部署;客户端保留本地缓存证书并提前足够余量续期(如剩 1/3 寿命即触发);监控续期失败率而非仅看证书是否过期,失败累积时告警介入。 - 追问 3:mTLS 的性能开销如何控制?
TLS 握手开销主要在首次连接,通过连接复用/长连接摊薄;会话恢复(Session Resumption)减少重复握手;实测开启 mTLS 对 RPC 的 RT 影响通常在个位数百分比,相比身份验证收益可接受。
场景题
某微服务架构 500+ 服务启用 mTLS,某天凌晨三个核心服务互相调用全部握手失败,业务大面积报错。排查发现是一张内部 CA 证书过期。如何处置与根治?
分析要点:应急:立即用备份 CA 重签证书并自动推送(证书分发通道必须独立于业务可用性),恢复握手;根因:长有效期(1 年)证书 + 无到期监控 + 手工轮换流程,三年未有人记得这张证书;长期方案:引入自动化证书管理(cert-manager/服务网格内置 CA),证书缩短到 24 小时~7 天自动续期;建立到期水位与握手失败率双重监控;轮换采用双证书灰度;权衡:短证书带来续期频率和续期服务可用性要求,但对比“全站故障”的风险完全值得——证书治理的目标是让“证书过期”从事故变成无人感知的日常。
【中等】SSRF、XXE、文件上传漏洞的原理与防御?⭐⭐⭐
上一题《常见安全漏洞》做了全景概览,本题聚焦服务端三类高危漏洞的深入防御设计——它们的共性是服务端“替攻击者干活”。
| 漏洞 | 原理 | 典型危害 | 核心防御 |
|---|---|---|---|
| SSRF | 服务端按用户给的 URL 发起请求 | 打内网、读云元数据(169.254.169.254)拿实例凭证 | 目标白名单 + 独立出口 |
| XXE | XML 解析器加载外部实体 | 读服务器任意文件、内网探测、Billion Laughs DoS | 解析器禁用外部实体与 DTD |
| 文件上传 | 可执行脚本混进上传目录 | WebShell 控制服务器 | 内容校验 + 改名隔离存储 |
SSRF 防御设计
- 目标白名单:只允许请求已登记的域名/IP 段;解析后的 IP 必须再校验(防 DNS 重绑定:校验域名后二次解析变内网 IP),用首次解析的 IP 直连发请求。
- 封堵高危目标:内网网段、回环地址、云元数据服务(
169.254.169.254)一律拒绝;禁用file://、gopher://等非必要协议。 - 统一出口:所有对外抓取收敛到一个专用代理服务,独立网络分区,泄露也只能看到隔离区。
XXE 防御设计
- 解析器层关闭:禁用外部实体与 DTD,Java 示例:
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
dbf.setFeature("http://xml.org/sax/features/external-general-entities", false);
dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);- 首选 JSON:新接口不引入 XML;遗留 SOAP/老协议无法避免时,统一封装安全解析器工厂,禁止业务自建解析器。
文件上传防御设计
- 内容校验:校验魔数(文件头)而非扩展名——
Content-Type和扩展名都可伪造;禁止上传可执行类型。 - 存储隔离:重命名为随机名,存入私有 OSS Bucket(无执行概念)或独立域名,与主站同源隔离;访问经应用层签名 URL 中转。
- 纵深防护:限制大小 + 病毒扫描;访问时响应头强制
Content-Disposition: attachment,防止浏览器直接执行。
失效场景与权衡:SSRF 白名单过严会挡合法外链需求(如抓取商户图片),可先“放行但记录告警”再逐步收敛;魔数可伪造,所以不能只靠校验,存储隔离才是底牌;XXE 防御依赖全局配置统一,一处自建解析器就会留缺口。三类漏洞的共同教训:服务端对用户提供的输入(URL/XML/文件)永远默认不信任。