BrassCoders 在其检查的 15 个 AI 生成的 Python 脚本中,发现了两个脚本包含硬编码密钥,这为那些直接从大语言模型输出中复制粘贴代码的开发者带来了具体的风险。研究结果表明,一个放错位置的密钥或密码,就能让一个有用的代码片段变成跨版本控制和生产环境的凭据泄露事件。

测试揭示了什么

第一个脚本 token_check.py 是根据一个要求提供“签名会话令牌并包含‘可用示例’函数”的提示词生成的。为了使代码能够运行,模型直接在源文件中插入了一个实际的 HMAC 签名密钥。

  • 问题: 密钥存在于代码库中。
  • 风险: 任何拥有仓库读取权限的人都可以看到该密钥,并且任何拉取该文件的部署都会继承该密钥。
  • 后果: 获取密钥的攻击者可以伪造有效的会话令牌,从而绕过身份验证检查。

第二个脚本 email_sender.py 回应了一个关于通过 SMTP 发送电子邮件函数的请求。模型再次提供了一个实际的密码,以便示例能够开箱即用。

  • 问题: 密码以明文字符串的形式出现在函数调用中。
  • 风险: 轮换密码需要更改代码并进行重新部署,且凭据会传播到使用该文件的每个环境中。
  • 后果: 密码可能会从源代码控制、日志或编译包中被窃取,从而使攻击者能够未经授权访问邮件服务器。

为什么 AI 会输出密钥

大语言模型通过补全提示词来生成文本。当用户要求提供“可用的示例”时,模型将其理解为“无需额外设置即可运行的代码”。因此,它会使用看似合理的占位符来填充缺失的值——如 API 密钥、密码、令牌等。除非提示词中明确提到,否则模型并不会意识到密钥管理的最佳实践。

Veracode 最近对 AI 生成代码的一项分析发现,45% 的代码片段至少包含一个 OWASP Top 10 中列出的漏洞,其中凭据泄露占了很大一部分。这一统计数据强调,该问题并非个别现象,而是这些模型训练和提示方式所产生的系统性副产品。

开发者现在可以采取的缓解措施

最简单的防御方法是将任何密钥与代码文件本身保持分离。环境变量是最常用的、与语言无关的方法:

# token_check.py – secure version
import os
import hmac
import hashlib

SECRET_KEY = os.environ["HMAC_SECRET_KEY"]

def sign_token(data: bytes) -> str:
    return hmac.new(SECRET_KEY.encode(), data, hashlib.sha256).hexdigest()
# email_sender.py – secure version
import os
import smtplib

smtp_password = os.environ["SMTP_PASSWORD"]
server = smtplib.SMTP("smtp.example.com", 587)
server.starttls()
server.login("noreply@example.com", smtp_password)

使用 os.environ 可以从运行时环境中提取值,从而使其远离版本控制,并允许在不改动源文件的情况下进行轮换。同样的模式也适用于被排除在提交之外的配置文件、密钥管理服务或容器编排密钥。

其他防护措施

  • 代码审查:标记出匹配常见密钥模式(例如长字母数字序列)的字面字符串。
  • 静态分析工具:针对检测新添加文件中的硬编码凭据进行优化。
  • 提示工程:明确要求模型“对所有密钥使用环境变量”或“省略真实凭据”。
  • 生成后的代码检查 (linting):在将代码复制到项目中之前,运行一个快速脚本来搜索可疑的字面量。

反论:这是否意味着 AI 代码是不安全的?

硬编码密钥的存在并不意味着 AI 生成的代码在普遍意义上是不安全的。在许多情况下,模型生成的逻辑清晰、结构良好,可以加速开发。风险在于,如果开发者在没有进行安全审计的情况下就将输出视为“生产就绪”的代码。请将 AI 视为草拟助手,而不是既定安全实践的替代品。

后续关注点

  • 工具更新:AI 平台正开始引入安全过滤器,用占位符替换密钥。监控这些变化可以减少风险暴露。
  • 政策转变:组织可能会制定 AI 辅助编程的正式指南,将密钥管理检查作为 CI 流水线的一部分。
  • 社区模式:随着开发者分享更多“安全提示词”,针对令牌签名或电子邮件发送等常见任务的最佳实践模板可能会成为默认输出。

核心结论: AI 可以在几秒钟内生成可运行的代码,但除非开发者加强密钥管理规范,否则这种便利性会带来隐藏的代价——泄露的凭据可能会危及整个系统的安全。请将每一段代码片段都视为草稿,剔除其中任何硬编码的密钥,并在提交之前通过环境变量或专门的密钥库进行注入。