AI 写的代码能运行就安全吗?聊聊依赖幻觉与 Python 软件供应链的风险
前言
现在使用 AI 编程助手开发项目已经很普遍。
只需要描述需求,AI 就可以生成代码、编写配置文件,甚至自动安装依赖。
例如,我们让 AI 开发一个 Python 数据处理工具,它可能生成:
pip install pandas requests some-helper-package
看起来只是普通的依赖安装命令。
但有一个问题值得注意:
AI 推荐的第三方包,真的存在吗?它的来源是否可靠?
大模型有时会生成看似合理、实际不存在的包名。如果开发者不加检查就执行安装命令,可能引入新的软件供应链风险。
本文从实际开发角度,介绍依赖幻觉的原理、潜在风险,以及如何建立简单有效的依赖检查流程。
一、什么是依赖幻觉?
大模型生成代码时,可能根据语言习惯和常见命名模式推测依赖名称。
例如,开发者要求:
“帮我实现一个自动整理日志的 Python 工具。”
AI 可能推荐一个名称非常合理的第三方包。
但这个包名未必对应真实、可靠、维护中的开源项目。
这类现象可以理解为依赖幻觉(Package Hallucination)。
需要区分两个概念:
-
依赖幻觉:AI 推荐了不存在或不正确的软件包。
-
恶意依赖:软件包确实存在,但其中可能包含恶意代码。
更值得关注的是,两者可能产生联系。
例如,攻击者发现某些不存在的包名经常被 AI 推荐,便可能尝试注册这些名称,并发布恶意软件包。
这种利用 AI 虚构依赖名称进行软件包投毒的风险,也被称为 Slopsquatting。
当然,并不是所有 AI 推荐的陌生包名都有安全问题,但自动安装未知依赖确实需要谨慎。
二、为什么 pip install 成功不代表安全?
假设 AI 给出了以下命令:
pip install example-ai-helper
这里的包名仅作说明,不代表真实恶意包。
如果命令执行成功,至少说明配置的软件包索引中可以找到相应发行包,并且安装过程完成。
但它无法证明:
-
这个包是项目真正需要的。
-
发布者是可信的。
-
软件包没有恶意行为。
-
项目维护状态良好。
-
依赖版本与当前环境兼容。
尤其是在 AI Agent 可以自行运行终端命令的情况下,自动安装依赖可能扩大风险。
因此,我认为应该把依赖安装视为一个需要验证的操作,而不是把它当成无条件执行的准备步骤。
三、常见的三种风险场景
1. AI 虚构不存在的包名
模型可能生成一个看起来专业的名称。
开发者如果没有验证来源,就可能寻找同名或相似名称的软件包。
此时需要确认真正的官方项目名称,而不是随便选择搜索结果中的第一个。
2. 拼写相似的软件包
例如,开发者原本需要安装某个知名框架,却误输入一个非常相似的名称。
攻击者可能利用字符差异或常见拼写错误,诱导用户安装非预期的软件包。
这类风险通常被称为 Typosquatting(拼写抢注)。
3. 安装脚本执行额外操作
部分软件包在安装或构建过程中可能执行额外脚本。
因此,对于来源不明的依赖,直接在拥有重要凭据、工作文件和网络权限的环境里执行安装命令,可能产生额外风险。
这也是为什么开发者需要重视隔离环境和最小权限原则。
四、实践:安装前先检查依赖
以 Python 项目为例,可以建立一个简单流程。
第一步:确认包名是否正确。
可以使用:
python -m pip index versions requests
这条命令可以查询配置的包索引中可用的版本信息。
但需要注意:查得到版本,不代表已经完成安全审查。
还应该确认项目官方网站、源码仓库和维护者信息。
第二步:检查是否真的需要这个依赖。
如果 Python 标准库已经能够实现功能,通常没有必要额外安装第三方包。
例如,简单的 JSON 解析可以直接使用:
import json
data = json.loads('{"name": "demo"}')
print(data["name"])
这种场景并不需要额外安装 JSON 解析库。
第三步:固定经过验证的依赖版本。
例如:
requests==2.32.3
这里的版本号只是配置格式示例,不代表推荐当前项目一定使用该版本。
固定版本有助于提高构建可重复性,但不能替代漏洞检查。
五、用 Python 编写一个简单的依赖检查器
下面实现一个小工具,检查 requirements.txt 中是否存在未固定版本的依赖。
from pathlib import Path
file = Path("requirements.txt")
if not file.exists():
print("未找到 requirements.txt")
raise SystemExit(1)
for line in file.read_text(
encoding="utf-8"
).splitlines():
package = line.strip()
if not package or package.startswith("#"):
continue
if package.startswith(("-", "git+", "http://", "https://")):
print(f"需要人工核验来源: {package}")
elif "==" not in package:
print(f"建议检查版本约束: {package}")
else:
print(f"发现固定版本声明: {package}")
print("基础检查完成")
假设 requirements.txt 内容为:
requests==2.32.3
pandas
https://example.com/example-package.whl
预期输出大致如下:
发现固定版本声明: requests==2.32.3
建议检查版本约束: pandas
需要人工核验来源: https://example.com/example-package.whl
基础检查完成
这个工具只做基础文本检查,并不是完整的依赖安全扫描器。
它不能判断包是否恶意,也没有完整解析 Python 依赖规范。
但对于初学者来说,它能帮助我们养成一个习惯:
安装之前,先知道自己准备安装什么。
六、AI Agent 自动开发应该增加哪些安全措施?
如果使用 AI Agent 自动开发项目,我建议在工作流中增加以下检查。
| 检查项目 | 目的 |
|---|---|
| 依赖必要性 | 避免安装完全用不到的包 |
| 包名与项目来源 | 防止错误名称及来源混淆 |
| 版本与锁文件 | 提高环境可重复性 |
| 已知漏洞检查 | 识别公开披露的安全问题 |
| 凭据隔离 | 降低安装过程接触敏感数据的风险 |
| 安装结果记录 | 方便排查与后续复现 |
对于安全要求较高的项目,还可以结合依赖漏洞扫描、软件物料清单(SBOM)和包文件哈希验证等机制。
需要强调的是,哈希验证能够帮助确认获得的是预期文件,但不保证该文件本身没有恶意代码。
同样,自动扫描工具也无法保证发现所有未知威胁。
所以,安全检查应当是多层次的。
七、一个容易忽略的优化:减少不必要依赖
有时候,提高安全性并不需要添加更多安全工具,而是减少没有必要的复杂性。
例如,一个简单的网页应用只需要:
-
HTML
-
CSS
-
JavaScript
如果用浏览器原生 API 就能实现全部功能,那么引入复杂框架、构建工具和大量第三方组件可能并不划算。
依赖越多,维护和更新工作通常也越复杂。
但也不能为了追求零依赖而重新实现成熟的安全关键功能。
合理的原则是:
简单功能优先考虑标准能力,复杂功能选择经过验证、维护可靠的依赖。
尤其对于 AI 自动开发工具,提示词里明确写出“禁止安装非必要依赖”,往往能减少安装失败、环境冲突和无效排查。
八、总结
AI 编程助手能够显著提高开发效率,但生成的代码与依赖信息仍然需要验证。
对于开发者来说,不能把“AI 推荐了这个包”当成可信来源,也不能把“安装命令成功了”当成安全证明。
通过本文的分析,可以总结出几个重要原则:
-
第三方包名必须核实,不盲目相信 AI 推荐。
-
安装之前先确认依赖是否真正必要。
-
对未知来源的软件包保持谨慎。
-
固定版本并建立适当的依赖安全检查。
-
在权限受限的环境中执行不可信构建与安装操作。
我认为,随着 AI Agent 开始自动编写代码、安装依赖和构建应用,软件供应链安全也会成为 AI 工程化的重要部分。
AI 可以帮助我们更快地编写代码,但决定哪些代码和依赖值得信任,仍然需要可靠的工程验证。
- 点赞
- 收藏
- 关注作者
评论(0)