一个登录接口能正确返回 200 和 401,只能说明业务结果符合预期,却无法证明数据库调用方式安全。尤其在审查 AI 生成代码时,字符串拼接 SQL 很可能藏在全绿的功能测试之后。要识别这类问题,需要把检查点推进到 cursor.execute 的调用边界。
我做了个很小的对照实验:
两份登录实现,四个功能测试全部通过。
但其中一份代码把用户名和密码直接拼进 SQL,另一份使用参数化查询。
功能测试看到的是一样的结果:
正确密码 -> 200
错误密码 -> 401
functional_total=4/4
测试很绿,SQL 却不一定安全。

容易出问题的实现:
def login(db, username: str, password: str):
sql = (
"SELECT id FROM users "
f"WHERE username = '{username}' AND password = '{password}'"
)
db.execute(sql)
row = db.fetchone()
return ({"ok": True}, 200) if row else ({"ok": False}, 401)
参数化实现:
def login(db, username: str, password: str):
db.execute(
"SELECT id FROM users WHERE username = ? AND password = ?",
(username, password),
)
row = db.fetchone()
return ({"ok": True}, 200) if row else ({"ok": False}, 401)
如果测试只断言“正确密码能登录、错误密码返回 401”,两份实现都能通过。
原因是测试看的路径不同:
功能测试:
请求参数 -> 登录结果
SQL 边界:
请求参数 -> SQL 字符串或参数元组 -> cursor.execute
返回值正确,不能证明实际执行的 SQL 已经参数化。
不要只测登录响应,直接检查 cursor.execute 收到了什么。
def assert_parameterized(db, username, password):
sql = db.sql or ""
assert "?" in sql
assert db.params == (username, password)
assert username not in sql
assert password not in sql
同一组断言,对两种实现的结果不同:
unsafe_login: FAIL
params=None
sql="SELECT id FROM users WHERE username = 'alice' AND password = 'correct-password'"
safe_login: PASS
params=('alice', 'correct-password')
sql='SELECT id FROM users WHERE username = ? AND password = ?'
这时,四个功能测试仍然全绿,但契约测试已经能把不安全实现拦下来。
再用 code-audit-cli 扫两份实现:
unsafe_login: findings=1
severity=high
pattern=sql-concat
line=6
safe_login: findings=0
扫描器给出一行值得人工检查的位置:
sql = (
"SELECT id FROM users "
f"WHERE username = '{username}' AND password = '{password}'"
)
契约测试则保证修复之后,这条路径不会悄悄退回字符串拼接。
两者是不同层级的检查:
完整顺序是:
扫描定位
-> 人工确认
-> 参数化修复
-> 契约测试
-> 功能回归
不要只问:
正确密码能不能登录?
还要问:
登录时,cursor.execute 实际收到的 SQL 和参数是什么?
前者证明功能正常,后者证明 SQL 边界没有失控。
AI 生成的代码也应该这样审。模型写出的登录逻辑可能完全正确,但执行路径仍然可能把输入拼进 SQL。功能测试全绿时,这个差异不会自动暴露。
实验边界:这里用的是可控的假数据库执行器,只验证“参数化查询”这一条契约,不代表覆盖了密码哈希、频率限制、账号枚举、日志和权限等全部安全问题。
公开规则和示例报告:
github.com/yuan1521913…
需要本地扫描器完整源码版:Gumroad
tplink ac路由器可以用其他poe吗(tplink ac路由器支持其他poe吗)
tplink ac路由器可以管理家用路由器吗(tplink ac路由器有管理家用路由器功能吗)
GPT-5.6 Sol 在 Codex 中的 token 消耗为何可能高于 GPT-5.5
Kimi K3 是否具备长程编码和 Agent 任务能力?
Kimi K3 生成编程项目时为什么耗时严重?
tplink路由器wdr6300参数配置(tplink路由器wdr6300参数配置方法)