关于 injection
injection 是面向 Python 项目的注入漏洞安全测试技能,供审查代码和测试 Web 应用的开发者使用。它汇总 SQL 注入、XSS、SSTI、命令注入和输入验证检查,并给出 Bandit 与 OWASP ZAP 扫描流程。
主要功能
- 01SQL、XSS、SSTI 与命令注入检查
- 02输入验证风险检查
- 03安全与易受攻击代码模式示例
- 04Bandit 静态扫描流程
- 05OWASP ZAP 动态扫描流程
适用场景
- 01审查 Python 项目中的原始 SQL 和命令调用
- 02检查模板渲染及用户输入处理风险
- 03在 CI/CD 中运行注入漏洞扫描
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ scholarly360/ owasp-top10-web-skills --skill injection安装后在 Claude Code 中输入/injection确认已加载。
附带文件references/payloads.md
详细介绍
OWASP A05:2025 — 注入:Python 安全测试技能
概述
当不可信用户输入到达解释器(例如数据库、OS shell、模板引擎或浏览器),并作为命令或查询的一部分执行时,就会发生注入。尽管注入在 2025 年的排名从第 3 位降到了第 5 位,但它仍是 CVE 数量最多的 OWASP 类别:62,445 个,其中仅 XSS 就有 30,000 多个。
此技能涵盖的注入类型:
- SQL 注入(SQLi)—— CWE-89
- 跨站脚本(XSS)—— CWE-79
- 服务端模板注入(SSTI)—— CWE-94
- OS 命令注入—— CWE-78 / CWE-77
- ORM 注入
- 输入验证失败—— CWE-20
- LLM 提示词注入(相关类别,OWASP 2025 中有提及)
检测清单
1. SQL 注入(CWE-89)
需要标记的高风险模式:
# ❌ VULNERABLE — f-string in raw SQL
db.execute(f"SELECT * FROM users WHERE email = '{email}'")
# ❌ VULNERABLE — .format() in SQLAlchemy text()
db.execute(text("SELECT * FROM users WHERE id = {}".format(user_id)))
# ❌ VULNERABLE — string concatenation in ORM raw query
User.query.filter(text("name = '" + name + "'"))
需要强制执行的安全模式:
# ✅ SAFE — bound parameters in SQLAlchemy text()
db.execute(text("SELECT * FROM users WHERE email = :email"), {"email": email})
# ✅ SAFE — ORM method (avoids interpreter entirely)
User.query.filter_by(email=email).first()
# ✅ SAFE — FastAPI with Pydantic + SQLAlchemy ORM
async def get_user(user_id: int, db: Session = Depends(get_db)):
return db.query(User).filter(User.id == user_id).first()
测试方法:
- 在代码库中搜索
text(、execute(、raw(、cursor.execute(加字符串插值的用法 - 运行 Bandit:
bandit -r . -t B608(硬编码 SQL 表达式) - 注入有效载荷:
' OR '1'='1、'; DROP TABLE users; --、1 UNION SELECT null,null-- - 对所有接受字符串参数的端点使用 OWASP ZAP 执行主动扫描
2. XSS — 跨站脚本(CWE-79)
需要标记的高风险模式:
# ❌ VULNERABLE — Jinja2 auto-escaping disabled globally
app = Flask(__name__)
# Missing: app.jinja_env.autoescape = True (it IS on by default for .html — verify!)
# ❌ VULNERABLE — |safe filter on untrusted data
# In template: {{ user_comment | safe }}
# ❌ VULNERABLE — render_template_string with user input
@app.route("/greet")
def greet():
name = request.args.get("name")
return render_template_string(f"<h1>Hello {name}</h1>") # Also SSTI risk!
需要强制执行的安全模式:
# ✅ SAFE — auto-escaping on (Flask default for .html/.htm/.xml/.xhtml)
# Verify: app.jinja_env.autoescape is True for the template extension
# ✅ SAFE — explicit escaping when rendering HTML from user input
from markupsafe import escape
safe_name = escape(request.args.get("name", ""))
# ✅ SAFE — Content-Security-Policy header
@app.after_request
def set_csp(response):
response.headers["Content-Security-Policy"] = "default-src 'self'"
return response
测试方法:
- 在模板中搜索
| safe——每次使用都需要人工审查 - 确认 Jinja2 环境中的所有模板类型都设置了
autoescape=True - 注入:
<script>alert(1)</script>、"><img src=x onerror=alert(1)> - 检查响应中的 Content-Security-Policy 和 X-XSS-Protection 标头
3. SSTI — 服务端模板注入(CWE-94)
对于使用 Jinja2 的 Flask 应用,这是最严重的注入风险。将用户输入作为模板字符串渲染,可能导致完整的 Python 表达式执行。
需要标记的高风险模式:
# ❌ VULNERABLE — user input in template constructor
from jinja2 import Template
user_template = request.args.get("template")
return Template(user_template).render()
# ❌ VULNERABLE — render_template_string with user data in template itself
return render_template_string(user_provided_content)
# ❌ VULNERABLE — format string from user input
msg_template = user_input # "Hello {user.name}"
msg_template.format(user=current_user) # exposes user object attributes
需要强制执行的安全模式:
# ✅ SAFE — only render static template files; pass user input as context variables
return render_template("greet.html", name=user_name) # name is escaped, not executed
# ✅ SAFE — if dynamic templates needed, use sandboxed environment
from jinja2.sandbox import SandboxedEnvironment
env = SandboxedEnvironment()
env.from_string(template_str).render(data=safe_data)
测试方法:
- 搜索
render_template_string(、Template(,以及源代码包含用户数据的.format( - 注入 SSTI 探测载荷:
{{7*7}}(预期结果为49)、{{config}}、{{''.__class__.__mro__}} - 权限提升载荷:
{{''.__class__.__mro__[1].__subclasses__()}},用于枚举类
4. OS 命令注入(CWE-78、CWE-77)
需要标记的高风险模式:
# ❌ VULNERABLE — shell=True with user input
import subprocess
filename = request.args.get("file")
subprocess.call(f"cat {filename}", shell=True)
# ❌ VULNERABLE — os.system with any user-controlled string
os.system("convert " + user_filename + " output.jpg")
# ❌ VULNERABLE — os.popen
result = os.popen(f"ls {directory}").read()
需要强制执行的安全模式:
# ✅ SAFE — shell=False (default) with argument list
subprocess.run(["cat", filename], shell=False, capture_output=True)
# ✅ SAFE — validate and sanitize before passing to any subprocess
import re
if not re.match(r'^[a-zA-Z0-9._-]+$', filename):
raise ValueError("Invalid filename")
subprocess.run(["convert", filename, "output.jpg"])
# ✅ SAFE — avoid shell entirely when possible (use Python libraries)
# Instead of: os.system("rm " + path)
import pathlib
pathlib.Path(path).unlink()
测试方法:
- Bandit:
bandit -r . -t B602,B603,B605,B606,B607(subprocess 和 shell 问题) - 搜索:
os.system(、os.popen(、shell=True - 注入:
; cat /etc/passwd、| id、&& whoami、`id`
5. 输入验证失败(CWE-20)
FastAPI(Pydantic — 推荐):
# ✅ SAFE — Pydantic enforces types, lengths, patterns at parse time
from pydantic import BaseModel, Field, constr
class UserCreate(BaseModel):
username: constr(min_length=3, max_length=50, pattern=r'^[a-zA-Z0-9_]+$')
age: int = Field(ge=0, le=150)
email: str = Field(max_length=255)
@app.post("/users")
async def create_user(user: UserCreate):
... # Input already validated
# ❌ VULNERABLE — bypassing Pydantic by reading raw request body
body = await request.body()
data = json.loads(body) # No validation!
Flask(需要手动验证):
# ✅ SAFE — explicit validation with WTForms or marshmallow
from marshmallow import Schema, fields, validate
class UserSchema(Schema):
username = fields.Str(required=True, validate=validate.Length(min=3, max=50))
age = fields.Int(validate=validate.Range(min=0, max=150))
# ❌ VULNERABLE — using request.args directly without validation
name = request.args.get("name") # Could be anything
db.execute(text(f"SELECT * FROM users WHERE name = '{name}'"))
自动化扫描流程
SAST — Bandit
pip install bandit
bandit -r ./app -f json -o bandit_report.json
# Injection-specific test IDs:
# B608 — Hardcoded SQL expressions
# B602 — subprocess with shell=True
# B603 — subprocess without shell_injection check
# B605 — os.system call
# B606 — os.popen call
# B607 — partial executable path
# B701 — Jinja2 autoescape=False
DAST — OWASP ZAP
docker run -t owasp/zap2docker-stable zap-baseline.py \
-t http://localhost:8000 \
-r zap_report.html
# For active injection testing (more thorough but more aggressive):
docker run -t owasp/zap2docker-stable zap-full-scan.py \
-t http://localhost:8000
组合流程(CI/CD):
# .github/workflows/security.yml
- name: Run Bandit SAST
run: bandit -r ./app -t B608,B602,B603,B605,B606,B701 --exit-zero -f json -o bandit.json
- name: Upload results
uses: github/codeql-action/upload-sarif@v2
with:
sarif_file: bandit.json
重要 CWE 参考
| CWE | 名称 | 主要风险 |
|---|---|---|
| CWE-89 | SQL 注入 | 数据库数据泄露/篡改 |
| CWE-79 | XSS | 会话劫持、网络钓鱼 |
| CWE-78 | OS 命令注入 | RCE、服务器接管 |
| CWE-77 | 命令注入 | 通过 eval/exec 实现 RCE |
| CWE-94 | 代码注入 / SSTI | 完整的 Python 执行 |
| CWE-20 | 输入验证不当 | 通往其他所有注入类型的入口 |
LLM 提示词注入(2025 年新增)
2025 年的 OWASP 列表将 LLM 提示词注入列为相关类别。对于使用 AI API 的应用:
# ❌ VULNERABLE — user input directly in system prompt
system_prompt = f"You are a helpful assistant. Context: {user_provided_context}"
# ✅ SAFER — separate user content from system instructions
messages = [
{"role": "system", "content": STATIC_SYSTEM_PROMPT},
{"role": "user", "content": user_input} # Never injected into system role
]
# Additional mitigations:
# - Input/output filtering for prompt injection patterns
# - Least-privilege tool use (don't give LLM access to sensitive ops)
# - Structured outputs (JSON schema) to limit instruction-following surface
快速参考:按攻击类型划分的严重程度
| 攻击 | 严重程度 | 利用难度 | 典型影响 |
|---|---|---|---|
| SSTI | 严重 | 中等 | RCE |
| OS 命令注入 | 严重 | 中等 | RCE |
| SQL 注入 | 高 | 简单–中等 | 数据泄露、绕过身份验证 |
| XSS(存储型) | 高 | 简单 | 会话劫持 |
| XSS(反射型) | 中 | 中等 | 网络钓鱼、凭据窃取 |
| ORM 注入 | 高 | 中等 | 数据暴露 |
| 提示词注入 | 中–高 | 简单 | 绕过逻辑、数据外泄 |
参考资料
- OWASP A05:2025 注入 — 官方指南
- Bandit 文档 — Python SAST 工具
- Jinja2 Sandbox — 安全的模板渲染
- 完整的注入载荷测试库请参阅
references/payloads.md
评论
支持 Markdown