安全、开源与技术交付
安全不是上线前加一层“检查”,技术交付也不是把代码推上去。系统需要从设计阶段就明确资产、信任边界、攻击面和失败后的影响;交付则需要版本、文档、许可、迁移和回滚信息。
1. 先做威胁模型
跳转到“1. 先做威胁模型”威胁模型不是列出所有攻击,而是回答四个问题:
- 我们在保护什么:账号、资金、隐私、内部文档、密钥、可用性。
- 谁可能攻击:外部匿名用户、登录用户、恶意员工、第三方服务、供应链。
- 哪里是信任边界:浏览器到服务端、服务到数据库、租户之间、内部网到公网。
- 资产被破坏会怎样:泄露、篡改、丢失、拒绝服务、越权操作。
1.1 数据流图
跳转到“1.1 数据流图”浏览器 → CDN/WAF → API → 业务服务 ├→ 数据库 ├→ 对象存储 ├→ 第三方 API └→ 消息队列 → Worker在每条箭头标出身份、数据、加密和权限检查。没有明确身份和边界的路径,通常是风险来源。
1.2 STRIDE
跳转到“1.2 STRIDE”| 威胁 | 含义 | 例子 |
|---|---|---|
| Spoofing | 冒充身份 | 偷取会话、伪造回调 |
| Tampering | 篡改数据 | 修改价格、请求参数 |
| Repudiation | 否认操作 | 缺少审计日志 |
| Information disclosure | 信息泄露 | 越权读取、公开存储桶 |
| Denial of service | 拒绝服务 | 资源耗尽、超大请求 |
| Elevation of privilege | 权限提升 | 普通用户执行管理员操作 |
每个威胁配一个可执行控制:认证、签名、审计、加密、限流、权限检查。
2. 认证、会话与权限
跳转到“2. 认证、会话与权限”- 认证回答“你是谁”,授权回答“你能做什么”。
- 前端隐藏按钮不是授权;后端必须检查每个受保护资源。
- 会话 Cookie 应设置
HttpOnly、Secure和合适的SameSite。 - JWT 要验证签名、算法、过期、签发者和受众,不把敏感信息只做 base64 编码。
- OAuth/OIDC 使用授权码 + PKCE、state 和严格回调白名单。
- API Key 要可轮换、可撤销、可限权,不能放在前端。
2.1 对象级权限
跳转到“2.1 对象级权限”常见越权是修改 URL 中的 ID:
GET /documents/123如果系统只检查“用户已登录”,攻击者可以枚举其他文档。每次访问都要验证:
- 用户是否属于该租户。
- 用户是否拥有该资源的读取/编辑权限。
- 资源当前状态是否允许该操作。
- 共享链接是否有有效期和最小范围。
2.2 安全会话
跳转到“2.2 安全会话”登录成功后应轮换会话 ID,防止会话固定。退出登录要撤销服务端会话或刷新令牌。敏感操作可以要求二次认证。密码存储使用专门密码哈希算法和每个用户独立盐,不使用普通 SHA/MD5。
3. 常见 Web 攻击面
跳转到“3. 常见 Web 攻击面”3.1 注入
跳转到“3.1 注入”把不可信输入拼进 SQL、命令、模板或 ORM 原始片段,可能改变程序语义。
// 错误:拼接输入db.query(`SELECT * FROM users WHERE email = '${email}'`);
// 正确:参数化查询db.query("SELECT * FROM users WHERE email = $1", [email]);参数化查询适用于数据值;表名、列名和排序方向不能随便参数化,应使用白名单。Shell 命令尽量使用参数数组,避免 shell: true 和字符串拼接。
3.2 XSS
跳转到“3.2 XSS”未转义的用户内容进入 HTML,脚本可能在其他人浏览器中执行。风险包括窃取会话、冒充操作和读取页面数据。
防护:
- 默认输出编码。
- 少用
innerHTML,必须用时经过可信净化。 - CSP 限制脚本来源,但 CSP 不是唯一防线。
- 富文本使用严格白名单。
- Cookie 使用
HttpOnly降低令牌被脚本读取的风险。
3.3 CSRF
跳转到“3.3 CSRF”浏览器会自动携带 Cookie,恶意站点可能诱导用户发出已认证请求。
防护:
- 使用
SameSiteCookie。 - 写操作要求 CSRF token 或自定义头部。
- 不用 GET 执行状态变更。
- 关键操作二次确认。
3.4 SSRF
跳转到“3.4 SSRF”服务端根据用户提供的 URL 发起请求时,可能被诱导访问内网、元数据服务或本地管理端口。
防护:
- 目标域名白名单。
- 解析后检查 IP,阻止私有地址和回环地址。
- 禁止任意协议和重定向跳转。
- 使用独立出站代理与最小网络权限。
3.5 文件上传
跳转到“3.5 文件上传”- 限制大小、类型和数量。
- 校验实际内容,不只信扩展名和 Content-Type。
- 文件名重新生成,避免路径穿越和控制字符。
- 上传后扫描恶意内容。
- 存储与执行环境隔离,使用私有访问或短期签名 URL。
3.6 反序列化与外部数据
跳转到“3.6 反序列化与外部数据”反序列化不可信对象可能触发代码执行、资源耗尽或类型混淆。优先使用纯数据格式和 schema 校验,限制嵌套深度、字段数量和总大小。第三方 webhook 要验证签名和时间戳,防止伪造与重放。
4. 加密与密钥
跳转到“4. 加密与密钥”4.1 传输与存储
跳转到“4.1 传输与存储”- 对外通信使用 HTTPS,内部敏感链路也应加密或隔离。
- 数据库、备份、对象存储和密钥应有静态加密。
- 加密不能替代访问控制;有密钥的人仍能读取明文。
- 密码使用不可逆哈希,不用可逆加密。
4.2 密钥管理
跳转到“4.2 密钥管理”密钥不能写进源码、镜像、前端包、日志或聊天记录。使用密钥管理服务或环境注入,按用途和环境隔离,定期轮换。访问密钥要有审计,泄露时要能快速撤销和轮换。
5. 依赖与供应链
跳转到“5. 依赖与供应链”项目依赖的库、构建工具、容器镜像和 CI 插件都可能成为攻击入口。
- 锁定依赖版本,保留 lockfile。
- 只从可信源安装,注意包名仿冒。
- 审查安装脚本和构建权限。
- 定期扫描已知漏洞,但不能只看扫描数量。
- 生成 SBOM 或至少记录直接依赖与版本。
- 构建产物签名、校验和来源证明能提高可追溯性。
依赖漏洞是否可利用,要结合调用路径、输入边界和运行权限判断。升级修复前先读变更说明,避免自动升级引入破坏。
6. 安全交付流程
跳转到“6. 安全交付流程”需求与威胁模型 → 设计与权限评审 → 编码与静态检查 → 依赖/镜像扫描 → 测试(含权限和注入) → 灰度发布 → 监控与应急安全检查应尽量自动化,但不能用工具代替设计评审。一个通过扫描的系统仍可能允许任意用户读取别人的订单。
6.1 最小权限
跳转到“6.1 最小权限”- 服务账号只拥有所需资源权限。
- CI/CD 部署凭据按环境隔离。
- 数据库用户不要共用管理员账号。
- 容器不以 root 运行。
- 云存储默认私有。
- 内部工具也要认证和审计。
6.2 审计
跳转到“6.2 审计”重要操作记录谁在何时对什么资源做了什么,结果如何。审计日志应防篡改并限制访问,不能和普通调试日志一样随意删除。隐私数据写入审计前要脱敏。
7. 开源协作与许可证
跳转到“7. 开源协作与许可证”使用开源项目要理解许可证,不只看“GitHub 上能下载”。
常见许可证大致分为:
- 宽松型:MIT、Apache-2.0、BSD,通常允许修改和商业使用,但保留版权/许可声明。
- 弱 copyleft:LGPL 等,对链接方式和分发有特定要求。
- 强 copyleft:GPL/AGPL,分发或提供网络服务时可能有源代码开放义务。
- 非商业/共享相同方式:CC BY-NC-SA 等,限制商业用途并要求署名与相同许可。
许可证条款需要阅读原文,特别是:
- 是否允许商业使用。
- 是否要求公开修改后的源代码。
- 是否要求相同方式共享。
- 是否保留 NOTICE、版权和出处。
- 数据库、字体、图片、模型权重是否另有许可。
7.1 参与开源
跳转到“7.1 参与开源”- 阅读贡献指南和行为准则。
- 先搜索已有 issue,再提问题。
- 一个变更解决一个清晰问题。
- 不提交来源不明或与项目许可冲突的代码。
- 尊重维护者时间和项目边界。
8. 技术选型
跳转到“8. 技术选型”选型不是寻找“最强技术”,而是寻找匹配当前约束的最简单方案。
要比较:
- 需求与性能目标。
- 团队经验与维护能力。
- 生态、文档、社区和长期支持。
- 部署、运维、监控和迁移成本。
- 安全、许可证和供应商风险。
8.1 常见陷阱
跳转到“8.1 常见陷阱”- 简历驱动:为了使用新技术而引入不必要复杂度。
- 盲目追新:忽略稳定性、迁移和团队学习成本。
- 只看基准:测试环境与真实数据分布不同。
- 忽略退出成本:数据锁定、专有 API 和迁移难度。
- 过度设计:为不存在的规模预先拆分系统。
8.2 ADR
跳转到“8.2 ADR”架构决策记录应写明:
背景与约束备选方案决定理由代价与风险验证指标回滚/退出条件ADR 让后来者知道当时的假设,而不是只看到结果。
9. 技术写作
跳转到“9. 技术写作”文档是交付物的一部分。最需要的不是长篇教程,而是能回答实际问题:
- 项目解决什么问题,不解决什么。
- 如何安装、配置、启动和验证。
- 关键概念与架构图。
- 数据模型、接口和错误码。
- 运维、备份、故障与回滚。
- 已知限制和许可。
9.1 写作原则
跳转到“9.1 写作原则”- 先写读者要完成的任务。
- 示例要能运行,命令和路径要一致。
- 明确版本、前置条件和预期结果。
- 用短段落、表格和检查清单降低扫描成本。
- 不把敏感信息、内部地址和个人数据写进公开文档。
- 文档随代码更新,过期内容比没有更危险。
10. 交付清单
跳转到“10. 交付清单”- 威胁模型、资产和信任边界是否明确。
- 身份、会话、对象级权限是否在服务端验证。
- 输入、上传、回调和外部 URL 是否按不可信处理。
- 密钥是否与代码和镜像分离,是否可轮换。
- 依赖和镜像是否锁定、扫描和可追溯。
- 是否检查许可证、版权和第三方资产来源。
- 是否有测试、灰度、监控和回滚。
- 文档是否说明安装、配置、接口、限制和故障处理。
- 选型是否记录取舍、风险和退出条件。
- 对外发布是否保护隐私、密钥和内部拓扑。