Luke a Pro

Luke Sun

Developer & Marketer

🇺🇦
EN||

如何建立安全判断能力

| , 8 minutes reading.

1. 为什么要关注这个?

你已经学会了算法,了解了陷阱。但安全不是一份清单——而是一种判断。

每个安全决策都是成本、可用性和保护级别之间的权衡。没有”完美安全”——只有”对这个威胁模型足够安全”。

这篇文章教你如何思考安全,而不仅仅是实现它。

2. 安全思维

开发者 vs. 安全工程师

开发者思维:
"我如何让这个功能工作?"
- 关注功能
- 正向路径思考
- 信任输入
- 假设用户善意

安全思维:
"这个怎么能被破解?"
- 关注失败模式
- 对抗性思考
- 不信任一切
- 假设恶意意图

像攻击者一样思考

对于每个功能,问:
1. 这做了什么假设?
2. 如果这些假设是错的呢?
3. 谁能访问什么?
4. 最坏情况会怎样?
5. 如果我是恶意的,我会怎么利用这个?

例子:密码重置
开发者:"用户点击链接,输入新密码,完成。"
攻击者:
- 如果我拦截了邮件呢?
- 如果我猜到重置令牌呢?
- 如果我请求重置别人的密码呢?
- 如果我使用令牌两次呢?
- 如果我在请求重置后更改邮箱呢?

偏执的问题

部署任何功能之前:

认证:
- 有人能以另一个用户身份认证吗?
- 如果凭据被盗会发生什么?
- 尝试有速率限制吗?

授权:
- 用户能访问其他人的数据吗?
- ID 是否可猜测?
- 每一层都检查了权限吗?

数据处理:
- 数据在哪里以明文形式存在?
- 谁能访问加密密钥?
- 日志里有什么?

失败模式:
- 出问题时会发生什么?
- 错误消息会泄露信息吗?
- 有安全的降级方案吗?

3. 威胁建模

什么是威胁模型?

威胁模型回答:
1. 我们在保护什么?(资产)
2. 谁可能攻击它?(威胁行为者)
3. 他们可能如何攻击?(攻击向量)
4. 可能出什么问题?(影响)
5. 我们如何预防?(缓解措施)

没有威胁模型,你要么:
- 防御不存在的威胁
- 遗漏存在的威胁
- 低效地分配资源

STRIDE 框架

微软的 STRIDE 分类:

S - Spoofing(欺骗)
    假冒他人身份
    缓解:认证

T - Tampering(篡改)
    修改数据或代码
    缓解:完整性检查、签名

R - Repudiation(抵赖)
    否认所做的操作
    缓解:日志、审计追踪

I - Information Disclosure(信息泄露)
    暴露机密数据
    缓解:加密、访问控制

D - Denial of Service(拒绝服务)
    使系统不可用
    缓解:速率限制、冗余

E - Elevation of Privilege(权限提升)
    获取未授权访问
    缓解:最小权限、沙箱

实用威胁建模

步骤 1:画出系统
┌──────────┐     ┌──────────┐     ┌──────────┐
│   客户端  │────▶│   API    │────▶│  数据库   │
└──────────┘     └──────────┘     └──────────┘


                 ┌──────────┐
                 │   缓存   │
                 └──────────┘

步骤 2:标记信任边界
┌─────────────────────────────────────────────┐
│ 不受信任                                     │
│  ┌──────────┐                               │
│  │  客户端   │                               │
│  └──────────┘                               │
└─────────────────────────────────────────────┘
          │ 信任边界

┌─────────────────────────────────────────────┐
│ 受信任(但要验证)                            │
│  ┌──────────┐     ┌──────────┐              │
│  │   API    │────▶│  数据库   │              │
│  └──────────┘     └──────────┘              │
└─────────────────────────────────────────────┘

步骤 3:列出每个边界的威胁
客户端 → API:
- 注入攻击
- 认证绕过
- 速率限制滥用
- 数据篡改

API → 数据库:
- SQL 注入
- 权限提升
- 数据泄露

威胁行为者画像

不同攻击者有不同的能力:

脚本小子:
- 使用现成工具
- 低复杂度
- 大量攻击
- 防御:基本安全卫生

网络犯罪分子:
- 财务动机
- 中等复杂度
- 针对性攻击
- 防御:强认证、监控

国家级行为者:
- 无限资源
- 高级能力
- 战略目标
- 防御:纵深防御,假设已被入侵

内部人员:
- 已有访问权限
- 了解系统
- 利用信任
- 防御:最小权限、审计日志

你的威胁模型是什么?
个人博客不需要防国家级攻击。
处理数十亿的银行需要。

4. 评估风险

风险 = 概率 × 影响

                    │   低概率         │   高概率         │
────────────────────┼──────────────────┼─────────────────┤
高影响              │   监控          │   立即修复       │
────────────────────┼──────────────────┼─────────────────┤
低影响              │   接受          │   最终修复       │
────────────────────┴──────────────────┴─────────────────┘

评估示例:

登录中的 SQL 注入:
- 概率:高(常见攻击)
- 影响:高(完全数据库访问)
- 优先级:立即修复

比较中的时序攻击:
- 概率:低(需要精确度)
- 影响:中(凭据泄露)
- 优先级:最终修复

管理面板中的 XSS:
- 概率:低(有限用户)
- 影响:高(账户接管)
- 优先级:监控/修复

安全的经济学

攻击者也做成本效益分析:

攻击成本 vs. 目标价值

低价值目标 + 高攻击成本 = 安全
高价值目标 + 低攻击成本 = 被攻破

你的目标:
1. 降低目标价值(最小化存储的数据)
2. 增加攻击成本(更好的安全)
3. 减少攻击者回报(限制爆炸半径)

真实例子:
- 目标:密码数据库
- 无哈希:一次泄露 = 所有凭据
- 使用 bcrypt:一次泄露 = 每个密码需要数月破解
- 攻击成本增加 1000 倍,保护价值相同

什么是”足够好”?

安全总是相对于:

1. 你在保护什么
   - 个人博客:基本安全
   - 电商:强安全
   - 医疗:合规 + 强安全
   - 国防:最大安全

2. 你在防御谁
   - 随机互联网:标准实践
   - 针对性攻击者:高级措施
   - 国家级:专门防御

3. 失败的后果
   - 尴尬:基本保护
   - 财务损失:强保护
   - 安全/生命:最大保护

4. 可用资源
   - 创业公司:优先处理最高风险
   - 企业:全面覆盖
   - 政府:纵深防御

"足够好" = 风险在可用资源内降低到可接受水平

5. 常见安全决策

什么时候用什么

密码存储:
- 总是:Argon2id 或 bcrypt
- 绝不:MD5、SHA-1、纯 SHA-256

对称加密:
- 默认:AES-256-GCM
- 替代:ChaCha20-Poly1305
- 绝不:DES、3DES、ECB 模式

非对称加密:
- 密钥交换:X25519 或 ECDH P-256
- 签名:Ed25519 或 ECDSA P-256
- 遗留:RSA-2048+ 使用 OAEP

随机数:
- 总是:secrets 模块或 OS CSPRNG
- 绝不:random 模块用于安全

TLS:
- 最低:TLS 1.2
- 首选:TLS 1.3
- 绝不:SSL、TLS 1.0/1.1

决策框架

选择安全控制时:

1. 行业标准是什么?
   - 从已建立的最佳实践开始
   - 只有充分理由才偏离

2. 威胁模型需要什么?
   - 保护与威胁匹配
   - 不要过度工程

3. 权衡是什么?
   - 性能影响
   - 可用性影响
   - 维护负担

4. 失败模式是什么?
   - 安全失败 vs. 开放失败
   - 优雅降级

5. 我们能检测到失败吗?
   - 日志和监控
   - 异常告警

安全讨论中的危险信号

某人不理解安全的警告信号:

"我们不需要担心那个"
- 泄露前的名言

"通过隐藏来安全"
- 攻击者会弄清楚的

"我们以后再加安全"
- 技术债务会累积

"它在防火墙后面"
- 防火墙是一层,不是唯一层

"我们用了[时髦词]所以我们安全了"
- 没有单一技术能解决安全

"没人会想攻击我们"
- 每个人都是目标

"我们的用户不会那样做"
- 永远不要信任用户行为

"那太不可能发生了"
- 在规模上不可能的事情经常发生

6. 培养你的技能

从泄露事件中学习

每份泄露报告都是一课:

1. 漏洞是什么?
   - 技术缺陷
   - 流程失败
   - 人为错误

2. 如何被利用?
   - 攻击技术
   - 使用的工具
   - 利用时间

3. 如何被发现?
   - 监控发现
   - 攻击者报告
   - 第三方发现

4. 什么能阻止它?
   - 技术控制
   - 流程改进
   - 培训

资源:
- Krebs on Security
- Troy Hunt 的博客
- 公司泄露报告
- CVE 数据库

练习进攻性安全

理解攻击有助于建立防御:

初学者:
- OWASP WebGoat
- HackTheBox 入门点
- TryHackMe 免费房间

中级:
- CTF 比赛
- 漏洞赏金计划(先只读)
- 易受攻击的虚拟机(DVWA、Metasploitable)

高级:
- 代码审查找漏洞
- 渗透测试课程
- 安全认证(OSCP)

你不需要成为专家攻击者。
但理解攻击能让你成为更好的防御者。

安全审查清单

# 代码审查时要问的问题

class SecurityReviewChecklist:
    """
    在审查代码时用作思维框架。
    """

    authentication = [
        "凭据是否安全存储(哈希密码)?",
        "每个请求都检查了认证吗?",
        "会话管理是否安全?",
        "有暴力破解保护吗?",
    ]

    authorization = [
        "是否在正确的层检查了访问控制?",
        "所有敏感操作都受保护吗?",
        "遵循了最小权限原则吗?",
        "用户能访问其他用户的数据吗?",
    ]

    input_handling = [
        "所有输入都验证了吗?",
        "查询参数化了吗(没有 SQL 注入)?",
        "输出编码了吗(没有 XSS)?",
        "文件上传受限制吗?",
    ]

    cryptography = [
        "使用了标准算法吗?",
        "密钥管理得当吗?",
        "随机性来自安全来源吗?",
        "敏感数据在静态/传输中加密了吗?",
    ]

    error_handling = [
        "错误消息会泄露信息吗?",
        "异常处理是否安全?",
        "系统是否安全失败?",
        "错误是否适当记录?",
    ]

    data_handling = [
        "存储了什么敏感数据?",
        "日志中有敏感数据吗?",
        "数据备份如何处理?",
        "需要时数据是否正确删除?",
    ]

7. 与非安全人员合作

沟通风险

对高管:
- 用商业术语说话(风险、成本、影响)
- 使用类比("这就像让保险库敞开")
- 尽可能量化("泄露可能造成 X 百万损失")
- 呈现带权衡的选项

对开发者:
- 具体说明漏洞
- 解释攻击场景
- 提供具体修复方案
- 不要只说"这不安全"

对用户:
- 解释"为什么"不只是"什么"
- 让安全行为变得简单
- 不要责怪错误
- 将安全内建到产品中

何时推回

有时你需要说不:

推回当:
- 截止日期压力凌驾于安全之上
- "就这一次"的例外积累
- 安全被当作可选项
- 已知漏洞没有被修复

如何推回:
- 解释具体风险
- 提出替代方案
- 记录决定
- 必要时升级

记录一切:
"在 [日期],我提出了对 [问题] 的担忧。
决定是 [接受/推迟]。
风险所有者:[姓名]。"

建立安全文化

安全是每个人的工作:

对开发者:
- 在代码审查中包含安全
- 进行安全培训
- 让安全编码成为默认
- 表彰安全修复

对组织:
- 让报告漏洞变得安全
- 奖励安全贡献
- 在规划中包含安全
- 从事件中学习而不责备

对产品:
- 默认安全设置
- 清晰的安全文档
- 简单的安全配置
- 定期安全更新

8. 判断框架

做安全决策

面对安全决策时:

1. 识别资产
   我们到底在保护什么?

2. 评估威胁
   谁可能攻击,如何攻击?

3. 评估风险
   概率 × 影响

4. 考虑选项
   有哪些缓解措施可用?

5. 权衡利弊
   成本、可用性、维护

6. 决定并记录
   做出选择,记录理由

7. 定期审查
   威胁在变化,定期重新评估

与不确定性共存

安全没有终点:

接受:
- 完美安全不存在
- 新漏洞会被发现
- 攻击者在进化他们的技术
- 你的威胁模型可能是错的

计划:
- 定期安全审查
- 事件响应
- 持续改进
- 从失败中学习

记住:
- 今天足够好明天可能不够
- 纵深防御提供韧性
- 检测和预防同样重要
- 恢复能力是必须的

9. 总结

三件事要记住:

  1. 像攻击者一样思考。 对每个系统,问:“我怎么能破解这个?“考虑认证绕过、数据访问、信任边界和失败模式。防御者必须处处正确;攻击者只需要对一次。

  2. 安全是风险管理。 没有”完美安全”——只有成本、可用性和保护级别之间的权衡。理解你的威胁模型,现实地评估风险,在最重要的地方投入资源。

  3. 通过实践建立判断力。 研究泄露事件,练习进攻技术,带着安全思维审查代码,从每个事件中学习。安全判断来自经验,不仅仅是知识。

10. 系列结语

你已经走了很长的路:

第一部分:你学会了为什么密码学重要以及基本原语。

第二部分:你掌握了对称加密——AES、操作模式和密钥派生。

第三部分:你理解了非对称密码学——RSA、Diffie-Hellman 和椭圆曲线。

第四部分:你探索了哈希、MAC 和数字签名。

第五部分:你看到了这些组件如何在真实协议中组合——TLS、密码存储、密钥管理。

第六部分:你学会了为什么好的密码学还不够,以及如何全面思考安全。

最重要的一课:密码学是工具,不是解决方案。 正确使用它,但记住安全是一个系统属性,需要持续关注代码、运营和人的因素。

现在去构建安全的系统吧。当你不确定时,记住:最好的安全决策通常是能够充分应对威胁模型的最简单方案。

祝你好运。