- SAST
- 应用安全
【免费下载链接】bandit
Bandit is a tool designed to find common security issues in Python code.
导读
本文以 Bandit 安全扫描器中的B505(weak_cryptographic_key)检测插件为核心,深入讲解它如何识别 Python 代码中不安全的 RSA、DSA 与 EC 密钥长度,涵盖阈值划分逻辑、severity/confidence 分级、可配置参数、检测边界以及基于 examples/weak_cryptographic_key_sizes.py 的完整实战验证。读完本文,你将掌握 B505 的触发条件、如何通过 Bandit 配置调优阈值,以及如何在自己的代码中规避弱密钥告警。
B505 是什么:检测弱密钥长度的安全插件
B505 是 Bandit 内置的测试插件,用于检查 Python 代码中是否使用了过短的加密密钥。随着算力提升,较短的密钥长度已可被暴力破解或因数分解攻击攻破,因此该插件以 NIST 推荐标准为依据设置阈值:RSA 与 DSA 算法推荐密钥长度 2048 及以上,1024 及以下视为可破解;椭圆曲线(EC)密钥推荐 224 及以上,160 及以下视为可破解。凡是低于这些下限的密钥使用,都会被 B505 标记为安全问题。
该插件的完整源码位于 bandit/plugins/weak_cryptographic_key.py,属于 B5xx(密码学)插件组,其插件 ID 分组可参见 doc/source/plugins/index.rst 中的 ID 对照表。插件最早在 Bandit0.14.0版本引入,并在1.7.3版本补充了 CWE 信息(关联 CWE-326,即“加密强度不足”)。
检测的核心对象:三类受支持的密钥生成调用
B505 并不是对所有密钥相关代码都做检查,而是精确匹配以下两个主流加密库的密钥生成函数调用:
| 库/模块 | 匹配的函数(限定名 qual name) | 对应算法 |
|---|---|---|
| cryptography | cryptography.hazmat.primitives.asymmetric.dsa.generate_private_key | DSA |
| cryptography | cryptography.hazmat.primitives.asymmetric.rsa.generate_private_key | RSA |
| cryptography | cryptography.hazmat.primitives.asymmetric.ec.generate_private_key | EC |
| PyCrypto | Crypto.PublicKey.DSA.generate | DSA |
| PyCrypto | Crypto.PublicKey.RSA.generate | RSA |
| PyCryptodome | Cryptodome.PublicKey.DSA.generate | DSA |
| PyCryptodome | Cryptodome.PublicKey.RSA.generate | RSA |
从源码结构看,这一匹配逻辑分别由_weak_crypto_key_size_cryptography_io与_weak_crypto_key_size_pycrypto两个内部函数完成:前者通过context.call_function_name_qual匹配 cryptography 库的调用,后者匹配 PyCrypto/PyCryptodome 的调用。EC 曲线生成目前只覆盖 cryptography 库(PyCrypto/PyCryptodome 的 EC 生成函数不在匹配范围内)。
阈值与分级:High / Medium 两档告警机制
默认阈值配置
gen_config函数为 B505 提供了 6 个可调参数及其默认值(源码见 bandit/plugins/weak_cryptographic_key.py):
| 配置项 | 默认值 | 含义 |
|---|---|---|
weak_key_size_dsa_high | 1024 | DSA 密钥长度低于此值时告警 High |
weak_key_size_dsa_medium | 2048 | DSA 密钥长度低于此值时告警 Medium |
weak_key_size_rsa_high | 1024 | RSA 密钥长度低于此值时告警 High |
weak_key_size_rsa_medium | 2048 | RSA 密钥长度低于此值时告警 Medium |
weak_key_size_ec_high | 160 | EC 密钥长度低于此值时告警 High |
weak_key_size_ec_medium | 224 | EC 密钥长度低于此值时告警 Medium |
分级判定逻辑
_classify_key_size函数实现了分级判定(源码见 bandit/plugins/weak_cryptographic_key.py):
- 当密钥长度低于 high 阈值(如 RSA/DSA 小于 1024、EC 小于 160)时,报告High 严重级别、High 置信度;
- 当密钥长度低于 medium 阈值但高于等于 high 阈值(如 RSA/DSA 在 1024~2048 之间、EC 在 160~224 之间)时,报告Medium 严重级别、High 置信度;
- 告警文本统一为
"<算法> key sizes below <阈值> bits are considered breakable.",并附带 CWE-326(issue.Cwe.INADEQUATE_ENCRYPTION_STRENGTH)。
例如在 examples/weak_cryptographic_key_sizes.py 第 36 行中,dsa.generate_private_key(512, backends.default_backend())使用了 512 位的 DSA 密钥,会触发如下输出:
>> Issue: DSA key sizes below 1024 bits are considered breakable. Severity: High Confidence: High CWE: CWE-326 (https://cwe.mitre.org/data/definitions/326.html) Location: examples/weak_cryptographic_key_sizes.py:36关键实现细节:EC 曲线的长度推导
对于 cryptography 库的 EC 密钥,B505 并不是直接读取数值型的 key_size 参数,而是通过curve参数(可以是关键字参数curve=或位置参数)解析出曲线对象名,再查表得到对应位长(源码见 bandit/plugins/weak_cryptographic_key.py)。内置曲线映射表包含:
| 曲线名 | 位长 |
|---|---|
| SECT571K1 / SECT571R1 | 571 / 570 |
| SECP521R1 | 521 |
| BrainpoolP512R1 | 512 |
| SECT409K1 / SECT409R1 | 409 |
| BrainpoolP384R1 / SECP384R1 | 384 |
| SECT283K1 / SECT283R1 | 283 |
| BrainpoolP256R1 / SECP256K1 / SECP256R1 | 256 |
| SECT233K1 / SECT233R1 | 233 |
| SECP224R1 | 224 |
| SECP192R1 | 192 |
| SECT163K1 / SECT163R2 | 163 |
如果传入的曲线不在映射表中(例如动态生成的曲线对象),则保守地默认按 224 位处理,再交由阈值逻辑判定。
参数提取策略:关键字参数、位置参数与默认值回退
B505 在提取密钥大小时采用了“优先关键字参数、其次位置参数、最后默认值”的回退策略:
- cryptography 库的 DSA/RSA:优先读取
key_size=关键字参数,其次读取位置参数(DSA 在第 0 位、RSA 在第 1 位,因为 RSA 的第 0 位是public_exponent),两者都缺失时默认按 2048 位处理(源码见 bandit/plugins/weak_cryptographic_key.py)。这也意味着:调用时若完全省略 key_size 参数,B505 不会告警——它假定调用方使用了库的默认安全长度。 - PyCrypto/PyCryptodome:优先读取
bits=关键字参数,其次读取位置参数(第 0 位),缺失时同样默认 2048 位(源码见 bandit/plugins/weak_cryptographic_key.py)。 - EC 曲线:
curve=关键字参数优先于位置参数。
检测边界:B505 的已知局限
从源码与示例文件中可以明确以下检测边界,使用时应心中有数:
- 变量化的密钥长度不检测:
_classify_key_size中当key_size为字符串(即由变量传入,无法静态求值)时直接返回,不做告警。例如 examples/weak_cryptographic_key_sizes.py 第 64-66 行rsa.generate_private_key(public_exponent=65537, key_size=some_key_size, ...)不会被标记。这体现了静态分析工具的本质局限——无法追踪跨函数或运行时的变量值。 - 动态曲线对象无法解析:当曲线通过表达式(如
curves[self.curve]'create')传入时,映射表查不到该对象,B505 会保守地按默认 224 位处理(见 examples/weak_cryptographic_key_sizes.py),此时告警结论可能不准。 - 不覆盖 PyCrypto/PyCryptodome 的 EC 生成:仅 cryptography 库的 EC 曲线被纳入映射表。
实战验证:用示例文件跑一遍 B505
运行方式
假设仓库已在本地 clone,且 Bandit 已安装,可直接在仓库根目录对示例文件运行:
bandit -f txt examples/weak_cryptographic_key_sizes.pyexamples/weak_cryptographic_key_sizes.py精心构造了三类场景:正确用法(2048 位及以上、SECP384R1 等安全曲线)、弱密钥用法(1024 位 RSA/DSA、SECT163R2 等)、以及变量化/动态化场景。
期望输出
按照 tests/functional/test_functional.py 中的功能测试断言,对该示例文件运行 B505 应得到:16 个告警,全部为 High 置信度;其中 8 个 High 严重级别、8 个 Medium 严重级别。具体对应关系为:
- 8 个 High:
dsa.generate_private_key(key_size=1024)、dsa.generate_private_key(512, ...)、rsa.generate_private_key(key_size=1024)、rsa.generate_private_key(3, 512, ...)、两个ec.generate_private_key(curve=ec.SECT163R2)变体、pycrypto_*与pycryptodomex_*的 1024 位调用各 1 个; - 8 个 Medium:密钥长度介于 high 与 medium 阈值之间(如示例中 1024 位 DSA/RSA 实际触发 Medium 档位的场景),EC 曲线落在 160~224 区间(如 SECT163R2 的 163 位落在 High 档,而 192 位 SECP192R1 等落在 Medium 档)时的告警。
说明:功能测试统计的是对示例文件的整体断言(8 High + 8 Medium,16 个告警,置信度全为 High),具体告警行可结合
-v详细输出对照示例文件逐行核对。
如需只看 B505 的告警,可配合-t B505过滤测试 ID:
bandit -t B505 -f txt examples/weak_cryptographic_key_sizes.py自定义阈值:通过 Bandit 配置文件调优
配置机制说明
Bandit 1.0 之后配置文件为可选。插件如需配置项,必须实现模块级的gen_config函数(B505 即如此),该函数以插件名为参数,返回默认配置字典(机制说明见 doc/source/plugins/index.rst 的 "Config Generation" 一节)。当不指定配置文件、或配置文件缺少该插件段落时,gen_config的默认值即生效。
Bandit 还提供了bandit-config-generator工具,可自动为所有已发现的插件生成配置模板块(doc/source/config.rst 的 "Generating a Config" 一节),生成的模板中即可看到 B505 的 6 个配置项,按需删改即可。
自定义配置示例
若企业安全基线要求 RSA/DSA 不低于 3072 位、EC 不低于 256 位,可创建如下bandit.yaml:
plugins: weak_cryptographic_key: weak_key_size_dsa_high: 2048 weak_key_size_dsa_medium: 3072 weak_key_size_rsa_high: 2048 weak_key_size_rsa_medium: 3072 weak_key_size_ec_high: 224 weak_key_size_ec_medium: 256运行时通过-c指定配置文件:
bandit -c bandit.yaml -r .配置文件中的插件配置段落名需与测试方法名(即weak_cryptographic_key)一致,Bandit 才会读取并覆盖gen_config默认值。
如何规避 B505 告警(正确的修复姿势)
修复弱密钥告警,核心是使用达到安全标准的密钥长度与曲线:
from cryptography.hazmat import backends from cryptography.hazmat.primitives.asymmetric import dsa, ec, rsa # 正确:RSA 2048 位及以上 rsa.generate_private_key(public_exponent=65537, key_size=2048, backend=backends.default_backend()) # 正确:DSA 2048 位及以上 dsa.generate_private_key(key_size=2048, backend=backends.default_backend()) # 正确:EC 使用安全曲线(如 SECP384R1,384 位) ec.generate_private_key(curve=ec.SECP384R1, backend=backends.default_backend())关于# nosec注释:B505 只在确认密钥长度不安全时告警,因此不推荐用# nosec直接压制此类告警;正确做法是提升密钥长度本身。若确因特殊兼容性原因无法立即升级,应在注释中说明原因并接受人工复核,例如:
rsa.generate_private_key(public_exponent=65537, key_size=1024, # nosec B505 - 兼容遗留系统,待迁移后升级 backend=backends.default_backend())总结
B505 通过匹配 cryptography、PyCrypto、PyCryptodome 三套库的密钥生成调用,以 RSA/DSA(high=1024、medium=2048)与 EC(high=160、medium=224)的默认双档阈值输出 High/Medium 告警,并支持通过gen_config暴露的 6 个配置项完全自定义安全基线。其“关键字参数 → 位置参数 → 默认值”的参数提取策略、EC 曲线映射表查长方案,以及“变量化密钥长度不检测、动态曲线对象保守默认”的边界处理,共同构成了这一插件的完整行为画像。理解这些实现细节,能帮助你在真实项目中准确解读 B505 的每一份报告,并把安全基线固化到 Bandit 配置中。
相关资源
- 插件源码:bandit/plugins/weak_cryptographic_key.py
- 测试示例:examples/weak_cryptographic_key_sizes.py
- 功能测试断言:tests/functional/test_functional.py
- 插件机制与配置生成说明:doc/source/plugins/index.rst
- Bandit 配置与
bandit-config-generator用法:doc/source/config.rst
- SAST
- 应用安全
【免费下载链接】bandit
Bandit is a tool designed to find common security issues in Python code.
相关推荐
5步掌握React SaaS主题定制:从零打造个性化企业级界面
5步掌握React SaaS主题定制:从零打造个性化企业级界面 想要快速构建专业SaaS应用却苦于界面设计?React SaaS Template为你提供了完美
Bandit 插件 B507 深度解析:检测 Paramiko SSH 主机密钥验证缺失(ssh_no_host_key_verification)
Bandit 插件 B507 深度解析:检测 Paramiko SSH 主机密钥验证缺失(ssh_no_host_key_verification) 导读 B5
SAST应用安全小爱音箱接入大语言模型:从Docker部署到自定义语音助手的完整教程
小爱音箱接入大语言模型:从Docker部署到自定义语音助手的完整教程 周五晚上,你对客厅的小爱音箱说"小爱同学,给我讲个睡前故事",等回来一句"抱歉,我没听懂"
SAST应用安全
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考