mcpField
S
security-and-hardening

security-and-hardening

github.com/addyosmani安全111.5k72.3k 次安装2 周前更新
代码仓库

关于 security-and-hardening

面向 Web 应用安全开发的技能,涵盖威胁建模、边界校验、安全加固和隐私保护,也涉及常见 Web 风险、AI/LLM 功能及依赖供应链。

主要功能

  1. 01围绕信任边界进行威胁建模
  2. 02输入校验与访问控制指导
  3. 03Web 和服务端风险加固
  4. 04隐私及个人数据处理实践
  5. 05AI/LLM 安全指导
  6. 06依赖与供应链审查

适用场景

  1. 01为 Web 功能规划安全控制
  2. 02审查身份验证和数据处理改动
  3. 03评估 LLM 功能的安全风险
  4. 04准备发布前的依赖变更

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/addyosmani/agent-skills --skill security-and-hardening

安装后在 Claude Code 中输入/security-and-hardening确认已加载。

附带文件references/hardening-patterns.md

详细介绍

安全与加固

概述

采用安全优先的 Web 应用开发实践。将每个外部输入视为恶意内容,将每个密钥视为至关重要的信息,并将每次授权检查视为必需步骤。安全不是一个阶段,而是对每一行涉及用户数据、身份验证或外部系统的代码的约束。

适用场景

  • 构建任何接受用户输入的内容
  • 实现身份验证或授权
  • 存储或传输敏感数据
  • 集成外部 API 或服务
  • 添加文件上传、Webhook 或回调
  • 处理支付或 PII 数据

流程:先进行威胁建模

没有威胁模型就硬加的控制措施,只能算猜测。加固之前,花五分钟换位思考,像攻击者一样思考:

  1. 梳理信任边界。 不可信数据会在哪里进入系统?HTTP 请求、表单字段、文件上传、Webhook、第三方 API、消息队列和 LLM 输出——还有一些看起来像内部数据、只是因为 OS 把它们交给你的本地值:另一个进程的命令行或环境变量、共享卷上的文件名、作业负载中的路径。信任取决于值的编写者,而非传递渠道。每个边界都是攻击面。
  2. 列出资产。 什么东西值得窃取或破坏?凭据、PII、支付数据、管理员操作、资金转移。
  3. 对每个边界进行 STRIDE 分析——这是一种快速审视方法,不是形式主义:
威胁要问的问题常见缓解措施
S 欺骗有人能冒充用户/服务吗?身份验证、签名验证
T 篡改数据在传输中或静态存储时能被修改吗?完整性检查、参数化查询、HTTPS
R 抵赖事后能否否认某项操作?记录安全事件的审计日志
I 信息泄露数据会泄露吗?加密、字段允许列表、通用错误信息
D 拒绝服务系统可能因不堪重负而瘫痪吗?速率限制、输入大小上限、超时
E 权限提升用户能获得不该拥有的权限吗?授权检查、最小权限
  1. 在使用场景旁边编写滥用场景。 对每项功能,都问一句“我会如何滥用它?”——然后把它作为第一个测试。

如果说不清某项功能的信任边界,就还没准备好保护它。这就是 OWASP A04:不安全设计——大多数安全漏洞始于设计,而非代码。

三级边界系统

始终执行(无例外)
  • 在系统边界(API 路由、表单处理程序)验证所有外部输入
  • 对所有数据库查询进行参数化处理——绝不将用户输入拼接到 SQL 中
  • 对输出进行编码以防止 XSS(使用框架的自动转义,不要绕过它)
  • 所有外部通信都使用 HTTPS
  • 使用 bcrypt/scrypt/argon2 对密码进行哈希处理(绝不存储明文密码)
  • 设置安全标头(CSP、HSTS、X-Frame-Options、X-Content-Type-Options)
  • 会话使用 httpOnly、secure、sameSite Cookie
  • 每次发布前,使用检测到的包管理器原生审计功能审计已提交的锁文件
先征求意见(需要人工批准)
  • 添加新的身份验证流程或更改身份验证逻辑
  • 存储新的敏感数据类别(PII、支付信息)
  • 添加新的外部服务集成
  • 更改 CORS 配置
  • 添加文件上传处理程序
  • 修改速率限制或节流设置
  • 授予更高权限或角色
绝不执行
  • 绝不将密钥提交到版本控制中(API 密钥、密码、令牌)
  • 绝不记录敏感数据(密码、令牌、完整信用卡号)
  • 绝不将客户端验证视为安全边界
  • 绝不为了方便而禁用安全标头
  • 绝不对用户提供的数据使用 eval() 或 innerHTML
  • 绝不将会话存储在客户端可访问的存储中(例如使用 localStorage 存储身份验证令牌)
  • 绝不向用户暴露堆栈跟踪或内部错误详情

加固控制

以下规则构成工作流;每项规则的具体实现见 references/hardening-patterns.md。用到相关代码时再打开所需章节,无需提前查看。

注入、XSS 和访问控制
  • 对每个查询使用参数化方式。绝不根据输入字符串构造 SQL、NoSQL 或 shell 命令。
  • 通过框架的自动转义功能对输出进行编码。如果无法避免使用原始 HTML,须先通过允许列表清理器进行清理。
  • 每个请求都要检查授权,而不仅是身份验证:经过身份验证的用户必须拥有特定资源,或获准访问该资源(A01,IDOR)。

模式:注入、XSS、访问控制。

身份验证和会话
  • 使用 bcrypt(≥12 轮)、scrypt 或 argon2 对密码进行哈希处理。会话密钥必须来自环境变量,不能写在代码中。
  • 会话 Cookie 必须设置 httpOnly、secure 和 sameSite: 'lax' 或 'strict'(用于防御 CSRF;'none' 会在跨站请求中发送 Cookie),并设置有界的 maxAge。

模式:身份验证。

标头、CORS 和响应
  • 每个响应都要包含安全标头(使用 helmet 或框架的等效功能);CSP 从 default-src 'self' 开始,并逐步收紧,而不是放宽。
  • CORS 仅允许配置中明确列出的来源。启用凭据时,绝不能使用 *。
  • 在发送任何响应前,移除敏感字段(passwordHash、重置令牌)。错误响应正文应使用通用内容;内部信息只能写入服务端日志。

模式:错误配置、敏感数据泄露。

输入验证和上传
  • 在边界处使用 schema 进行验证:允许列表中的结构、长度、枚举值和格式。拒绝时返回 422 和结构化详情;下游代码只能使用解析后的类型化值。
  • 上传:使用允许列表限制 MIME 类型、限制大小,并在必要时验证内容(魔数)。文件扩展名不能证明任何内容。

模式:Schema 验证、文件上传。

服务端抓取(SSRF)

用户能够影响的任何 URL——webhook、从 URL 导入、图片代理、链接预览——都可能被指向内部服务。使用允许列表限制 scheme 和 host,解析所有 DNS 记录并拒绝任何私有或保留地址(回环、链路本地 169.254.169.254、私有地址、IPv4 和 IPv6 的唯一本地地址),并禁止重定向。此检查仍存在 DNS 重绑定 TOCTOU 漏洞:对于高风险入口,应固定已解析的 IP,或在前面设置过滤 Agent。

模式:SSRF。

对派生路径执行破坏性操作

删除、移动或覆盖操作的安全性取决于用于指定目标的值;信任应取决于该值的写入者,而不是传递它的渠道:另一个进程的命令行与表单字段一样,都可能受攻击者控制。形状检查只能证明格式正确,不能证明已获授权。调用前必须同时满足以下三项:解析后的目标(已解析符号链接)位于允许列表中的根目录之下;目标至少位于该根目录下一层;并且目标具有在操作前读取的所有权证据。拒绝时,记录被拒绝的目标并停止;绝不能回退到范围更广的默认路径。

为什么这项检查并没有看起来那么可靠(标记自我证明、检查与使用之间的竞争条件):破坏性路径。示例代码:../../references/security-checklist.md。

速率限制

对 API 实施常规限流,并严格限制身份验证端点(每 15 分钟约 10 次尝试)。一旦多个进程开始处理流量,内存计数器就会悄然变成 max × instances,或者在无服务器环境中完全不触发:请使用共享存储作为限流器的后端。

模式:速率限制。

密钥

密钥来自环境变量。提交 .env.example 并使用占位符;将真实的 .env* 文件和密钥材料加入 gitignore;提交前检查暂存的差异。密钥一旦到达远程端,就已泄露:先轮换密钥,再清除历史记录。

模式:密钥管理。

依赖项和供应链
  1. 找到安装边界和包管理器。 使用拥有锁文件的工作区根目录;只有在独立的嵌套项目位于该工作区之外时,才使用该项目。交叉核对 packageManager(如有)、锁文件和 CI;如果信息不一致或存在多个竞争的锁文件,请停止操作。固定包管理器版本。
  2. 首次执行前阻止依赖项脚本。 禁用脚本或采用有文档记录的默认拒绝策略进行引导;检查待执行脚本的源代码,只批准最低限度的脚本,提交策略,然后通过干净的冻结/不可变安装进行验证。切勿一概批准。
  3. 每次发布前,使用已提交的锁文件运行原生审计。 根据可达性(运行时、构建、测试、部署路径)确定严重/高危问题的优先级,并修复影响可用性的问题。切勿自动执行强制修复(npm audit fix --force 或同类操作),因为强制修复可能超出已声明的依赖范围;请先预览、阅读变更日志,并逐项测试升级。每项延期都要记录理由和复审日期。
  4. 审计只能匹配已知公告。 它们无法发现新出现的恶意包或仿冒包(cross-env 与 crossenv)。请一并审查新增依赖项、锁文件差异和脚本策略变更:所有权、维护情况、发布年限、来源证明和传递依赖图。支持的情况下验证注册表签名(npm audit signatures、pnpm audit signatures);如果缺少签名,应将其视为需要调查的信号,而非自动认定已遭入侵(A06、LLM03)。

确定处理优先级的决策树:依赖项审计分流。包管理器矩阵和安装脚本门控:../../references/security-checklist.md。

个人数据与隐私

安全加固关注“攻击者能否读取它?”,隐私关注“我们是否应该持有它?要持有多久?”最容易保护、应对泄露和满足合规要求的数据,就是从未收集的数据;请将个人数据视为需要尽量减少的责任。

  • 添加字段时对其进行分类(非个人数据、PII、敏感数据),并据此处理各类数据。找不到数据,就无法保护它,也无法响应删除请求。
  • 仅为明确说明的目的收集数据。“以后可能有用”是潜在的数据泄露范围,不是收集目的。不要在遥测数据中包含 PII(observability-and-instrumentation 技能也从运维角度强调了这一点)。
  • 预先设定保留期限,并真正删除数据。 每个个人数据存储都需要 TTL 和可用的删除路径,包括备份、缓存、搜索索引和分析副本。
  • 支持司法管辖区要求的数据主体权利(GDPR、CCPA 等):导出、更正、删除。设计架构时,应确保能够找到并删除用户数据,而不是让数据不可逆地散布到各个系统中。
  • 收集数据和向第三方共享数据均须经过同意,并且同意过程可供审计。 将 PII 发送给分析、广告或大模型供应商即构成共享;供应商需要签署数据处理协议。将地区设为可配置的策略,而非硬编码的假设。

分类表:数据分类。隐私事件会启动数据泄露通知时限;请使用 debugging-and-error-recovery 技能进行事后复盘。

AI / LLM 功能

调用大模型——聊天机器人、摘要工具、Agent、RAG——会带来新的攻击面;请参照 OWASP 大模型应用十大风险(2025)梳理这些风险:

  • 模型输出是不可信输入(LLM05)。绝不能将其传入 eval、SQL、shell、innerHTML 或文件路径;应谨慎解析,根据架构验证,然后编码。
  • 提示词可能被劫持(LLM01)。上下文中的不可信文本——用户消息、抓取的页面、PDF——都可能包含指令。系统提示词不是安全边界;请在代码中强制执行权限。
  • 不要将机密、其他租户的数据和完整系统提示词放入上下文窗口(LLM02、LLM07);限定工具权限,验证每个工具参数,并确认破坏性操作(LLM06);限制 token 数量、请求速率和递归深度(LLM10);按租户划分 RAG 嵌入,并在索引前验证文档(LLM08)。

模式:LLM 输出处理。

审查清单

签核前,请逐项检查 ../../references/security-checklist.md:其中涵盖身份验证、授权、输入、数据保护与隐私、标头与 CORS、依赖项与供应链、AI/LLM 和错误处理,以及 OWASP 快速参考表。

常见借口

借口实际情况
“这是内部工具,安全不重要”内部工具也会遭到入侵。攻击者会瞄准最薄弱的一环。
“以后再加安全措施”事后补上安全措施要比一开始就纳入设计难 10 倍。现在就加上。
“没人会试图利用这个”自动化扫描器会找到它。依赖隐蔽性并不等于安全。
“框架会处理安全问题”框架提供的是工具,而非保障。你仍然需要正确使用这些工具。
“这只是个原型”原型会进入生产环境。从第一天起就养成安全习惯。
“在这里做威胁建模太过了”花五分钟想想“我会如何攻击它?”,就能避免那些事后无法靠任何控制措施修补的设计缺陷。
“这只是大模型的输出,只是文本”这种“文本”可能是 SQL 语句、脚本标签或 shell 命令。应将其视为任何其他不可信输入。
“审计通过了,所以依赖项是安全的”审计针对的是已知公告。它无法发现新出现的恶意软件包,也无法确保未经审查的安装脚本可安全执行。
“先收集起来,以后可能用得上”不持有的数据就不会遭遇泄露、传票或误删。“可能用得上”属于泄露范围,而非收集目的。
“我们会手动处理删除请求”手动删除会漏掉备份、缓存和分析数据副本。如果架构无法找到用户的数据,就无法满足其请求——请从设计上考虑这一点。
“合规是法务的事,不是我们的事”导出、删除、保留和同意都是架构与代码的一部分。要是你已将个人身份信息散落在十个系统中,法务也无法事后补上这些功能。

红旗问题

  • 用户输入直接传入数据库查询、Shell 命令或 HTML 渲染
  • 删除、移动或覆盖操作的目标来自载荷、配置值或其他进程的命令行,且仅通过路径格式检查加以防护
  • 源代码或提交历史中包含密钥
  • API 端点没有身份验证或授权检查
  • 缺少 CORS 配置,或允许通配符(*)来源
  • 身份验证端点没有速率限制,或在多个实例前使用内存中的限流器
  • 向用户暴露堆栈跟踪或内部错误
  • 依赖项存在已知严重漏洞、同一安装边界存在相互竞争的锁文件、安装过程不可复现,或脚本一律获准运行
  • 服务端获取用户提供的 URL,且没有使用允许列表(SSRF)
  • 将 LLM/模型输出传入查询、DOM、Shell 或 eval
  • 将密钥、PII 或完整系统提示词放入 LLM 上下文窗口
  • 收集个人数据,却未说明用途、保留期限或删除途径
  • 未经同意或未签订数据处理协议,就将 PII 发送给分析、广告或 LLM 服务商
  • “删除我的账户”只切换了一个标记,个人数据却仍留在存储系统和备份中

验证

实施与安全相关的代码后:

  • 原生审计不存在未缓解且可触达的严重/高危问题;CI 保留权威锁文件,并阻止未经审核的依赖脚本
  • 源代码或 git 历史中没有密钥
  • 在系统边界验证所有用户输入
  • 在执行破坏性文件系统操作前,先解析符号链接,再验证允许的根路径、最小深度和所有权
  • 在每个受保护的端点检查身份验证和授权
  • 响应中包含安全标头(使用浏览器 DevTools 检查)
  • 错误响应不会暴露内部详情
  • 身份验证端点已启用速率限制;当多个实例提供流量服务时,使用共享存储支持限流
  • 根据允许列表验证服务端 URL 获取操作(避免 SSRF)
  • 使用前验证并编码 LLM/模型输出(如存在 AI 功能)
  • 对个人数据进行分类,按明确用途尽量减少收集,并设定保留期限
  • 删除和导出请求端到端可用(包括备份、缓存和分析副本)

评论

支持 Markdown