首页› 博客› 技术干货
技术干货

Python 里六个最常见的危险写法,和对应改法

2026-10-18·6 分钟阅读·智维工作室

eval、shell=True、SQL 拼接、pickle、yaml.load、硬编码密钥,六条各给一段改前改后。

这六条是我们扫描器里最容易命中的六条(编号对应判据全文那篇)。它们的共同点是:写法很短、看着人畜无害、出事一步到位。每条给「改前 / 改后」。

1. SEC001 / SEC002:eval() 与 exec()

改前:result = eval(input("算式:"))——输入框里可以写任意表达式,包括读文件、发起网络连接。

改后:需要算数学式就用 ast.literal_eval(只认字面量),需要「根据字符串选函数」就用显式字典映射,把可选项钉死在自己写的表里。

2. SEC006:shell=True

改前:subprocess.run("convert " + filename, shell=True)——文件名里带一个分号,后面就跟了一条你的命令。

改后:参数传列表 subprocess.run(["convert", filename], shell=False),并且先把输入文件名做白名单校验。

3. SEC005:SQL 字符串拼接

改前:cur.execute(f"SELECT * FROM t WHERE id = {uid}")。这一条最阴险的地方是:它看起来只是在拼一个变量,而绝大多数人写的时候都认为「这个值是程序自己生成的,不会有事」。

改后:参数化查询 cur.execute("SELECT * FROM t WHERE id = ?", (uid,))。不要用「先转义再拼」这种做法,那是把安全寄托在自己的细心上。

4. SEC003:pickle.load() 读不可信数据

改前:obj = pickle.load(open(sys.argv[1], "rb"))——pickle 在反序列化时可以调用任意对象的 __reduce__,等于把执行权交给文件作者。

改后:换 JSON 或 MessagePack;确实需要对象序列化的,只加载自己签名的数据,别加载下载来的。

5. SEC004:yaml.load() 未指定 Loader

改前:conf = yaml.load(text)——默认 Loader 可以构造任意 Python 对象,和 pickle 是同类问题。

改后:yaml.safe_load(text)。旧代码里如果确实依赖自定义标签,那要用显式的 Loader 子类,而不是退回默认 Loader。

6. SEC007 / SEC008:硬编码密钥与密码

改前:api_key = "sk-..." 写在源码里,跟着仓库一起进了 git 历史。

改后:从环境变量或密钥管理服务读;已经提交过的那一把必须轮换,删掉代码行不算解决了问题——历史里还在,而且任何拿到仓库的人都能读到。

顺带三条容易漏的

  • SEC009:用 assert 做校验。生产环境跑 python -O 时整段 assert 会被优化掉,你的「参数校验」就这么消失了。
  • SMELL001:裸 except:。它会把 KeyboardInterrupt 和真正的 bug 一起吞掉,出问题时你什么日志都看不见。
  • SMELL002:def f(items=[])。默认值在函数定义时创建一次,所有调用共用同一个列表——这种 bug 排查起来很费时间。

想把手上的代码过一遍

两个入口,按预算分:¥9.9 代码体检(单文件 ≤300 行,九条判据 + 人工确认 Top3)和代码审查 + 安全审计(¥299 起)(15 条全跑,报告按严重级分类,每条带文件路径、行号与修复建议)。仓库在公开 GitHub 上也可以直接扫。

报告里每条发现都写成「这里有问题、这样改」,不是「可能有问题」。没命中的判据也会如实写「未命中」,不会为了让报告显得值钱而凑几条。


这一篇讲到的服务(一口价)

全部 12 项服务与价目在服务市场;报价规则与加急、定制档在定价页。交付时限一律逐单确认。

站内其他 6 篇

看着有用?接下来有两件事可以当场做

免费工具在浏览器本地跑,不上传任何数据;¥9.9 体检把判据全文摊在页面上,没命中也不会推你买别的。

¥9.9 代码体检 免费在线工具 发样例,免费评估