mcpField
S
securability-engineering

securability-engineering

github.com/owasp安全208163 次安装2 周前更新
代码仓库

关于 securability-engineering

securability-engineering 是面向代码生成的安全工程技能,将 FIASSE SSEM 原则作为工程约束,生成代码时附带安全性说明。默认采用单次生成;完整的 PRD 到报告流程需显式启用。

主要功能

  1. 01按 SSEM 属性约束生成代码
  2. 02识别并处理信任边界
  3. 03参考 ASVS 匹配安全要求
  4. 04审慎选择依赖并加入可观测性
  5. 05可选端到端生成与审查流程

适用场景

  1. 01生成函数、服务或 API
  2. 02为安全敏感功能编写代码
  3. 03重构代码以改善安全性和可维护性

安装

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

$npx skills add https://github.com/owasp/secure-agent-playbook --skill securability-engineering

安装后在 Claude Code 中输入/securability-engineering确认已加载。

详细介绍

Securability Engineering — 代码生成封装

此技能通过将 FIASSE v1.0.4 SSEM 原则作为工程约束,增强内置的代码生成功能。它不会执行完整的 SSEM 评分(如需评分,请使用 securability-engineering-review)。

端到端的 PRD 增强 → 生成 → 审查 → 增强 → 报告工作流为可选模式,并非默认模式。请参阅下文的“完整工作流模式”。

参考数据:data/fiasse/(尤其是 S2.1–S2.6 基础原则、S3.2.1–S3.2.3 SSEM 属性,包括 S3.2.1.4 可观测性、S2.5 透明性、S4.3 边界控制、S4.4 弹性编码、S4.4.1 规范化输入处理、S4.6 依赖管理)以及功能级要求所在的 data/asvs/。

何时调用

当用户要求以下操作时,触发此技能:

  • 生成新代码(函数、模块、服务、API、脚本)
  • 搭建项目、功能或组件的框架
  • 为提升安全性或可维护性而重构现有代码
  • 实现安全敏感功能:身份验证、授权、输入处理、文件上传/下载、数据访问、密码学、日志记录、错误处理、会话管理
  • 编写跨越信任边界的代码(任何用户/外部输入、任何存储 I/O、任何网络出站、任何跨服务调用)

留意相关表述:“确保安全”“强化此端点”“我要把它暴露到互联网,可以帮我……”“编写生产版本的……”“可供审计”“达到生产级”。

运行模式

默认模式(单次生成)

直接根据用户请求生成可安全化的代码,并应用 SSEM 约束。大多数调用都采用此模式。输出包括代码和“可安全化说明”区块。

完整工作流模式(可选,端到端)

运行完整的 PRD 增强 → 生成 → 审查 → 增强 → 报告工作流。仅在用户满足以下条件时启用:

  • 传入 --full-loop 标记或参数
  • 表示“端到端可安全化”或“完整可安全化工作流”
  • 明确提及此 play(例如,“遵循可安全化生成 play”)

否则请使用默认模式。对于简单的一次性生成请求,不要自行编造 PRD。

启用完整工作流模式时,请遵循 plays/securable-generation.md。启用默认模式时,仅遵循此文件。

基本约束

在生成任何代码之前,应用以下 FIASSE v1.0.4 原则:

  1. 可保护范式(FIASSE v1.0.4 S2.1)——不存在静态的“安全”状态。生成的代码应具备适应不断演变的威胁的特性,而不只是“当前安全”。
  2. 韧性地创造计算价值(FIASSE v1.0.4 S2.2)——代码必须能够抵御变化、压力和攻击,同时交付业务价值。安全特性是工程要求,而非事后补救。
  3. 降低实质影响(FIASSE v1.0.4 S2.3)——优先采用与代码上下文和暴露程度相符的务实控制措施,而非追求理论上的完备。
  4. 派生完整性(FIASSE v1.0.4 S4.4.1.2)——绝不隐式信任客户端提供的服务器所有状态值。明确地仅从请求中提取预期值。
  5. 透明性与可观测性(FIASSE v1.0.4 S2.5,S3.2.1.4)——代码必须能通过自身输出被观测:采用有意义的命名,在信任边界进行结构化日志记录,内置审计跟踪和检测能力,而非事后从外部添加。
  6. 最少意外原则(FIASSE v1.0.4 S2.6)——行为和副作用必须与名称和签名所暗示的内容一致。不得有隐藏的变更、隐式的网络或文件系统副作用,也不得出现意料之外的错误路径。
  7. 边界控制(FIASSE v1.0.4 S4.3)——灵活性属于内部,控制则应存在于每个信任边界。将边界视为坚固外壳,同时让内部保持足够灵活,以便演进。
  8. 依赖卫生与管理(FIASSE v1.0.4 S4.5,S4.6)——默认使用与运行时兼容的最新稳定版本。优先选择 CVE/CWE 暴露风险较低、积极维护且发布信号良好的软件包。将每项依赖都视为需要持续维护的关系。
  9. 规范化输入处理(FIASSE v1.0.4 S4.4.1)——在每个信任边界执行规范化 → 清理 → 验证。优先使用具体类型和受限枚举。实施请求面最小化(FIASSE v1.0.4 S4.4.1.1)——仅处理预期的特定命名值。

SSEM 属性执行要求

每次代码生成的输出都必须满足以下十项属性。需要了解定义时,请阅读 data/fiasse/ 中的相关章节。

可维护性
属性执行要求
可分析性(FIASSE v1.0.4 S3.2.1.1)方法不超过 30 行代码。圈复杂度 < 10。命名清晰且有描述性。不得包含无用代码。仅在信任边界和复杂逻辑处添加注释,并解释为什么,而非是什么。
可修改性(FIASSE v1.0.4 S3.2.1.2)通过接口 / 依赖注入实现松耦合。不得使用静态可变状态。安全敏感逻辑(身份验证、加密、验证)应集中在专用模块中,不得分散在各调用点。配置应外置。
可测试性(FIASSE v1.0.4 S3.2.1.3)所有公共接口都应可在不修改被测代码的情况下进行测试。依赖应可注入 / 模拟。安全控制应隔离,以便进行专门的测试套件测试。
可观测性(FIASSE v1.0.4 S3.2.1.4)应具备代码级检测能力,不能只依赖外部工具。在信任边界和安全敏感操作处记录结构化日志,并提供足够的上下文(谁 / 做什么 / 在何处 / 何时 / 结果)。通过标准化 API 暴露健康状况和性能指标。失败路径应产生可观测信号;不得静默吞掉异常。界面 / 操作人员反馈应呈现有意义的状态,同时不得泄露内部信息。
可信度
属性执行方式
机密性(FIASSE v1.0.4 S3.2.2.1)在类型级别对敏感数据进行分类。遵循最小权限原则访问数据。代码、日志或错误消息中不得包含机密信息。在适用情况下,对静态和传输中的数据进行加密。尽量减少数据收集。
问责性(FIASSE v1.0.4 S3.2.2.2)使用结构化数据记录安全敏感操作(谁、做了什么、在哪里、何时)。审计跟踪只能追加。记录身份验证事件(登录、登出、失败)和授权决策(允许、拒绝)。日志中不得包含敏感数据。
真实性(FIASSE v1.0.4 S3.2.2.3)使用成熟的身份验证机制。验证令牌/会话完整性(使用固定算法的已签名 JWT、安全 Cookie)。对服务间调用进行相互身份验证。支持不可否认性。
可靠性
属性执行方式
可用性(FIASSE v1.0.4 S3.2.3.1)强制执行资源限制(内存、连接数、文件句柄)。为所有外部调用配置超时。在适当情况下进行速率限制。并发代码采用线程安全设计。非关键故障发生时应优雅降级。
完整性(FIASSE v1.0.4 S3.2.3.2)在每个信任边界验证输入:规范化 → 清理 → 验证(FIASSE v1.0.4 S4.4.1)。跨越信任边界时对输出进行编码。仅使用参数化查询。应用派生完整性(FIASSE v1.0.4 S4.4.1.2)和请求面最小化(FIASSE v1.0.4 S4.4.1.1)。
韧性(FIASSE v1.0.4 S3.2.3.3)防御性编码:预判越界输入。采用具体的异常处理方式,不要使用不加区分的兜底捕获。仅在输入/数据库边界检查空值。并发代码中使用不可变数据结构。采用确定性的资源释放模式(with、using、RAII)。以优雅且安全的方式处理故障:错误消息不得泄露内部信息。

信任边界处理(FIASSE v1.0.4 S4.3)

应用边界控制原则(“乌龟类比”):在信任边界处设置坚硬的外壳,内部保持灵活。

  • 识别信任边界:用户输入、API 调用、数据库查询、文件 I/O、服务间调用。
  • 在每个边界入口点严格处理输入(规范化 → 清理 → 验证)。
  • 记录跨越边界的操作及其验证结果。
  • 保持内部逻辑灵活——严格控制应设在边界处,而非无处不在。
防御性边界解析

边界输入在证明安全之前都应视为恶意输入——而“恶意”也包括出于好意但形式异常的输入,不只是攻击者精心构造的输入。真实协议和格式都存在边缘情况,朴素的解析器往往无法处理。在编写任何边界解析代码之前,请明确考虑以下几类变化:

  • HTTP 标头 — 名称不区分大小写;根据 RFC 规定行为不区分大小写的方案令牌(依照 RFC 6750/7235,Bearer、bearer、BEARER);前导/尾随空白;多个值;逗号分隔的列表;非 ASCII 字符;完全缺失。
  • URL 和查询字符串 — 百分号编码变体、规范化(/a/./b → /a/b)、路径遍历(..)、尾随斜杠、大小写混合的方案、IDN/punycode、重复的查询键。
  • 文件名和路径 — Unicode 规范化形式(NFC/NFD)、不同文件系统上的大小写敏感性差异、嵌入的空字节、保留名称(Windows 上的 CON、PRN)、路径遍历片段。
  • 数字和布尔输入 — 前导零、带符号形式、科学计数法、Infinity/NaN、特定区域设置的分隔符、布尔值变体(“yes”/“true”/“1”/“on”)。
  • 内容类型和 MIME — 名称不区分大小写、可选参数(; charset=utf-8)、声明的类型与嗅探出的类型不一致。
  • JSON 和结构化载荷 — 重复键、深度炸弹、整数溢出、类型混淆("123" 与 123)。
  • 令牌和凭据 — 前导/尾随空白、base64url 与 base64、填充变体、前导 Bearer 是否已被移除。

不要在代码中罗列上述所有情况——请选择与当前边界相关的情况,并有意识地加以处理。对于任何由 RFC 定义的令牌,默认原则是:遵循 RFC,不要仅仅因为原型只见过一种形式,就拒绝符合规范的变体。

步骤(默认模式)

  1. 识别上下文 — 语言、框架、系统类型、数据敏感性、暴露程度、信任边界、功能类别。
  2. 将功能需求映射到 ASVS — 使用 data/asvs/README.md 和相关的 data/asvs/V*.md 章节,确定适用于所生成功能的安全要求。
  3. 应用 SSEM 约束 — 执行上方表格中的属性规则。请参阅 data/fiasse/S3.2.1.md–data/fiasse/S3.2.3.md,了解总括性定义。
  4. 处理信任边界 — 确定生成的代码会在何处跨越信任边界。应用 FIASSE v1.0.4 S4.3(边界控制)和 S4.4(弹性编码)。
  5. 审慎选择依赖项(FIASSE v1.0.4 S4.5、S4.6):
    • 除非已知存在兼容性约束,否则使用最新稳定版本
    • 已知 CVE/CWE 风险较低
    • 选择成熟且积极维护的项目
    • 尽量减少依赖;标准库足以胜任时,避免使用库
    • 固定版本;提供锁文件方面的指导
    • 将依赖视为长期关系(Stewardship)
  6. 实现透明性与可观测性 — 在安全敏感的节点添加结构化日志(FIASSE v1.0.4 S2.5)。为身份验证/授权事件添加审计跟踪钩子。在代码本身中构建可观测性(FIASSE v1.0.4 S3.2.1.4)。
  7. 生成代码 — 生成满足所有 SSEM 约束的代码。代码应当:
    • 使用小巧、单一职责且名称清晰的函数(可分析性)
    • 松散耦合,并支持注入依赖(可修改性、可测试性)
    • 在信任边界处采取防御措施,在内部保持灵活(完整性、韧性)
    • 通过结构化日志和审计跟踪实现可观测性(可观测性、问责性)
  8. 自检 — 返回之前,对照下方的生成检查清单进行核验。

输出格式

代码本身是主要交付内容。在代码之后,附上简短的可保障性说明:

## Securability Notes

- **SSEM attributes enforced**: [the 2–4 that actually shape this code, named briefly]
- **ASVS references**: [V-chapter.section IDs that apply]
- **Trust boundaries**: [where input is canonicalized/validated]
- **Dependencies**: [package@version — only when something non-trivial was introduced]
- **Trade-offs**: [decisions a reviewer needs to know — e.g., "in-process rate limit; switch to shared store for multi-instance"]

略过没有实质内容的要点。对于没有跨越边界的小型编辑,一句话就够了。此部分旨在加快审查,而不是面面俱到。

实例示例(Mini)

用户请求:“编写一个 Python FastAPI 端点,让已登录用户按 ID 获取自己的某个订单。”

不严谨的默认写法(应避免):

@app.get("/orders/{order_id}")
def get_order(order_id: str, current_user=Depends(get_user)):
    order = db.query("SELECT * FROM orders WHERE id = '" + order_id + "'")
    return order

问题:SQL 注入(字符串拼接)、缺少所有权检查(任何用户都能读取任何订单 — IDOR)、返回内容范围过宽,泄露字段、没有日志、没有输入验证、没有错误处理。

可安全化的版本:

from fastapi import APIRouter, Depends, HTTPException
from pydantic import BaseModel
from uuid import UUID
import structlog

router = APIRouter()
log = structlog.get_logger()

class OrderView(BaseModel):
    id: UUID
    placed_at: str
    status: str
    total_cents: int

@router.get("/orders/{order_id}", response_model=OrderView)
def get_order(
    order_id: UUID,                                  # canonicalized: must parse as UUID or 422
    current_user = Depends(get_authenticated_user),  # auth at the boundary
    orders = Depends(get_orders_repo),               # injectable for tests
):
    order = orders.find_owned_by(order_id, current_user.id)  # ownership enforced server-side
    if order is None:
        log.info("order_lookup.denied",
                 user_id=current_user.id, order_id=str(order_id), reason="not_found_or_not_owned")
        raise HTTPException(status_code=404, detail="Order not found")
    log.info("order_lookup.granted",
             user_id=current_user.id, order_id=str(order_id))
    return OrderView.model_validate(order)

改动内容及原因:

  • order_id: UUID 在边界处规范化输入(完整性,FIASSE v1.0.4 S4.4.1)。
  • find_owned_by(order_id, user_id) 在服务端强制执行所有权检查 — current_user.id 是服务端拥有的状态,绝不信任客户端传来的值(派生完整性,FIASSE v1.0.4 S4.4.1.2)。
  • OrderView 投影将响应限制为预期字段(机密性;请求面最小化,FIASSE v1.0.4 S4.4.1.1)。
  • 在边界处理结果处记录结构化日志,为审计流水线提供所需信息(问责性、可观测性 — FIASSE v1.0.4 S2.5、S3.2.1.4)。
  • Depends(get_orders_repo) 可注入,因此测试无需连接真实数据库即可运行(可测试性、可修改性)。
  • 对“未找到”和“无权访问”均返回 404 — 避免向非所有者透露订单是否存在(机密性)。

反模式标签参考(撰写时应避免)

这些是在生成内容时不应输出的模式。每一行都将不良写法与其违反的原则配对,因此当你发现自己正要写出其中一种时,就能知道问题所在,以及正确写法是什么。

应避免输出的模式违反的原则 / 属性标签正确写法
使用字符串拼接构造 SQL / shell / 格式字符串,并接触用户输入完整性 — 边界输入处理(FIASSE v1.0.4 S4.4.1、S4.3)"信任边界输入处理"参数化查询 / subprocess 参数列表 / 使用占位符进行格式化
在授权决策中信任 req.body.user_id、X-Tenant-ID、JWT 声明完整性 — 派生完整性(FIASSE v1.0.4 S4.4.1.2)"派生完整性违规"从已认证会话中查找用户 / 租户;绝不信任客户端声称的信息
将 req.body / **request.json 直接展开到 ORM 更新中完整性 — 请求面最小化(FIASSE v1.0.4 S4.4.1.1)"批量赋值"明确的命名字段允许列表 → 类型化 DTO → 映射更新
使用 os.path.join(base, user_input) / 模板路径拼接完整性 — 边界规范化(FIASSE v1.0.4 S4.4.1)"路径规范化缺口"解析绝对路径,断言其位于 base 下,否则拒绝
使用默认算法或不设置 aud / iss 的 jwt.decode(token)真实性(FIASSE v1.0.4 S3.2.2.3)"令牌验证规范不足"jwt.decode(token, key, algorithms=['RS256'], audience=..., issuer=...)
使用 print(...) / console.log(...) / fmt.Println(...) 记录安全事件可问责性 + 可观测性(FIASSE v1.0.4 S2.5、S3.2.1.4)"非结构化审计跟踪"使用结构化日志记录器,输出 {event, actor, target, outcome, request_id}
try: ... except: pass / 静默失败路径可观测性(FIASSE v1.0.4 S3.2.1.4);弹性(FIASSE v1.0.4 S3.2.3.3)"静默失败"使用具体的异常类型;记录带上下文的日志;重新抛出异常或返回类型化错误
裸 except: / catch (e) 并返回原始异常文本弹性;机密性(FIASSE v1.0.4 S3.2.3.3、S3.2.2.1)"缺少具体的异常处理"使用命名异常类型、通用的公开消息,以及包含详情的内部日志
在模块级创建全局对象(数据库连接、应用、配置)可修改性 + 可测试性(FIASSE v1.0.4 S3.2.1.2、S3.2.1.3)"导入时副作用"工厂函数 / DI 容器 / 通过 fixture 注入依赖
未设置大小上限就调用 request.body.read() / ioutil.ReadAll(r.Body)可用性 + 弹性(FIASSE v1.0.4 S3.2.3.1、S3.2.3.3)"无界资源消耗"使用有界读取器;显式设置 max_size;超限时返回 413
password == request.password / 非恒定时间的机密比较真实性;机密性"时序侧信道比较"使用 hmac.compare_digest / 语言中的等效实现
硬编码机密、连接字符串或 API 密钥机密性(FIASSE v1.0.4 S3.2.2.1)"代码中的机密"使用环境变量 / 机密管理器;通过注入的配置传递
在信任边界表面使用 any / interface{} / dynamic可分析性 + 完整性"信任边界类型擦除"使用具体的类型化 DTO / Pydantic 模型 / 类型化结构体
使用 setTimeout / time.sleep 代替实际的速率限制可用性(FIASSE v1.0.4 S3.2.3.1)"基于休眠的限流"使用真正的速率限制器(令牌桶 / 固定窗口),并以操作者为键
发起外部调用时不设置超时(requests.get(url)、http.Client{})可用性 + 弹性"无界外部调用"显式设置 timeout= / 使用配置了超时的 Client
默认记录完整的请求正文 / 响应正文 / 令牌机密性 + 可问责性(审计中的敏感数据)"审计日志中的个人身份信息"仅使用 ID 记录结构化事件;对正文和凭据字段进行脱敏

如果你发现自己正要输出其中一种模式,请停下来重写。

生成检查清单

可维护性:

  • 函数 ≤ 30 行,圈复杂度 < 10
  • 不使用静态可变状态;通过注入方式提供依赖项
  • 集中处理安全逻辑,避免重复
  • 无需修改被测代码即可进行测试
  • 代码内置可观测性:在边界处记录包含充分上下文的结构化日志;失败路径可观测;检测机制不应仅依赖外部工具

可信度:

  • 代码、日志或错误输出中不包含机密、个人身份信息或令牌
  • 使用结构化数据记录身份验证/授权事件
  • 使用成熟的机制进行身份验证
  • 数据访问遵循最小权限原则

ASVS 功能要求:

  • 已确定该功能相关的 ASVS 章节
  • 已将适用的 ASVS 要求转化为实现约束
  • 生成的代码满足要求的意图,而不仅仅是理想路径

可靠性:

  • 在每个信任边界验证输入(规范化 → 清理 → 验证)
  • 应用派生完整性(状态由服务端维护,而非由客户端提供)
  • 应用请求面最小化(只提取预期值)
  • 使用针对性的异常处理和有意义的消息;不使用空泛的兜底捕获
  • 采用资源限制、超时和释放模式

依赖项卫生:

  • 外部库确有必要(不添加可避免的依赖项)
  • 所选版本为兼容的最新稳定版本
  • 所选软件包已知的 CVE/CWE 风险较低
  • 已检查活跃维护的迹象
  • 固定版本;附上锁文件指导

透明度:

  • 命名有意义;代码可自我说明
  • 在信任边界和安全事件处记录结构化日志
  • 为安全敏感操作添加审计跟踪钩子

避免反模式:

  • 生成的代码中不存在反模式标签参考表中的任何一项

输出格式:

  • 代码后包含 Securability Notes 区块(精简——仅列出实质要点)
  • 备注指出实际影响代码设计的 2–4 个 SSEM 属性(而非全部十项)
  • 权衡部分指出审查者可能需要重新审视的内容

如有疑问

  • 优先选择简洁、明确且附有清晰 Securability Notes 区块的代码,而不是假设隐含其中的大型综合方案。
  • 优先在权衡部分明确指出缺失的要求,而不是悄然引入默认行为。
  • 除非新依赖项能实质性提升正确性,否则优先使用标准库/框架原语。
  • 优先使用命名的异常类型和显式错误响应,而不是通用的 try/except。

FIASSE 参考资料

  • FIASSE Framework v1.0.4
  • data/asvs/README.md — ASVS 章节索引
  • data/asvs/V*.md — 按章节划分的 ASVS 5.0 功能要求
  • data/fiasse/S2.1.md–S2.6.md — 基本原则(包括透明度 S2.5 和最小意外原则 S2.6)
  • data/fiasse/S3.2.1.md–S3.2.3.md — SSEM 属性类别(可维护性、可信度、可靠性)
  • data/fiasse/S3.2.1.4.md — 可观测性
  • data/fiasse/S4.3.md — 边界控制原则
  • data/fiasse/S4.4.md — 弹性编码
  • data/fiasse/S4.4.1.md — 规范化输入处理
  • data/fiasse/S4.4.1.1.md — 请求面最小化原则
  • data/fiasse/S4.4.1.2.md — 派生完整性原则
  • data/fiasse/S4.5.md / S4.6.md — 依赖项管理与维护
  • Full Loop Mode 运行手册:plays/securable-generation.md
  • ISO/IEC 25010:2011 — 软件质量模型
  • RFC 4949 — Internet 安全术语表

评论

支持 Markdown