mcpField
M
mishandling-exceptional-conditions

mishandling-exceptional-conditions

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

关于 mishandling-exceptional-conditions

面向代码审查与安全测试的 OWASP A10:2025 安全技能,聚焦异常条件处理不当造成的崩溃、信息泄露和可利用状态。提供针对 Python Web 应用的检查清单、扫描方法和修复优先级。

主要功能

  1. 01检查异常处理与全局处理器
  2. 02识别认证逻辑中的故障放行
  3. 03检查错误响应中的敏感信息
  4. 04审查异常路径的资源清理与回滚
  5. 05使用 Bandit 和模式搜索辅助扫描

适用场景

  1. 01审查 FastAPI 或 Flask 应用的异常处理
  2. 02排查错误响应泄露堆栈或数据库信息
  3. 03检查认证失败时是否错误放行
  4. 04发现异常路径中的资源泄漏或事务问题

安装

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

$npx skills add https://github.com/scholarly360/owasp-top10-web-skills --skill mishandling-exceptional-conditions

安装后在 Claude Code 中输入/mishandling-exceptional-conditions确认已加载。

详细介绍

OWASP A10:2025 — 异常情况处理不当

2025 年全新类别,取代 SSRF(已并入 A01)。包含 24 个 CWE,共有 769,581 条记录。针对未能预防、检测和响应异常情况的程序——这可能导致崩溃、意外行为、信息泄露以及可被利用的状态。


核心概念

涵盖范围
弱点风险
错误处理不当未处理的异常会导致应用崩溃或暴露内部信息
发生异常时默认放行(CWE-636)抛出异常时仍通过身份验证/授权检查
错误消息中包含敏感数据(CWE-209)向客户端泄露堆栈跟踪、数据库详情和文件路径
未捕获的异常(CWE-248)缺少全局安全兜底机制 → 返回包含调试输出的 500 错误
异常处理路径中的资源耗尽出错时数据库连接、文件句柄未关闭
状态损坏异常发生时提交了部分事务
NULL 指针/None 解引用(CWE-476)访问属性前未检查 None
缺少默认分支(CWE-754)if/elif 链没有 else;match 没有通配分支
错误恢复过程中的竞态条件清理逻辑本身可能被中断
预防原则
  1. 在错误发生处捕获错误——由能够处理错误的函数捕获,而不是上溯三层才处理。
  2. 默认拒绝——身份验证/授权逻辑抛出异常时,拒绝访问;绝不放行。
  3. 彻底回滚——必须回滚部分数据库事务,绝不能提交。
  4. 将面向用户的消息与技术详情分开——在服务器端记录堆栈跟踪;向客户端返回安全、通用的消息。
  5. 将全局异常处理器作为安全兜底机制——每个应用都需要,但它不能替代局部处理。
  6. 限制速率和配额——防止有人故意触发异常情况(例如资源耗尽)。

FastAPI 测试清单

1. 全局异常处理器
# REQUIRED — catches anything not handled locally
@app.exception_handler(Exception)
async def global_handler(request: Request, exc: Exception):
    logger.error("Unhandled exception", exc_info=exc)
    return JSONResponse(status_code=500, content={"detail": "Internal server error"})

若缺失则标记。 FastAPI 默认的 500 响应在开发模式下可能包含回溯信息。

2. 默认拒绝的身份验证中间件(CWE-636)
# BAD — exception causes pass-through (fail open)
@app.middleware("http")
async def auth_middleware(request: Request, call_next):
    try:
        verify_token(request)
    except Exception:
        pass                       # ← VULNERABILITY
    return await call_next(request)

# GOOD — exception causes denial (fail closed)
@app.middleware("http")
async def auth_middleware(request: Request, call_next):
    try:
        verify_token(request)
    except Exception as e:
        logger.warning("Auth check failed", exc_info=e)
        return JSONResponse(status_code=401, content={"detail": "Unauthorized"})
    return await call_next(request)
3. 自定义 HTTP 错误响应(CWE-756 / CWE-209)
# Register handlers for all common error codes
@app.exception_handler(404)
async def not_found(request, exc):
    return JSONResponse(status_code=404, content={"detail": "Not found"})

@app.exception_handler(422)
async def validation_error(request, exc):
    return JSONResponse(status_code=422, content={"detail": "Invalid input"})

标记任何在响应正文中返回 str(exc)、repr(exc) 或 traceback.format_exc() 的处理器。

4. 异常处理路径中的资源清理
# BAD — connection leaked if query raises
conn = db.connect()
result = conn.execute(query)   # raises → conn never closed
conn.close()

# GOOD — context manager guarantees cleanup
with db.connect() as conn:
    result = conn.execute(query)

检查以下调用是否未放在 with 块或 try/finally 中:db.connect()、open(file)、socket.socket()。

5. SQLAlchemy 事务回滚
# BAD — partial write committed on error
session.add(obj)
risky_operation()        # raises → session still commits elsewhere
session.commit()

# GOOD — rollback on exception
try:
    session.add(obj)
    risky_operation()
    session.commit()
except Exception:
    session.rollback()
    raise

标记:任何未在 except 分支中配对调用 session.rollback() 的 session.commit()。


Flask 测试清单

1. 全局异常处理器
@app.errorhandler(Exception)
def global_error(e):
    app.logger.error("Unhandled exception", exc_info=e)
    return {"error": "Internal server error"}, 500

同时注册特定处理器:

@app.errorhandler(404)
def not_found(e):
    return {"error": "Not found"}, 404

@app.errorhandler(500)
def server_error(e):
    return {"error": "Server error"}, 500
2. Flask 调试模式——同时属于 A02 和 A10 问题

调试模式(debug=True 或 FLASK_DEBUG=1)会启用 Werkzeug 交互式调试器,该调试器:

  • 向浏览器暴露完整的回溯信息。
  • 允许通过调试器控制台执行任意代码。

若在生产配置或环境变量中发现,应立即标记。

3. request.args.get() 静默返回 None
# BAD — returns None silently; downstream code may crash
user_id = request.args.get("user_id")
user = db.query(User).filter_by(id=user_id).first()  # id=None → wrong query

# GOOD — explicit validation
user_id = request.args.get("user_id")
if user_id is None:
    abort(400, description="user_id is required")

FastAPI 的 Pydantic 模型会自动防止此问题;Flask 则需要手动进行保护。

4. 默认拒绝的 before_request 钩子
# BAD — exception in auth check bypasses protection
@app.before_request
def check_auth():
    try:
        verify_session()
    except:
        pass   # ← VULNERABILITY

# GOOD
@app.before_request
def check_auth():
    try:
        verify_session()
    except Exception as e:
        app.logger.warning("Session verify failed", exc_info=e)
        abort(401)

自动扫描方法

静态分析(Bandit)
bandit -r . -t B110,B112   # try-except-pass and try-except-continue
bandit -r . --severity-level medium

此类别的 Bandit 关键测试 ID:

  • B110 — try: ... except: pass(吞掉异常)
  • B112 — try: ... except: continue(在循环中吞掉异常)
模式搜索(grep / ripgrep)
# Fail-open patterns
rg "except.*:\s*(pass|continue|return True)" --type py

# Stack traces leaking to response
rg "traceback\.format_exc\(\)|str\(exc\)|repr\(exc\)" --type py

# Missing context managers
rg "open\(|\.connect\(\)" --type py   # review each hit for 'with'

# Missing rollback
rg "session\.commit\(\)" --type py    # check each for paired rollback
运行时/DAST
  • 主动触发 404、500 和验证错误(FastAPI 中为 422)。
  • 检查 HTTP 响应是否包含:文件路径、堆栈帧、SQL 查询字符串、异常类名称。
  • 通过发送格式错误的 Authorization 标头来探测中间件——确认响应为 401,而不是 200。

关键 CWE(A10:2025)

CWE名称Python 中的表现形式
CWE-209错误消息中的敏感信息JSON 响应中的 str(exc)、调试回溯
CWE-248未捕获异常没有全局处理程序;未处理的 raise 会导致应用崩溃
CWE-636失败时默认放行身份验证检查中的 except: pass
CWE-703未正确处理异常情况会隐藏错误的宽泛 except
CWE-754未正确检查异常情况未检查外部输入是否为 None 或为空
CWE-476空指针解引用访问可能为 None 的对象的属性
CWE-756缺少自定义错误页面使用包含调试信息的框架默认错误页面

修复优先级

  1. 严重: 失败时默认放行的身份验证中间件 / before_request 钩子(CWE-636)——可直接绕过身份验证。
  2. 严重: 在生产环境中启用调试模式(Werkzeug 调试器 = RCE)。
  3. 高: 在 HTTP 响应中泄露堆栈跟踪 / 数据库详细信息(CWE-209)——有助于攻击者侦察。
  4. 高: 缺少全局异常处理程序——未处理的路径会导致应用崩溃,并可能泄露详细信息。
  5. 中: 缺少事务回滚——会破坏数据完整性。
  6. 中: 异常路径中的资源泄漏——遭受攻击时会耗尽连接池。
  7. 低: request.args.get() 静默返回 None——会导致逻辑错误,但无法直接利用。

评论

支持 Markdown