AI 写 Python 代码时最容易埋下的一个安全隐患:SQL 注入

AI 生成的 Python 代码经常使用 f-string 拼接 SQL,这种写法可读性强,却容易带来 SQL 注入风险。开发者需要在代码审查、IDE 插件和自动化检测环节建立防线。

当开发者让 AI 编程助手写一个“按 ID 查询用户”的 Python 函数时,得到的结果往往能直接运行,也很易读,但可能已经把 SQL 注入风险写进了生产代码。问题并不在于模型不懂数据库安全,而在于它从大量公开代码里学到的最常见写法,本身就不够安全。

n

看起来能运行的代码,可能正把用户输入当成 SQL 执行

n

文章给出的典型例子非常直观。AI 常见的写法是:

n

def get_user(user_id):n    query = f"SELECT * FROM users WHERE id={user_id}"
    cursor.execute(query)
    return cursor.fetchone()

n

而更安全的参数化查询则是:

n

def get_user(user_id):n    query = "SELECT * FROM users WHERE id=?"
    cursor.execute(query, (user_id,))
    return cursor.fetchone()

n

两者在数据库调用上的差别很小,但安全含义完全不同。参数化查询会把 user_id 当作数据处理;f-string 拼接则会把变量内容嵌入 SQL 字符串,等于让外部输入参与 SQL 语句的构造。如果传入的是 1; DROP TABLE users--,第一种写法就可能执行恶意 SQL。

n

作者称,自己向 Claude、GPT-4 和 Copilot 提出同一个需求:“写一个根据 ID 查询用户的函数”,三者第一次给出的结果都使用了 f-string。

n

为什么 AI 会反复生成这种危险写法

n

原因并不复杂:模型的训练数据里有大量教程、博客和 Stack Overflow 回答,其中的示例代码为了简洁和易读,经常直接拼接 SQL。这类代码通常能获得高票,也更容易被复制和传播。模型学到的不是“最安全”的写法,而是“最常见、最容易被接受”的写法。

n

参数化查询当然也存在于训练数据中,但通常更啰嗦,也不如 f-string 直观。如果提示词里没有明确要求安全上下文,模型倾向于选择更简单的表达方式。

n

作者还提到,这类问题并非只出现在演示代码里。他发现一个拥有 2,693 个 star 的英国政府仓库中,也出现了类似的 SQL 拼接,并且代码已经通过审查并进入生产环境。

n

不止 f-string:四种常见拼接方式都需要警惕

n

素材列举了 AI 生成代码中常见的几种 SQL 注入形式:

n

    n

  • f-string 拼接:cursor.execute(f"SELECT * FROM users WHERE id={user_id}")
  • n

  • 字符串拼接:query = "SELECT * FROM users WHERE id=" + user_id
  • n

  • .format()query = "SELECT * FROM users WHERE id={}".format(user_id)
  • n

  • 百分号格式化:query = "SELECT * FROM users WHERE id=%s" % user_id
  • n

n

这些写法的共同点是把不可信数据直接嵌入 SQL 字符串。只要变量来自用户输入,就可能被利用。

n

文章还给出了两个现实项目中的例子。一处代码是:

n

query = f"SELECT * FROM results WHERE {filter}"

n

filter 来自用户输入,且没有过滤或参数化。另一处匹配库代码则写成:

n

query = f"INSERT INTO matches VALUES ('{name}', '{score}')"
cursor.execute(query)

n

如果 name 被传入 '; DROP TABLE matches; --,数据库就可能被攻击者控制。同一文件的另一行还出现了带两个注入点的查询:

n

query = f"SELECT * FROM {table} WHERE id='{match_id}'"

n

防护并不复杂:参数化查询、审查和自动化检测都要跟上

n

多数 Python 数据库库都支持参数化查询。例如:

n

    n

  • sqlite3:cursor.execute("SELECT * FROM users WHERE id=?", (user_id,))
  • n

  • psycopg2:cursor.execute("SELECT * FROM users WHERE id=%s", (user_id,))
  • n

  • mysql-connector:cursor.execute("SELECT * FROM users WHERE id=%s", (user_id,))
  • n

  • SQLAlchemy:session.execute(text("SELECT * FROM users WHERE id=:id"), {"id": user_id})
  • n

n

如果使用 Django 或 SQLAlchemy 等 ORM,框架通常会自动处理参数化。风险更高的是手写原生 SQL 的场景,而这正是 AI 容易直接使用 f-string 的地方。

n

在代码审查时,可以重点检查 cursor.execute()db.execute()session.execute() 等调用,尤其是参数中包含 f"+.format(% 的情况。如果字符串里又包含用户可控变量,基本就可以判定存在注入风险。作者认为,仅在数据库调用附近搜索 f",就能发现 AI 引入的大部分 SQL 注入问题。

n

自动化检测也是必要补充。素材提到可以使用 AIVerify、Bandit、Semgrep 等工具。其中,AIVerify 可通过 pip install aiverify 安装,并用 aiverify your_project/ --rules sql_injection 检查 SQL 调用中的 f-string 和字符串拼接,同时过滤测试文件和不含用户输入的静态查询。也可以通过 pre-commit 配置在提交前拦截问题。

n

真正的问题是:AI 代码往往只考虑正常路径

n

SQL 注入只是 AI 生成代码风险的其中一种。更大的问题是,模型常常优先保证代码在“正常路径”下可以运行,却没有处理恶意输入、边界条件和攻击场景。对开发者来说,AI 生成的代码不能只靠“看起来对”来判断,尤其是在涉及数据库、权限、外部输入和网络请求的代码中,安全审查必须成为默认流程。

原创文章,作者:点点,如若转载,请注明出处:https://www.dian8dian.com/ai-xie-python-dai-ma-shi-zui-rong-yi-mai-xia-de-yi-ge-an

Like (0)
点点的头像点点
Previous 3小时前
Next 1小时前

相关推荐