Security Basic Notes
Security Programming
Security Principles
安全三要素:
- 机密性 (Confidentiality).
- 完整性 (Integrity).
- 可用性 (Availability).
安全原则:
- 白名单原则:
- 防火墙白名单: 默认只开放
80
与443
端口. - XSS 防御白名 单: 富文本编辑器只允许
<a>
与<img>
标签.
- 防火墙白名单: 默认只开放
- 最小权限原则.
- 纵深防御原则:
- Web 应用安全.
- 网络环境安全.
- 数据库安全.
- OS 系统安全.
- 数据与代码分离原则:
- 缓冲区溢出漏洞: 混淆代码与数据边界, 导致安全问题发生.
- 注入漏洞: 混合应用代码与用户数据, 导致 SQL/XSS/CSRF/XML 漏洞发生.
- 不可预测性原则:
- 有效地对抗基于篡改与伪造的攻击.
- 随机栈基址防御缓冲区溢出攻击.
- 加密哈希 Token 防御 CSRF 攻击.
STRIDE 威胁分析模型:
Threat | Definition | Security |
---|---|---|
Spoofing | 伪装 (他人身份) | 认证 |
Tampering | 篡改 (数据或代码) | 完整性 |
Repudiation | 抵赖 (做过的事情) | 不可抵赖性 |
Information Disclosure | 信息泄露 (机密数据) | 机密性 |
Denial of Service | 拒绝服务 | 可用性 |
Elevation of Privilege | 提升权限 (未经授权获得许可) | 授权 |
DREAD 风险分析模型:
- :
- 高危: 12 ~ 15 分.
- 中危: 8 ~ 11 分.
- 低危: 0 ~ 7 分.
- Damage Potential:
- High: 完全验证权限, 执行管理员操作, 非法上传文件.
- Medium: 泄露敏感信息.
- Low: 泄露其他信息.
- Reproducibility:
- High: 攻击者可以随意重复攻击.
- Medium: 攻击者可以重复攻击, 有时间限制.
- Low: 攻击者难以重复攻击.
- Exploitability:
- High: 初学者短期能掌握攻击方法.
- Medium: 熟练者才能掌握攻击方法.
- Low: 漏洞利用条件非常苛刻.
- Affected users:
- High: All user, key user, default configuration.
- Medium: Some user, non-default configuration.
- Low: Rare user, anonymous user.
- Discoverability:
- High: 漏洞显眼, 攻击条件容易获得.
- Medium: 私有区域才可发现漏洞, 需要深入挖掘.
- Low: 发现漏洞极其困难.
Software Security Assurance
- 逻辑安全.
- 数据安全:
- 数据访问权限.
- 数据访问时间.
- 数据存储格式.
- 数据存储位置.
- 数据分解与组合.
- UI 安全.
- 约束安全:
- 数据正确类型.
- 数据正确范围.
- 数据长度的最大值和最小值.
- 数据非法值.
Defensive Programming
保护程序免遭非法数据的破坏:
- 检查所有来源于外部的数据:
当从外部接口中获取数据时, 应检查所获得的数据值, 以确保它在允许的范围内.
- 检查接囗数据字段: 是否存在/数据类型/取值范围/缺省值/正则表达式/特殊字符.
- 检查方法的属性参数做必要的转换: 是否存在/数据类型/取值范围/缺省值/正则表达式/特殊字符.
- 检查子程序所有输入参数的值.
- 决定如何处理错误的输入数据: 一旦检测到非法参数, 选择适合的错误处理方处理.
断言:
- 用错误处理代码处理预期发生的状况, 用断言去处理那些不该发生的错误!
- 利用断言来注解前条件和后条件: 对于
入参
/外部数据
/返回结果
进行检查, 是否符合业务逻辑. - 避免将需要执行的子程序放到断言中.
- 通过写断言, 不仅可以提高防御性, 还能提高可读性.
程序的健壮性:
- 健壮性具体指的是应用在不正常的输入或不正常的外部环境下仍能表现出正常的程度.
- 不断 尝试采取措施来包容错误的输入以此让程序正常运转 (对自己的代码要保守, 对用户的行为要开放:
主动防御处理是有降级/容错处理, 尽量不要走到
Error Boundary
. - 考虑各种各样的极端情况:
- 考虑到各种可能的输入修士, 兼容全面.
- Mock 各种极端数据进行测试.
- 即使终止执行, 也要准确/无歧义的向用户展示全面的错误信息.
- 抛出有助于 Debug 的错误信息: 丰富捕获到的错误信息, 包含更多上下文信息.
程序的正确性:
- 返回
中立值
/默认值
: 处理错误的最佳做法就是继续执行操作并简单的返回一个没有危害的值.- 换用下一个正确的数据: 在轮询中, 如返回数据有误就丢掉, 进行下一轮查询.
- 返回上一次正确的数据: 同上, 不跳过的也可以返回上一次正确的数据.
- 选择最接近的合法值.
- 上报错误日志: 上报的错误日志对还原问题和调试友好.
- 返回一个错误状态码.
- 启动错误处理子程序或对象.
- 显示对用户友好的出错消息: 展示给用户的错误信息需要加工, 用户能看明白, 有建设性.
- 正确性要求高的话, 就直接退出程序.
异常处理:
- 用异常通知程序的其他部分, 发生了不可忽略的错误.
- 只在真正例外的情况下才抛出异常: 当前有错误就直接抛出去, 会导致线上监控的错误信息质量不高.
- 不能用异常来推卸责任: 能在局部处理掉就在局部解决掉, 不要简单抛出去.
- 避免在构造函数和析构函数中抛出异常, 除非你在同一个地方把它们捕获.
- 在恰当的抽象层次抛出异常: 不要把底层的异常抛给高层的调用方, 暴露具体实现的细节.
- 异常消息中加入关于导致异 常发生的全部信息.
- 避免使用空
catch
语句. - 考虑创建一个集中的异常上报机制.
- 考虑异常的替换机制.
代码隔栏:
- 左侧外部接口数据假定是脏数据 (不可信), 通过中间这些类 (子程序) 构成隔栏, 负责清理与验证数据, 并返回可信的数据.
- 最右侧的类 (子程序) 全部在假定数据干净 (安全) 的基础上工作, 这样可以让大部分的代码无须再担负检查错误数据的职责.
- 适配器模式和门面模式用来隔离或适配变化, 是对不可控变化的防御.
辅助调试代码 (Debugging Aids
):
- 在早期的引入辅助调试代码, 发布时移除调试辅助的代码:
console.log
算是一种辅助调试代码, 发布时清除.- 在复杂的调试场景下, 有必要专门写一些辅助调试代码.
- 利用 Chrome 插件追踪变量和状态变化辅助调试.
- 采用进攻式编程:
- 尽量让异常的情况在开发期间暴露出来, 而在产品上线时自我恢复.
- 在开发阶段考虑到最坏的情况.
- 写单测是一进攻式编程.
UI 的防御性:
- 防白屏:
- 白屏监控.
- 资源加载失败重试.
Service Worker
: 资源 fallback 机制.- 模块都包装了
Error Boundary
. - 兼容性探测和提示.
- 白屏提示信息.
- 防慢 (网络慢/响应慢/渲染慢/执行慢): 前端性能优化.
- 防卡 (卡顿/假死): 前端性能优化.
- 防布局错乱: 前端响应式开发.
- 防极端内容 (缺失/超长/连续字符/未转义): 前端响应式开发.
- UI 一致性问题:
- 发布设计规范 (
Design System
). - UI 走查工具.
- 视觉回归测试.
- 发布设计规范 (