flawopen.com/参考资料/FastAPI SQL 注入
FastAPI 默认会阻止 SQL 注入吗?
Python 与 API 指南
简要回答
Pydantic 会检查值是否符合声明的输入类型;它不会重写 SQL,也不会把 Python 字符串自动变成数据库参数。经过验证的 name: str 仍然是调用者提供的文本。可以把验证想成检查包裹上的标签:它确认收到的值属于哪种类型;参数绑定则像把值封装在 SQL 指令之外。保持 SQL 模板固定,并通过 SQLAlchemy 单独传递值。
FastAPI 中有风险与安全的写法
有风险:插值会改变 SQL 文本
# A string type check does not make input safe inside SQL syntax
@app.get("/users")
def get_users(name: str, db: Session = Depends(get_db)):
query = text(f"SELECT * FROM users WHERE name = '{name}'")
return db.execute(query).fetchall()
安全:SQLAlchemy 单独绑定该值
# :name is a bind parameter; the value is passed separately
@app.get("/users")
def get_users(name: str, db: Session = Depends(get_db)):
query = text("SELECT * FROM users WHERE name = :name")
return db.execute(query, {"name": name}).fetchall()
参数绑定不涵盖什么
绑定参数代表数据值,而不是表名、列名、SQL 运算符或排序方向。如果请求必须选择排序字段,应把选项映射到固定的 SQLAlchemy 列表达式白名单中;切勿将原始请求字符串拼接进 SQL。参数化也不能取代授权:限制调用者可以读取的行,并让数据库账号仅拥有该端点所需的权限。
防护检查清单
- ✓切勿将请求数据插入 SQLAlchemy
text()或原始数据库执行字符串。 - ✓使用具名绑定参数,并单独传递其值,例如
db.execute(query, {"name": name})。 - ✓对于动态表名、列名或排序选项,将输入映射到固定的已知 SQLAlchemy 表达式白名单。
- ✓单独检查行级授权,并仅授予数据库账号端点所需的权限。
- ✓当 SQLAlchemy
select()表达式能清晰表达查询时,优先使用它;使用 ORM 并不会让不安全的原始 SQL 变安全。