1. 项目概述:为什么Python开发者需要Bandit?

如果你写过Python,大概率遇到过这种情况:项目上线前,安全团队扫描出一堆“中危”、“高危”漏洞,其中不少是“硬编码密码”、“SQL注入风险”、“不安全的反序列化”。你看着这些报告一头雾水,心想“我这代码跑得好好的,怎么就高危了?” 更头疼的是,这些问题往往在开发后期甚至部署前才被发现,修复成本极高。这就是典型的“安全意识滞后”问题——我们太专注于功能实现,而忽略了代码本身可能引入的安全隐患。

Bandit的出现,就是为了把安全这件事“左移”,让它成为开发流程中自然而然的一环。它不是那种部署在服务器上、扫描运行时漏洞的“黑盒”工具,而是一个静态代码分析工具,专门针对Python。你可以把它理解为一个极其严格、且只关心安全问题的代码审查员。在你提交代码、甚至在你敲下 git commit 之前,它就能告诉你:“嘿,兄弟,你这里用 eval() 处理用户输入,是想给黑客开个后门吗?” 或者“这个 assert 语句用在生产环境,万一被禁用,你的权限检查就形同虚设了。”

我最初接触Bandit,是因为一个线上事故。一个内部工具因为使用了 yaml.load() 而不是 yaml.safe_load() 来解析外部上传的配置文件,导致了远程代码执行。问题代码已经存在了半年,直到被恶意利用才发现。事后我们复盘,如果早在代码入库时就有个工具能发现这个风险点,事故完全可以避免。自那以后,Bandit就成了我们团队CI/CD流水线里的强制关卡。

所以,这篇指南不是教你如何通过一个叫“Bandit”的CTF游戏(虽然那个游戏也叫Bandit,且是学习Linux安全的好工具),也不是讲强化学习里的“上下文赌博机”。我们聚焦的是这个能实实在在提升你Python代码安全水位线的静态分析工具。无论你是刚入门的新手,还是在维护大型遗产代码库的老鸟,掌握Bandit的这几个实用技巧,都能让你写出更健壮、更让人放心的代码。

2. Bandit工具的核心机制与工作原理

2.1 静态分析:不运行代码的“X光机”

要理解Bandit,首先得明白什么是静态应用程序安全测试。想象一下,你有一份建筑的设计蓝图。SAST工具就像一位经验丰富的安全审计师,他不需要等到大楼盖起来、住进去人之后再去检查消防通道是否被堵,而是直接对着蓝图分析:“这个承重墙的标注厚度不够”,“电路走向图里,强电和弱电管道交叉没有屏蔽保护”。Bandit做的就是同样的事情——它不执行你的Python代码,而是直接分析源代码的抽象语法树。

AST是代码的结构化表示。当Bandit扫描 config = yaml.load(user_input) 这行代码时,它看到的不是一个简单的字符串,而是一个结构化的树节点:“这是一个赋值语句,右边是一个函数调用,函数名是 load ,来自模块 yaml ,参数是变量 user_input 。” Bandit内置的检测器会匹配这个模式,然后触发一条规则:“B506: yaml.load 函数允许执行任意代码,应使用 yaml.safe_load 。”

这种基于AST的分析方式,决定了Bandit的优势和局限。优势在于,它速度快,可以在代码开发的任意阶段介入,甚至能发现那些尚未被触发的潜在执行路径上的漏洞。局限在于,它无法感知运行时的数据流和状态。比如,它无法判断一个从数据库读出的字符串是否真的来自用户输入,也无法知道一个 if 条件在真实运行中是否总为真。因此,Bandit的报告是“发现疑点”,而非“确认漏洞”,最终判断需要开发者结合上下文进行。

2.2 插件化架构:如何定制你的安全规则

Bandit的强大之处在于其插件化的架构。它本身是一个框架,核心功能是遍历AST,而具体的“找茬”工作,则由一个个独立的“插件”来完成。这些插件在Bandit的语境里就是测试用例。

每个测试用例都是一个独立的Python文件,通常包含以下几个关键部分:

  1. 测试ID和严重性 :如 B105 (硬编码密码字面量), HIGH
  2. 匹配模式 :定义在AST中要寻找的代码模式。
  3. 触发函数 :当模式匹配时执行的函数,用于生成报告。

这种架构带来了极高的灵活性。假设你们公司内部有一个自研的、不安全的加密函数 my_company.unsafe_encrypt() ,你想禁止团队使用。你完全可以自己编写一个测试插件。这个插件会扫描所有函数调用,如果发现调用了 my_company.unsafe_encrypt ,就抛出一个自定义的中危告警。然后,你只需要把这个插件文件放到Bandit的插件目录,或者通过命令行指定,整个团队的安全扫描标准就统一升级了。

注意 :自定义插件需要一定的Python AST知识。对于大多数团队,优先利用好Bandit内置的、经过社区千锤百炼的近百个测试用例,已经能覆盖80%以上的常见安全问题。自定义插件更适合针对内部框架、特定业务逻辑的深度定制。

2.3 结果报告:理解置信度与严重性

Bandit的输出不是简单的一刀切。它会对每个发现的问题进行评估,给出两个关键维度: 严重性 置信度

  • 严重性 :分为 LOW MEDIUM HIGH 。这代表了如果这个漏洞被利用,可能造成的危害程度。例如,一个 DEBUG 级别的日志里打印了密码可能是 LOW ,而一个SQL注入点则是 HIGH
  • 置信度 :分为 LOW MEDIUM HIGH 。这代表了Bandit对这个发现的确信程度。由于静态分析的局限性,有些告警可能是误报。置信度 HIGH 意味着代码模式非常明确,几乎可以确定是问题;置信度 LOW 则意味着需要人工重点审查上下文。

一个典型的输出如下:

>> Issue: [B105:hardcoded_password_string] Possible hardcoded password: 'secret123'
   Severity: Medium   Confidence: Medium
   Location: ./myapp/auth.py:42
   More Info: https://bandit.readthedocs.io/en/latest/plugins/b105_hardcoded_password_string.html
41     def connect_db():
42         conn = psycopg2.connect(host='localhost', dbname='test', user='admin', password='secret123')
43         return conn

解读:在 auth.py 文件的第42行,发现一个可能硬编码的密码 ‘secret123’ 。严重性是中危,置信度也是中危。报告还给出了详细说明的链接。

理解这两个维度,能帮你高效处理扫描结果。一个常见的策略是:在CI/CD中,将 HIGH 严重性且 HIGH 置信度的问题设为阻塞项,必须修复才能合并代码;对于 LOW 置信度的告警,可以设置为仅输出报告,提醒开发者注意,但不阻塞流程。

3. 7个提升代码安全意识的实战技巧

3.1 技巧一:将Bandit集成到开发工作流中

工具再好,如果只在想起来的时候手动跑一下,效果也有限。真正的价值在于“自动化”和“前置”。我的建议是分三步走,将Bandit无缝嵌入你的日常开发。

第一步:本地预提交钩子 在代码提交到本地仓库之前进行检查,这是最早、成本最低的反馈环节。使用 pre-commit 框架可以轻松实现。

  1. 在项目根目录创建 .pre-commit-config.yaml 文件。
  2. 添加Bandit钩子配置:
    repos:
      - repo: https://github.com/PyCQA/bandit
        rev: 1.7.8 # 使用固定的版本号
        hooks:
          - id: bandit
            args: ['-iii', '-ll', '--exclude', './tests,./venv'] # 忽略测试目录和虚拟环境
    
  3. 运行 pre-commit install 安装钩子。 此后,每次执行 git commit ,Bandit都会自动扫描暂存区的文件。如果有问题,提交会被中止,你必须先修复或明确跳过(不推荐)。

第二步:持续集成流水线 在代码推送到远程仓库(如GitHub, GitLab)后,在CI流水线中运行Bandit作为必检步骤。以GitHub Actions为例:

name: Security Scan
on: [push, pull_request]
jobs:
  bandit:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: '3.10'
      - name: Install dependencies
        run: pip install bandit
      - name: Run Bandit
        run: bandit -r . -f json -o bandit-report.json --skip B101,B404
      - name: Upload report
        uses: actions/upload-artifact@v4
        if: always()
        with:
          name: bandit-report
          path: bandit-report.json

这个工作流会在每次推送或拉取请求时运行,生成JSON格式的报告并保存为制品。你可以配置分支保护规则,要求Bandit检查必须通过才能合并。

第三步:IDE实时提示 对于追求极致效率的开发者,可以在VS Code或PyCharm中配置Bandit作为linter或外部工具。虽然不如专门的安全插件智能,但可以设置快捷键,对当前文件运行Bandit并快速查看结果。这适合在编写代码过程中进行即时自查。

实操心得 :不要试图一步到位。可以先从CI流水线开始,让团队适应“安全门禁”的存在。然后推广预提交钩子,减少在CI阶段才失败的挫败感。IDE集成则面向那些对代码质量有极高要求的个人或小团队。

3.2 技巧二:编写安全的配置与密码管理代码

硬编码密码是Bandit最常抓到的“低级错误”之一,但危害极大。Bandit的 B105 规则会扫描代码中所有看起来像密码的字符串字面量。

反面教材与修复方案:

# 反面教材:硬编码密码
DB_PASSWORD = 'MySuperSecretPassword123!'  # Bandit: B105 触发
def get_connection():
    return psycopg2.connect(host='localhost', password=DB_PASSWORD)

# 修复方案1:使用环境变量
import os
DB_PASSWORD = os.environ.get('DB_PASSWORD')  # 从环境变量读取
if not DB_PASSWORD:
    raise ValueError("DB_PASSWORD environment variable not set")

# 修复方案2:使用配置文件(配合环境变量)
# config.ini 或 config.yaml 文件本身不提交到仓库,通过环境变量指定路径
# 或使用python-dotenv加载.env文件(.env文件也在.gitignore中)

进阶:安全地处理配置文件 YAML和JSON配置也常是风险点。

# 高危:使用yaml.load
import yaml
with open('config.yaml') as f:
    data = yaml.load(f)  # Bandit: B506 触发!可能执行任意代码。

# 安全:使用yaml.safe_load
with open('config.yaml') as f:
    data = yaml.safe_load(f)  # 只加载基本的Python对象,安全。

# JSON文件通常使用json.load,它是安全的。但要警惕用json.loads加载来自网络的未经验证字符串。

管理实践 :在项目中建立一个明确的规范:所有密钥、密码、API Token等敏感信息,一律不得以明文形式出现在代码仓库中。统一通过环境变量或安全的密钥管理服务传递。 .env.example 文件可以提交,用于说明需要哪些环境变量,但真实的 .env 文件必须列入 .gitignore

3.3 技巧三:彻底避免注入类漏洞

注入漏洞是Web应用的“头号杀手”,Bandit能有效识别SQL注入和命令注入的潜在模式。

SQL注入防护:

# 高危:字符串拼接SQL
def get_user(username):
    query = "SELECT * FROM users WHERE name = '%s'" % username  # Bandit: B608 触发(疑似SQL注入)
    cursor.execute(query)

# 高危:使用.format
def get_user(username):
    query = "SELECT * FROM users WHERE name = '{}'".format(username) # 同样高危
    cursor.execute(query)

# 安全:使用参数化查询
def get_user(username):
    query = "SELECT * FROM users WHERE name = %s"  # 使用占位符
    cursor.execute(query, (username,))  # 参数作为元组传入

Bandit的 B608 规则会检测使用字符串格式化操作( % .format() , f-string)来构建SQL语句的模式。但请注意,Bandit是静态分析,它无法知道 execute 的第二参数是否被正确使用。因此,养成 无条件使用参数化查询 的习惯是唯一准则。

命令注入防护:

import subprocess
import shlex

# 高危:直接拼接用户输入
user_input = input("Enter filename to delete: ")
subprocess.run(f"rm /tmp/{user_input}", shell=True)  # Bandit: B602 触发!shell注入风险极高。

# 较安全:使用参数列表,避免shell=True
user_input = "myfile.txt"  # 假设来自用户
# 仍然危险,如果user_input是“myfile.txt; rm -rf /”
subprocess.run(["rm", f"/tmp/{user_input}"])  # Bandit可能仍会警告,因为参数部分包含变量。

# 最佳实践:严格校验输入,并使用shlex.quote(但更推荐避免执行shell命令)
# 更好的方式是使用Python内置的文件操作函数,而非调用shell。
import os
safe_filename = validate_and_sanitize_filename(user_input) # 自定义的严格校验函数
os.remove(f"/tmp/{safe_filename}")

对于命令执行,最根本的建议是: 尽可能避免使用 subprocess 调用系统命令,尤其是 shell=True 。如果必须使用,确保参数列表化,并对所有来自外部的输入进行严格的“白名单”校验。

3.4 技巧四:安全地处理文件与路径操作

文件操作不当会导致路径遍历攻击,让攻击者读取或写入系统上的任意文件。

路径遍历漏洞:

import os

# 高危:直接拼接用户控制的路径部分
def read_file(username):
    user_dir = f"/home/data/{username}"  # 如果username是“../../etc/passwd”
    with open(user_dir + '/profile.txt', 'r') as f:  # Bandit: B108 可能触发(硬编码路径是另一个问题)
        return f.read()

# 安全:使用os.path.abspath和os.path.commonprefix进行规范化与校验
def safe_read_file(base_dir, username):
    # 1. 规范化输入路径
    requested_path = os.path.join(base_dir, username, 'profile.txt')
    normalized_path = os.path.abspath(os.path.normpath(requested_path))
    
    # 2. 确保规范化后的路径仍在允许的基目录下
    base_dir_abs = os.path.abspath(base_dir)
    if not normalized_path.startswith(base_dir_abs + os.sep):
        raise ValueError("Attempted path traversal attack detected.")
    
    # 3. 安全检查通过,执行操作
    with open(normalized_path, 'r') as f:
        return f.read()

Bandit的 B108 规则主要针对硬编码的 /tmp 目录使用,但路径安全的原则是通用的。核心思路是: 将用户输入视为不可信的,将其拼接为完整路径后,必须与一个安全的“根目录”进行比对,确保最终路径没有“逃逸”出去。

临时文件安全:

# 不够安全
import tempfile
temp_file = tempfile.mktemp()  # Bandit: B306 触发。mktemp存在竞态条件风险。
with open(temp_file, 'w') as f:
    f.write('data')

# 安全:使用tempfile.NamedTemporaryFile或mkstemp
with tempfile.NamedTemporaryFile(mode='w', delete=False) as f:
    temp_file_name = f.name  # 安全生成的唯一临时文件路径
    f.write('data')
# 记得后续清理 temp_file_name

tempfile.mktemp() 会在不创建文件的情况下生成一个唯一的文件名,这中间存在一个时间窗口,攻击者可能抢先创建同名文件,导致你的程序向攻击者控制的文件写入数据。 NamedTemporaryFile mkstemp 在生成名字的同时会创建文件,消除了这个竞态条件。

3.5 技巧五:警惕不安全的反序列化与代码执行

Python的灵活性强,但也带来了危险。 pickle eval() exec() 等功能非常强大,但一旦处理不受信任的数据,就是打开了潘多拉魔盒。

不安全的反序列化:

import pickle
import yaml

# 高危:反序列化来自网络或不可信来源的数据
data = receive_from_network()  # 假设来自外部
obj = pickle.loads(data)  # Bandit: B301 触发!可能执行任意代码。
obj = yaml.load(data)     # Bandit: B506 触发!同上。

# 安全方案
# 1. 根本避免:如果可能,使用JSON等安全的数据交换格式。
import json
obj = json.loads(data)  # JSON反序列化是安全的(仅生成基础对象)。

# 2. 如果必须用pickle,确保数据来源绝对可信(如,同一系统、同一信任域内)。
# 并且考虑使用hmac签名来验证数据完整性和来源。

危险的动态代码执行:

# 绝对禁止的行为
user_code = input("Enter a calculation: ")  # 例如输入“__import__('os').system('rm -rf /')”
result = eval(user_code)  # Bandit: B307 触发!灾难性后果。
exec("import os; os.system('ls')")  # Bandit: B102 触发!

# 安全替代方案
# 如果需要计算数学表达式,使用ast.literal_eval(只能求值字面量)或专门的库如`numexpr`、`simpleeval`。
import ast
safe_expr = "1 + 2 * 3"
result = ast.literal_eval(safe_expr)  # 安全,但功能受限。

# 如果需要更复杂的“公式”计算,使用限制执行环境的沙箱(但Python沙箱很难做到绝对安全,需极其谨慎)。

重要警告 :在生产代码中,除非你有极其特殊、可控的场景,并且完全清楚后果,否则 永远不要使用 eval() exec() pickle.load(s) yaml.load() 来处理任何来自用户、网络、配置文件等外部不可信源的数据 。这是红线。

3.6 技巧六:利用 .banditrc 文件进行精细化配置

随着项目规模扩大,你可能会发现Bandit的某些规则对你的项目不适用,或者你想忽略某些特定的文件或目录。每次都通过冗长的命令行参数来配置非常麻烦。这时,就需要使用Bandit的配置文件。

创建配置文件 : 在项目根目录创建一个名为 .banditrc bandit.yaml 的文件。

常用配置示例

# .banditrc (YAML格式)
skips: ['B101', 'B404']  # 跳过“assert语句”和“导入子进程”的检查(根据项目需要)
exclude_dirs: ['tests', 'docs', 'build', '*.venv']  # 排除扫描的目录/模式
tests: ['B201', 'B301']  # 只运行指定的测试ID(白名单模式,较少用)
# 或者用 `aggregate_by` 选项来按严重性聚合输出

# 针对特定文件或目录的覆盖规则
overrides:
  - paths: ['legacy_code/*.py']  # 对遗留代码目录放宽要求
    skips: ['B601', 'B602', 'B608']  # 跳过所有注入类检查(慎用!)
  - paths: ['app/secrets_manager.py']
    skips: ['B105']  # 这个文件专门处理密码,允许出现密码字符串模式

命令行使用配置 :运行 bandit -c .banditrc -r . ,Bandit会自动读取配置文件。

配置策略建议

  1. 谨慎使用 skips :跳过某个测试(如 B101 关于 assert )意味着你接受了该风险。最好在团队内达成共识,并记录在案。
  2. 善用 exclude_dirs :排除第三方库目录、构建输出目录、测试目录等,可以大幅提升扫描速度和报告清晰度。
  3. 区分环境 :可以考虑为不同环境准备不同的配置文件。例如,在CI严格流水线中使用一个严格的配置,在开发者本地预提交钩子中使用一个略宽松的配置(如跳过某些低置信度告警),以平衡安全与开发效率。

3.7 技巧七:解读报告与处理误报

运行Bandit后,面对可能出现的几十条甚至上百条告警,如何高效处理是关键。不要被数量吓倒,大部分告警可以通过模式化的方法快速解决。

处理流程:

  1. 按严重性排序 :优先处理 HIGH 严重性的问题。
  2. 审查上下文 :点击报告中的“More Info”链接,查看官方对该问题的详细描述和示例。然后回到你的代码,判断这是真正的漏洞,还是误报。
  3. 分类处理
    • 确认为漏洞 :立即修复。这是提升代码安全性的直接价值。
    • 确认为误报(假阳性) :如果Bandit判断错了,你有几种方式处理: a. 代码注解压制 :在特定行代码上方添加 # nosec 注释。这是最精确的方式,但需附上理由。
      # 这个eval用于动态调用内部已知的安全函数,数据源可信。
      result = eval(f"internal_safe_func_{name}")  # nosec B307
      
      b. 配置文件跳过 :如果某类误报在整个项目中普遍存在(例如,你们就是需要大量使用 assert 做调试),可以在 .banditrc skips 中全局跳过该测试( B101 )。 c. 重构代码 :有时,让代码的意图更明确可以避免误报。例如,将字符串拼接SQL重构为参数化查询,不仅消除了漏洞,也消除了告警。

常见误报场景与处理:

  • B101: assert_used :在测试文件或调试脚本中使用 assert 是合理的。可以在测试目录的 .banditrc 覆盖规则中跳过,或在CI中排除测试目录扫描。
  • B404: import_subprocess :导入 subprocess 模块本身不危险,危险的是错误使用。这个检查争议较大,很多项目选择跳过 B404 ,而依赖 B602 , B603 , B607 等具体的使用规则来捕获真正的问题。
  • B105: hardcoded_password_string :可能误报一些看起来像密码但实际不是的字符串(如某个普通的配置项叫 secret_key 但并非密码)。可以通过 # nosec 或重构变量名来消除。

建立团队处理规范 :在团队内约定,任何使用 # nosec 压制告警的行为,必须在代码审查中说明理由。并且定期(如每季度)回顾被压制的告警,看是否有条件通过重构代码来彻底消除它们,而不是一味压制。

4. 超越Bandit:构建纵深防御体系

Bandit是一个优秀的SAST工具,但代码安全不是单点工具就能解决的。它应该是一个多层次、纵深防御体系中的一环。

1. 与其它工具链集成:

  • 代码风格与质量 :在预提交钩子或CI中,将Bandit与 black (格式化)、 isort (导入排序)、 flake8 pylint (代码风格与质量)一起运行。确保代码在安全的同时,也保持整洁和可维护。
  • 依赖项安全扫描 :使用 pip-audit safety 或GitHub的Dependabot、GitLab的Dependency Scanning来检查项目依赖的第三方库是否存在已知漏洞。这解决了Bandit无法覆盖的“供应链安全”问题。
  • 动态安全测试 :在测试或预发布环境,使用 OWASP ZAP 等DAST工具进行动态扫描,模拟黑客攻击行为,发现运行时漏洞。

2. 将安全内化为开发习惯:

  • 安全培训 :定期分享Bandit扫描出的真实案例,将其转化为团队内部的安全编码规范。
  • 代码审查清单 :在代码审查清单中增加安全项,例如:“是否处理了用户输入?”、“是否有硬编码的敏感信息?”、“数据库查询是否参数化?”。
  • 威胁建模 :在项目设计阶段,简单讨论可能面临的安全威胁,提前在架构和代码层面考虑缓解措施。

3. 理解Bandit的局限性: Bandit不是银弹。它无法发现:

  • 业务逻辑漏洞 :例如,权限绕过、金额篡改。
  • 运行时漏洞 :依赖于特定输入和程序状态才能触发的漏洞。
  • 依赖库的漏洞 :你使用的 requests django 版本本身有漏洞。
  • 配置错误 :服务器、数据库的错误配置。

因此,Bandit的最佳定位是“自动化代码安全守门员”,它能以极低的成本捕获大量常见的、模式化的编码安全缺陷,为开发者提供快速反馈。但它不能替代安全专家的评审、渗透测试以及开发者自身安全意识的提升。

5. 常见问题与排查技巧实录

在实际推广和使用Bandit的过程中,我和团队遇到过不少典型问题。这里记录下最常见的几个及其解决方法。

Q1:Bandit扫描速度太慢,大型项目怎么办? A:这是最常见的问题。可以尝试以下优化:

  • 使用 -x / --exclude 参数 :排除 venv , .git , build , dist , __pycache__ 等无关目录。
  • 增量扫描 :在CI中,可以结合Git命令只扫描变更的文件。例如: bandit $(git diff --name-only HEAD~1 HEAD | grep '.py$') 。但要注意,这种方式可能漏掉因变更而受影响的其他文件。
  • 并行扫描 :Bandit本身不支持并行,但你可以将项目目录拆分成多个子目录,用 xargs GNU parallel 启动多个Bandit进程并行扫描,最后合并报告(需要自己写脚本处理)。
  • 升级硬件 :CI Runner使用性能更好的机器。

Q2:Bandit报告了一个问题,但我认为我的用法是安全的,如何证明? A:这是处理误报的核心。你需要向团队(或未来的自己)证明代码的安全性。

  1. 添加详细注释 :在 # nosec 旁边,详细说明为什么这里是安全的。例如:“此 eval 仅用于拼接内部定义的、经过白名单校验的函数名, func_name 来自内部配置字典,非用户输入。”
  2. 编写单元测试 :如果可能,为这段有争议的代码编写一个安全测试用例,证明在预期的输入范围内,它不会产生安全问题。这比注释更有说服力。
  3. 寻求第二意见 :在代码审查中提出,让其他同事一起评估风险。

Q3:如何让Bandit检查Jupyter Notebook文件(.ipynb)? A:Bandit默认只检查 .py 文件。对于 .ipynb ,你需要先将它转换为 .py 文件。

# 使用jupyter nbconvert将notebook转换为python脚本
jupyter nbconvert --to script my_analysis.ipynb
# 然后扫描生成的.py文件
bandit my_analysis.py

可以考虑将这个过程写进CI脚本,自动化扫描项目中的所有Notebook。

Q4:Bandit的某个规则(如B404)我们就是想全局禁用,怎么管理? A:在项目根目录的 .banditrc 配置文件中设置 skips 是最佳实践。这相当于项目的“安全策略声明”,所有开发者共享同一套规则。禁止在命令行中为不同的人设置不同的跳过规则,那会导致标准不一。

Q5:Bandit没有报告问题,是否意味着代码绝对安全? A: 绝对不是! 这是最重要的认知。Bandit只是一个基于模式的静态分析工具。它只能发现它“知道”的漏洞模式。代码安全是一个涵盖设计、实现、部署、运维的完整生命周期问题。没有工具能提供100%的安全保证。Bandit的价值在于,它能以自动化、低成本的方式,帮助你消除一大批“已知的、不该犯的”错误,从而让你有更多精力去应对更复杂、更隐蔽的安全挑战。

最后,分享一个我个人的小习惯:每次Bandit在CI中报告一个新类型的问题(尤其是高严重性的),我都会把它记下来,并花10分钟研究一下背后的原理和修复方法。久而久之,这些曾经由工具发现的问题,在我写代码的时候就会自然而然地避开。这大概就是Bandit这类工具最大的意义——它不仅仅是在“找bug”,更是在潜移默化中训练开发者的“安全肌肉记忆”。

更多推荐