mcpField
I
insecure-design

insecure-design

github.com/scholarly360安全2247 次安装29 周前更新
代码仓库

关于 insecure-design

insecure-design 是针对 OWASP A06:2025 的安全审查技能,帮助分析架构层面的安全控制缺失。它通过检查清单、STRIDE 威胁建模和修复优先级,覆盖限流、文件上传、租户隔离等设计问题。

主要功能

  1. 01识别架构层面的安全设计缺陷
  2. 02检查认证端点限流和文件上传
  3. 03审查业务逻辑及租户隔离
  4. 04评估服务端与客户端安全控制
  5. 05使用 STRIDE 指引威胁建模

适用场景

  1. 01审查 FastAPI 或 Flask 应用的安全设计
  2. 02检查登录和支付流程的限流控制
  3. 03评估多租户查询的隔离措施
  4. 04在开发前使用 STRIDE 梳理威胁

安装

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

$npx skills add https://github.com/scholarly360/owasp-top10-web-skills --skill insecure-design

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

附带文件references/cwe-details.mdreferences/threat-modeling.md

详细介绍

OWASP A06:2025 — 不安全设计

此技能的作用

指导检测、分析和修复不安全设计漏洞——这类漏洞属于架构层面的缺陷,表现为缺少安全控制或安全控制在结构上不足。与实现错误不同,仅靠修补代码无法修复不安全设计;必须重新设计流程或添加缺失的控制层。

OWASP 2025 排名: 第 6 位(较 2021 年的第 4 位下降,原因是威胁建模的采用率有所提高)
涵盖的 CWE: 39 | 平均发生率: 1.86%
主要 CWE: CWE-434、CWE-269、CWE-362、CWE-799、CWE-602


核心概念

设计与实现
不安全设计(A06)实现错误(其他类别)
登录流程的架构中从未加入速率限制已实现速率限制器,但配置错误
按设计将文件上传到 Web 根目录上传处理程序缺少扩展名检查
多租户数据库架构中没有租户隔离查询缺少 WHERE 子句
业务逻辑允许负数量缺少服务器端输入验证

设计缺陷需要添加新的控制或重构架构,而不仅仅是修补现有代码。


FastAPI / Flask 测试清单

1. 速率限制(CWE-799)

确认登录、注册、密码重置和高价值交易端点均实施速率限制。

FastAPI — SlowAPI:

from slowapi import Limiter
from slowapi.util import get_remote_address

limiter = Limiter(key_func=get_remote_address)

@app.post("/login")
@limiter.limit("5/minute")
async def login(request: Request, ...): ...

Flask — Flask-Limiter:

from flask_limiter import Limiter
limiter = Limiter(app, key_func=get_remote_address)

@app.route("/login", methods=["POST"])
@limiter.limit("5 per minute")
def login(): ...

审查时需标记的风险信号:

  • 登录、/register、/reset-password、/checkout 路由没有速率限制装饰器
  • RATELIMIT_ENABLED = False,或初始化了限制器,却未将其应用于敏感路由
  • 速率限制过于宽松(例如,为身份验证端点设置 1000/minute)

2. 文件上传安全(CWE-434)

文件上传必须按内容进行验证,而不能只检查扩展名,并且必须存储在Web 根目录之外。

import magic  # python-magic

ALLOWED_MIME = {"image/jpeg", "image/png", "application/pdf"}
MAX_SIZE = 5 * 1024 * 1024  # 5 MB

@app.post("/upload")
async def upload(file: UploadFile):
    content = await file.read(MAX_SIZE + 1)
    if len(content) > MAX_SIZE:
        raise HTTPException(400, "File too large")
    mime = magic.from_buffer(content[:2048], mime=True)
    if mime not in ALLOWED_MIME:
        raise HTTPException(400, "Unsupported file type")
    # Store in /var/app/uploads/ — NOT inside static/ or public/
    safe_path = UPLOAD_DIR / secrets.token_hex(16)
    safe_path.write_bytes(content)

风险信号:

  • 仅依赖 file.content_type 或扩展名(filename.endswith(".jpg"))
  • 将上传文件存储在 static/、public/ 或任何可通过 Web 访问的路径中
  • 没有文件大小上限
  • 未经身份验证即可通过直接 URL 提供上传文件

3. 业务逻辑缺陷

业务逻辑缺陷因应用而异——它们利用有效流程,以非预期的方式达成目的。

常见测试模式:

场景测试
购物车中的负数量使用 quantity: -1 发送 POST 请求,确认订单总额不会变成负数
篡改价格使用 price 字段发送 POST 请求,确认服务器忽略客户端提供的价格
并发购买竞争条件并行请求购买最后一件商品,确认只有一个请求成功
滥用预约系统并行预订同一时段两次
重复使用优惠券在第一笔交易提交前重复使用同一张优惠券

FastAPI 示例 — 安全处理数量:

class OrderItem(BaseModel):
    product_id: int
    quantity: int = Field(..., ge=1, le=100)  # enforced server-side

风险信号:

  • 接受客户端负载中的价格、折扣或角色字段
  • 金融交易没有幂等键或重复检查
  • 未在 Pydantic 或同类机制中使用 ge=1 限定数量或金额

4. 租户隔离(CWE-269)

在多租户应用中,每个数据库查询都必须限定为经过身份验证的租户。

应实施的模式:

# UNSAFE — returns data across all tenants
def get_reports(db: Session):
    return db.query(Report).all()

# SAFE — scoped to current tenant
def get_reports(db: Session, current_user: User):
    return db.query(Report).filter(Report.tenant_id == current_user.tenant_id).all()

风险信号:

  • 任何未按租户或用户进行筛选的 db.query(Model).all()
  • 可从面向用户的端点访问类似管理员的查询
  • 在请求正文中传递租户 ID(必须从 JWT/会话中获取,而不能来自用户输入)

5. 仅在客户端实施服务器端安全控制(CWE-602)

仅在浏览器中实施的安全控制很容易通过直接 API 调用绕过。

风险信号:

  • 只在 JavaScript / 前端中进行授权检查,而未在 API 路由中检查
  • 控制价格、角色或访问级别的隐藏表单字段
  • 基于客户端提供的值设置功能标志(应使用 JWT 声明或服务器会话)
# WRONG — trusting client-supplied role
@app.post("/admin/action")
async def admin_action(role: str = Body(...)):  # never do this
    if role == "admin":
        ...

# CORRECT — derive from authenticated token
@app.post("/admin/action")
async def admin_action(current_user: User = Depends(get_current_user)):
    if current_user.role != "admin":
        raise HTTPException(403)
    ...
6. 凭据 / 账户恢复设计

不安全的恢复流程是设计缺陷,而非实现错误。

危险信号:

  • 基于知识的安全问题(母亲的娘家姓、宠物名字)——可以从社交媒体上猜到
  • 密码重置链接在 15–60 分钟内未过期
  • 重置令牌通过 HTTP 发送或未经过哈希处理便存储
  • 可通过重置流程枚举账户(提示“未找到账户”与静默成功的区别)

安全模式:

# Generate short-lived, single-use, high-entropy token
token = secrets.token_urlsafe(32)
expiry = datetime.utcnow() + timedelta(minutes=30)
# Store hash of token, not the token itself
db_token = PasswordResetToken(
    user_id=user.id,
    token_hash=hashlib.sha256(token.encode()).hexdigest(),
    expires_at=expiry,
    used=False
)

威胁建模指南(STRIDE)

使用 STRIDE,在设计缺陷进入代码之前将其找出:

威胁适用对象FastAPI/Flask 示例
S 欺骗身份验证流程可预测的会话令牌、缺少 MFA
T 篡改传输中 / 存储中的数据签名数据缺少 HMAC、上传文件可写
R 抵赖审计日志未记录财务操作的请求日志
I 信息泄露错误消息、API 文档生产环境中 /docs 公开、500 错误中包含堆栈跟踪
D 拒绝服务速率限制、资源使用未限制请求大小、缺少速率限制器
E 权限提升授权设计角色由客户端提供、缺少租户范围

修复优先级矩阵

发现项严重性修复复杂度
身份验证 / 支付端点未设置速率限制高低 — 添加 SlowAPI/Flask-Limiter
文件上传存储在 Web 根目录中高中 — 移动存储路径,添加服务层
价格 / 角色字段由客户端提供严重低 — 从请求模型中移除字段
数据库查询缺少租户范围严重中 — 审查所有查询
基于知识的安全问题中高 — 重新设计恢复流程
库存 / 预订存在竞态条件中高 — 添加数据库级锁定或幂等性

参考资料

如需深入了解,请参阅:

  • references/cwe-details.md — A06 中全部 39 个 CWE 的完整说明和示例
  • references/threat-modeling.md — FastAPI/Flask 应用的 STRIDE 工作表模板

与设计问题相关的 OWASP 类别:

  • A01 访问控制失效 — 设计默认授予过多访问权限时
  • A07 身份验证失效 — 身份验证流程设计是根本原因时
  • A10 特殊情况处理不当 — 错误恢复设计未能采取失败关闭策略时

评论

支持 Markdown