关于 securability-engineering
securability-engineering 是面向代码生成的安全工程技能,将 FIASSE SSEM 原则作为工程约束,生成代码时附带安全性说明。默认采用单次生成;完整的 PRD 到报告流程需显式启用。
主要功能
- 01按 SSEM 属性约束生成代码
- 02识别并处理信任边界
- 03参考 ASVS 匹配安全要求
- 04审慎选择依赖并加入可观测性
- 05可选端到端生成与审查流程
适用场景
- 01生成函数、服务或 API
- 02为安全敏感功能编写代码
- 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 原则:
- 可保护范式(FIASSE v1.0.4 S2.1)——不存在静态的“安全”状态。生成的代码应具备适应不断演变的威胁的特性,而不只是“当前安全”。
- 韧性地创造计算价值(FIASSE v1.0.4 S2.2)——代码必须能够抵御变化、压力和攻击,同时交付业务价值。安全特性是工程要求,而非事后补救。
- 降低实质影响(FIASSE v1.0.4 S2.3)——优先采用与代码上下文和暴露程度相符的务实控制措施,而非追求理论上的完备。
- 派生完整性(FIASSE v1.0.4 S4.4.1.2)——绝不隐式信任客户端提供的服务器所有状态值。明确地仅从请求中提取预期值。
- 透明性与可观测性(FIASSE v1.0.4 S2.5,S3.2.1.4)——代码必须能通过自身输出被观测:采用有意义的命名,在信任边界进行结构化日志记录,内置审计跟踪和检测能力,而非事后从外部添加。
- 最少意外原则(FIASSE v1.0.4 S2.6)——行为和副作用必须与名称和签名所暗示的内容一致。不得有隐藏的变更、隐式的网络或文件系统副作用,也不得出现意料之外的错误路径。
- 边界控制(FIASSE v1.0.4 S4.3)——灵活性属于内部,控制则应存在于每个信任边界。将边界视为坚固外壳,同时让内部保持足够灵活,以便演进。
- 依赖卫生与管理(FIASSE v1.0.4 S4.5,S4.6)——默认使用与运行时兼容的最新稳定版本。优先选择 CVE/CWE 暴露风险较低、积极维护且发布信号良好的软件包。将每项依赖都视为需要持续维护的关系。
- 规范化输入处理(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,不要仅仅因为原型只见过一种形式,就拒绝符合规范的变体。
步骤(默认模式)
- 识别上下文 — 语言、框架、系统类型、数据敏感性、暴露程度、信任边界、功能类别。
- 将功能需求映射到 ASVS — 使用
data/asvs/README.md和相关的data/asvs/V*.md章节,确定适用于所生成功能的安全要求。 - 应用 SSEM 约束 — 执行上方表格中的属性规则。请参阅
data/fiasse/S3.2.1.md–data/fiasse/S3.2.3.md,了解总括性定义。 - 处理信任边界 — 确定生成的代码会在何处跨越信任边界。应用 FIASSE v1.0.4 S4.3(边界控制)和 S4.4(弹性编码)。
- 审慎选择依赖项(FIASSE v1.0.4 S4.5、S4.6):
- 除非已知存在兼容性约束,否则使用最新稳定版本
- 已知 CVE/CWE 风险较低
- 选择成熟且积极维护的项目
- 尽量减少依赖;标准库足以胜任时,避免使用库
- 固定版本;提供锁文件方面的指导
- 将依赖视为长期关系(Stewardship)
- 实现透明性与可观测性 — 在安全敏感的节点添加结构化日志(FIASSE v1.0.4 S2.5)。为身份验证/授权事件添加审计跟踪钩子。在代码本身中构建可观测性(FIASSE v1.0.4 S3.2.1.4)。
- 生成代码 — 生成满足所有 SSEM 约束的代码。代码应当:
- 使用小巧、单一职责且名称清晰的函数(可分析性)
- 松散耦合,并支持注入依赖(可修改性、可测试性)
- 在信任边界处采取防御措施,在内部保持灵活(完整性、韧性)
- 通过结构化日志和审计跟踪实现可观测性(可观测性、问责性)
- 自检 — 返回之前,对照下方的生成检查清单进行核验。
输出格式
代码本身是主要交付内容。在代码之后,附上简短的可保障性说明:
## 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 安全术语表