Bandit

← 返回目录 > ← 返回总览

相关工具推荐

工具 说明
Ruff 内置 flake8-bandit 兼容规则(S 系列),可替代 Bandit 的部分检查
Pylint 包含部分安全相关检查,可与 Bandit 互补
Mypy 静态类型安全,与 Bandit 的运行时安全检查互补
Gitleaks 检测 Git 仓库中的密钥泄露,与 Bandit 的代码安全检查互补
Detect-Secrets Yelp 出品的密钥泄露基线扫描工具
CodeQL GitHub 官方代码分析引擎,支持 Python 安全分析
Gosec Go 生态的安全扫描工具,定位类似

1. 简介

Bandit 是由 PyCQA 维护的 Python 代码安全扫描工具,专门用于发现 Python 代码中的常见安全问题。Bandit 通过解析每个源文件构建 AST(抽象语法树),然后对 AST 节点运行插件化检测规则,最终生成安全报告。

  • 主要检查语言:Python
  • 主要检查能力:检测 Python 代码中的安全隐患(硬编码密码、注入风险、弱加密、子进程调用等);涵盖安全类检查
  • 核心检查原理:基于 Python AST 遍历,插件化检测规则架构,支持自定义扩展
  • 检查规则/选项:34 个 B 规则(B1xx 杂项、B2xx 框架配置、B5xx 密码学、B6xx 注入、B7xx XSS),全量规则列表
  • GitHub 仓库https://github.com/PyCQA/bandit(8,084 stars)
  • 开源协议:Apache-2.0
  • 最新稳定版本:v1.8.3
  • 运行环境要求:Python 3.9+
  • 误报率:低

2. 官方文档

文档 链接
官方文档首页 https://bandit.readthedocs.io/en/latest/
快速入门(安装与基本用法) https://bandit.readthedocs.io/en/latest/start.html
配置说明 https://bandit.readthedocs.io/en/latest/config.html
集成方式(IDE、CI/CD、Linters) https://bandit.readthedocs.io/en/latest/integrations.html
检测插件完整列表 https://bandit.readthedocs.io/en/latest/plugins/index.html
黑名单插件(调用与导入) https://bandit.readthedocs.io/en/latest/blacklists/index.html
报告格式器 https://bandit.readthedocs.io/en/latest/formatters/index.html
CI/CD 集成(GitHub Actions) https://bandit.readthedocs.io/en/latest/ci-cd/github-actions.html
常见问题 https://bandit.readthedocs.io/en/latest/faq.html

3. 社区优秀实践

3.1 OpenStack Keystone

OpenStack Keystone 是 OpenStack 的身份认证服务,是 Bandit 的原始诞生项目之一。Keystone 在 pre-commit 中集成了 Bandit,并在 pyproject.toml 中配置了 Bandit 规则。

  • pre-commit 配置:在 .pre-commit-config.yaml 中使用 https://github.com/PyCQA/bandit 仓库,指定 rev: '1.8.3',通过 args: ['-c', 'pyproject.toml'] 引用配置文件
  • Bandit 配置:在 pyproject.toml[tool.bandit] 节中配置 exclude_dirs,排除测试和开发目录
  • 生态参考项目openstack/keystone

3.2 PyCQA Bandit 官方仓库

Bandit 自身仓库同时维护了 .pre-commit-hooks.yaml,使其他项目可以直接通过 pre-commit 引用 Bandit 作为 hook。这是 Bandit 官方推荐的 pre-commit 集成方式。

  • pre-commit hooks 定义.pre-commit-hooks.yaml 定义了 bandit hook,使用 language: pythonlanguage_version: python3,限制 types: [python],设置 require_serial: true 避免并行冲突
  • 生态参考项目PyCQA/bandit

3.3 PyCQA bandit-action(GitHub Actions 官方 Action)

PyCQA 官方提供了 bandit-action GitHub Action,支持 Code Scanning 结果上传,被超过 270 个仓库使用。

  • 功能:自动运行 Bandit 扫描,支持 SARIF 格式输出并上传至 GitHub Code Scanning
  • 配置项:支持 configfileprofiletestsskipsseverityconfidenceexcludebaselinetargets 等输入参数
  • 生态参考项目PyCQA/bandit-action

4. 工具配置说明

4.1 配置文件说明

Bandit 支持多种配置文件格式:

配置文件 格式 用途 使用场景
.bandit INI 项目级默认配置 放在项目根目录,使用 -r 时自动加载
bandit.yaml YAML 显式指定的配置文件 通过 -c bandit.yaml 指定
pyproject.toml TOML 与项目其他 Python 工具配置统一管理 通过 -c pyproject.toml 指定,需安装 bandit[toml]

注意.bandit INI 文件仅在 Bandit 使用 -r 选项时自动查找。如果使用其他文件名或格式,必须通过 -c--ini 显式指定。

4.2 bandit.yaml 配置详解

Bandit 的配置项在不同格式下语义一致,仅语法不同。以下配置项适用于 .bandit(INI)、bandit.yaml(YAML)和 pyproject.toml(TOML [tool.bandit] 段)三种格式。

配置项说明

配置项 类型 说明
exclude_dirs string[] 排除非业务代码的目录列表(INI 格式中对应 exclude,值为逗号分隔字符串)
tests string[] 仅运行的检测规则 ID 列表
skips string[] 跳过的检测规则 ID 列表

最小配置示例(三种格式对照):

INI 格式(.bandit):

# .bandit
[bandit]
exclude = tests,path/to/file
tests = B201,B301
skips = B101,B601

YAML 格式(bandit.yaml):

# bandit.yaml
exclude_dirs: ["tests", "path/to/file"]
tests: ["B201", "B301"]
skips: ["B101", "B601"]

TOML 格式(pyproject.toml):

# pyproject.toml
[tool.bandit]
exclude_dirs = ["tests", "path/to/file"]
tests = ["B201", "B301"]
skips = ["B101", "B601"]

默认全量扫描

对于大多数项目,建议先使用 Bandit 的默认全量扫描评估结果,再根据实际情况调整配置:

bandit -r . -f json -o bandit-report.json

推荐配置示例

以下配置跳过常见的误报规则,同时保留所有高价值的安全检查(以 pyproject.toml 为例):

[tool.bandit]
# 排除非业务代码目录
exclude_dirs = [
    "tests",
    "test_*",
    "migrations",
    "venv",
    ".venv",
    "__pycache__",
    ".tox",
    "build",
    "dist",
    "*.egg-info",
]

# 跳过常见误报规则:
# B101: assert_used -- assert 在测试中广泛使用,生产代码中也有合理用途
# B603: subprocess_without_shell_equals_true -- 不带 shell=True 的 subprocess 本身较安全
# B606: start_process_with_no_shell -- 同上
skips = ["B101", "B603", "B606"]

4.3 规则 ID 分组说明

Bandit 的检测规则按 ID 范围分组:

ID 范围 分类 说明
B1xx 杂项检查 assert 使用、exec 使用、硬编码密码/路径/端口、try-except-pass 等
B2xx 应用/框架配置 Flask debug 模式等
B3xx 黑名单(函数调用) 不安全的函数调用黑名单
B4xx 黑名单(模块导入) 不安全的模块导入黑名单
B5xx 加密相关 SSL/TLS 配置、弱密钥、不安全的 YAML 加载、SSH 配置等
B6xx 注入攻击 shell 注入、SQL 注入、Paramiko 调用等
B7xx XSS Jinja2 自动转义、Mako 模板、Django mark_safe 等

4.4 高优先级规则说明

以下规则建议在所有项目中启用,覆盖了最常见的 Python 安全漏洞:

规则 ID 名称 严重级别 说明
B105 hardcoded_password_string High 检测硬编码的密码字符串
B106 hardcoded_password_funcarg High 检测函数参数中的硬编码密码
B107 hardcoded_password_default High 检测函数默认参数中的硬编码密码
B108 hardcoded_tmp_directory Low 检测硬编码的临时目录路径
B110 try_except_pass Low 检测空 except 块(可能吞没安全异常)
B112 try_except_continue Low 检测 except 块中的 continue(可能跳过安全处理)
B201 flask_debug_true High 检测 Flask debug 模式开启
B501 request_with_no_cert_validation High 检测未验证证书的 HTTP 请求
B502 ssl_with_bad_version High 检测不安全的 SSL/TLS 版本
B503 ssl_with_bad_defaults Medium 检测不安全的 SSL/TLS 默认配置
B504 ssl_with_no_version High 检测未指定版本的 SSL/TLS
B505 weak_cryptographic_key Medium 检测弱加密密钥
B506 yaml_load Medium 检测不安全的 yaml.load 调用
B507 ssh_no_host_key_verification High 检测未验证 SSH 主机密钥
B601 paramiko_calls Medium 检测不安全的 Paramiko 调用
B602 subprocess_popen_with_shell_equals_true High 检测 shell=True 的 subprocess 调用
B607 start_process_with_partial_path Medium 检测使用部分路径启动进程
B608 hardcoded_sql_expressions Medium 检测硬编码的 SQL 表达式
B609 linux_commands_wildcard_injection High 检测 Linux 命令通配符注入
B610 django_extra_used Medium 检测 Django extra() 中的 SQL 注入风险
B611 django_rawsql_used Medium 检测 Django raw() 中的 SQL 注入风险
B701 jinja2_autoescape_false High 检测 Jinja2 自动转义关闭
B702 use_of_mako_templates Medium 检测 Mako 模板使用(默认不转义)
B703 django_mark_safe Medium 检测 Django mark_safe 使用

完整规则列表请参考:Bandit 检测插件完整列表黑名单插件

5. 主流集成方式

5.1 pip / uv 安装(生态主流)

Bandit 是 Python 工具,其生态主流安装方式为 pip/uv。

# 使用 pip 安装
pip install bandit

# 使用 uv 安装
uv pip install bandit

# 如需 TOML 配置文件支持(pyproject.toml)
pip install bandit[toml]

# 如需 SARIF 输出格式支持
pip install bandit[sarif]

# 如需 bandit-baseline CLI
pip install bandit[baseline]

pyproject.toml 中声明为开发依赖:

[project.optional-dependencies]
dev = ["bandit[toml]>=1.9.4"]

5.2 pre-commit 集成

Bandit 官方仓库提供了 .pre-commit-hooks.yaml,可直接引用。

适用前提: pre-commit 会自动创建隔离的 Python 虚拟环境并安装 Bandit,无需项目本地预先安装 Bandit。如需使用自定义配置文件(如 pyproject.toml),需通过 additional_dependencies 添加 bandit[toml]

# .pre-commit-config.yaml
repos:
  - repo: https://github.com/PyCQA/bandit
    rev: "1.9.4" # 建议锁定版本
    hooks:
      - id: bandit
        # 如需使用 pyproject.toml 配置,取消下面注释
        # args: ["-c", "pyproject.toml"]
        # additional_dependencies: ["bandit[toml]"]

说明:pre-commit 默认仅将暂存区中变更的文件传给 hook(文件级增量),因此 Bandit 通过 pre-commit 运行时天然只检查变更文件。

安装并启用 hook:

pre-commit install
pre-commit run bandit --all-files  # 手动全量运行

增量检查:文件级增量检查优先基于 pre-commit 框架实现。pre-commit 默认仅将暂存区中变更的文件传给 hook,Bandit 通过 pre-commit 运行时天然只检查变更的 Python 文件。

5.3 IDE 集成

VS Code:

安装扩展 Bandit by PyCQA,在 VS Code 中实时显示 Bandit 安全检查结果。

Vim/Neovim:

通过 ALE (Asynchronous Lint Engine) 集成 Bandit。ALE 支持 Bandit 作为 Python linter,在编辑时自动运行检查。

Sublime Text:

通过 SublimeLinter-bandit 插件集成。

Emacs:

通过 flycheck-pycheckers 集成。

5.4 命令行使用方式

# 递归扫描项目目录
bandit -r path/to/your/code

# 扫描指定文件
bandit examples/*.py

# 只报告高危问题
bandit -r . --severity-level=high
bandit -r . -lll

# 指定上下文行数
bandit examples/*.py -n 3

# 使用配置文件
bandit -c pyproject.toml -r .

# 使用 .bandit INI 文件(需配合 -r 使用)
bandit -r .

# 指定 INI 文件路径
bandit --ini tox.ini -r .

# 跳过指定测试规则
bandit -r . -s B101,B601

# 只运行指定测试规则
bandit -r . -t B201,B301

# 使用 profile
bandit examples/*.py -p ShellInjection

# 从标准输入读取
cat examples/imports.py | bandit -

# 输出为 JSON 格式(用于基线对比)
bandit -f json -o bandit-report.json -r .

# 使用基线对比
bandit -b baseline.json -r .

# 指定排除目录
bandit -r . --exclude "tests/,venv/"

# 查看帮助
bandit -h

检查模式 vs 修复模式: Bandit 是纯检查工具,不提供自动修复功能。发现安全问题后需手动修复代码,或通过 # nosec 注释抑制误报。

增量检查 -- Bandit 本身不提供专门的增量参数(如 --new-from-rev),但可以直接将文件列表传给 Bandit:

# 直接指定文件列表
bandit file1.py file2.py path/to/module.py

# 使用 glob 模式
bandit "src/**/*.py"

配合 Git 获取变更文件列表实现增量扫描:

# 只检查 Git 暂存区中变更的 Python 文件
git diff --name-only --diff-filter=ACMR -- '*.py' | xargs bandit

# 只检查相对于指定 commit 变更的 Python 文件
git diff --name-only --diff-filter=ACMR main -- '*.py' | xargs bandit

# 配合配置文件
git diff --name-only --diff-filter=ACMR -- '*.py' | xargs bandit -c pyproject.toml

CI 脚本调用

GitHub Actions(手动安装方式)

# .github/workflows/bandit.yml
name: Bandit
on: [push, pull_request]

jobs:
  bandit:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: "3.12"
      - run: pip install bandit[toml]
      - run: bandit -c pyproject.toml -r . -f json -o bandit-report.json
      - run: bandit -c pyproject.toml -r .

GitLab CI

# .gitlab-ci.yml
bandit:
  image: python:3.12
  before_script:
    - pip install bandit[toml]
  script:
    - bandit -c pyproject.toml -r . -f json -o bandit-report.json
    - bandit -c pyproject.toml -r .
  artifacts:
    reports:
      codequality: bandit-report.json
    when: always

增量检查 -- 按 PR/MR 变更文件触发增量扫描:

GitHub Actions -- 按 PR 变更文件触发增量检查:

name: Bandit Incremental
on:
  pull_request:

jobs:
  bandit:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - uses: actions/setup-python@v5
        with:
          python-version: "3.12"
      - run: pip install bandit[toml]
      - name: Run Bandit on changed files
        run: |
          CHANGED=$(git diff --name-only --diff-filter=ACMR origin/main -- '*.py')
          if [ -n "$CHANGED" ]; then
            echo "$CHANGED" | xargs bandit -c pyproject.toml
          else
            echo "No Python files changed."
          fi

GitLab CI -- 按 MR 变更文件触发增量检查:

bandit-incremental:
  image: python:3.12
  before_script:
    - pip install bandit[toml]
  script:
    - |
      CHANGED=$(git diff --name-only --diff-filter=ACMR origin/$CI_MERGE_REQUEST_TARGET_BRANCH_NAME -- '*.py')
      if [ -n "$CHANGED" ]; then
        echo "$CHANGED" | xargs bandit -c pyproject.toml
      else
        echo "No Python files changed."
      fi
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"

5.5 GitHub Action 插件

使用 PyCQA 官方提供的 bandit-action,支持自动上传 Code Scanning 结果:

# .github/workflows/bandit.yml
name: Bandit Security Scan
on:
  push:
    branches: [main]
  pull_request:
    branches: [main]
  workflow_dispatch:

jobs:
  analyze:
    runs-on: ubuntu-latest
    permissions:
      security-events: write
      actions: read
      contents: read
    steps:
      - uses: actions/checkout@v4
      - name: Perform Bandit Analysis
        uses: PyCQA/bandit-action@v1
        with:
          targets: "myapp/"
          severity: "medium"
          exclude: "tests/,migrations/"

6. 告警抑制(屏蔽)方法

6.1 通过 pre-commit 屏蔽

.pre-commit-config.yaml 中通过 excludefiles 等字段控制 Bandit 的检查范围:

repos:
  - repo: https://github.com/PyCQA/bandit
    rev: "1.9.4"
    hooks:
      - id: bandit
        # 只检查 src 目录下的 Python 文件
        files: '^src/.*\.py$'
        # 排除测试和迁移文件
        exclude: "^src/tests/.*|^.*/migrations/.*"
        args: ["-c", "pyproject.toml"]
        additional_dependencies: ["bandit[toml]"]

参考:pre-commit 配置说明

6.2 通过工具配置文件屏蔽

在配置文件中通过 exclude_dirs/exclude 排除文件/目录,通过 skips 跳过指定规则:

TOML 格式(pyproject.toml):

[tool.bandit]
# 排除目录
exclude_dirs = ["tests", "migrations", "venv"]
# 跳过指定规则
skips = ["B101", "B601"]
# 只运行指定规则
# tests = ["B201", "B301"]

YAML 格式(bandit.yaml):

exclude_dirs: ["tests", "migrations", "venv"]
skips: ["B101", "B601"]

INI 格式(.bandit):

[bandit]
exclude = tests,migrations,venv
skips = B101,B601

参考:Bandit 配置文件说明

6.3 通过工具命令行参数屏蔽

# 排除目录
bandit -r . --exclude "tests/,migrations/,venv/"

# 跳过指定规则
bandit -r . -s B101,B601

# 只运行指定规则
bandit -r . -t B201,B301

# 只报告指定严重级别及以上的问题
bandit -r . --severity-level=high

# 只报告指定置信级别及以上的问题
bandit -r . --confidence-level=high

# 组合使用
bandit -r . -s B101 --exclude "tests/" --severity-level=medium

参考:Bandit 快速入门

6.4 通过代码屏蔽

行级注释 # nosec

在触发告警的行末添加 # nosec,Bandit 将跳过该行的所有安全检查:

# 跳过该行所有安全检查
self.process = subprocess.Popen('/bin/echo', shell=True)  # nosec

行级注释指定规则 ID:

可以指定要跳过的具体规则 ID,其他安全问题仍会被报告:

# 只跳过 B602 和 B607
self.process = subprocess.Popen('/bin/ls *', shell=True)  # nosec B602, B607

也可以使用完整的测试名称:

# 只跳过 assert_used(B101),B506 仍会被报告
assert yaml.load("{}") == []  # nosec assert_used

最佳实践:使用 # nosec 时建议添加注释说明原因,避免后续引入新的安全问题被意外忽略。

参考:Bandit 配置 -- Exclusions(行级抑制)