千锋教育-做有情怀、有良心、有品质的职业教育机构

3步集成Bandit,你的Python测试代码漏洞无处遁形

来源:千锋教育
发布时间:2026-05-05 11:16:34

千锋教育品牌logo

01 为什么测试代码是黑客的“后门”?

测试代码——开发者眼中最安全的角落,却是黑客眼里最甜美的果实。

2023年,某知名云服务商遭遇数据泄露,攻击者并非直接攻破生产环境,而是通过一个暴露的测试API端点,获取了数据库访问凭证。这个测试端点,本该在部署前就被清理干净。但测试代码中硬编码的密钥,成了整条防线上的裂缝。

数据不会说谎:根据Verizon《2023年数据泄露调查报告》,超过60%的安全事件与内部系统漏洞相关,其中测试环境暴露的问题占比逐年上升。测试代码中常见的风险点包括:

  • ▸ **硬编码凭证**:测试数据库密码、API密钥直接写在代码里
  • ▸ **不安全的网络请求**:使用HTTP而非HTTPS,或未验证SSL证书
  • ▸ **敏感信息泄露**:日志中打印密码、Token等敏感数据
  • ▸ **权限越界**:测试代码绕过认证和授权检查
  • ▸ **注入漏洞**:SQL注入、命令注入在测试场景中屡见不鲜

**测试代码的漏洞不是bug,是给黑客留的钥匙。**

你的测试代码可能运行在Jenkins、GitLab CI等持续集成环境中。这些环境往往拥有访问生产数据库、云服务凭证的权限。一旦测试代码被攻破,攻击者就能通过这个“后门”直取核心资产。

02 Bandit:专为Python代码打造的安全扫描器

Bandit是Python生态中最成熟的安全扫描工具之一。它不是一个通用安全工具,而是专门针对Python代码的安全风险分析器。

Bandit的工作原理:它不是一个简单的字符串匹配工具。Bandit对Python代码进行AST(抽象语法树)解析,识别出潜在的安全风险模式。这意味着它能理解代码结构,减少误报率。

核心能力:

  • ▸ 检测硬编码密码(通过模式匹配和熵值分析)
  • ▸ 发现不安全的函数调用(如`eval()`、`exec()`、`pickle.loads()`)
  • ▸ 识别SQL注入风险(检测字符串拼接的SQL查询)
  • ▸ 标记不安全的网络请求(如未验证SSL的`requests.get()`)
  • ▸ 检测文件权限问题(如`chmod`设置不当)

安装Bandit:一行命令搞定

BASH
pip install bandit

验证安装:

BASH
bandit --version

输出示例:

代码
bandit 1.7.6
  python version: 3.11.4

为什么选择Bandit而不是其他工具?

  • ▸ 零配置即可运行:`bandit -r your_code/`
  • ▸ 可自定义规则:通过配置文件增减检测项
  • ▸ 支持多种输出格式:JSON、XML、HTML
  • ▸ 与CI/CD无缝集成:非零退出码可阻断构建

**Bandit不是万能药,但它是你代码安全的守门人。**

03 实战:三步完成测试代码安全扫描

第一步:创建测试代码样本

创建一个包含常见安全漏洞的测试文件test_vulnerable.py:

PYTHON
# test_vulnerable.py - 一个包含安全漏洞的测试文件
#CE9178">"color:#569CD6;font-weight:bold">import os
#CE9178">"color:#569CD6;font-weight:bold">import pickle
#CE9178">"color:#569CD6;font-weight:bold">import hashlib
#CE9178">"color:#569CD6;font-weight:bold">import requests
#CE9178">"color:#569CD6;font-weight:bold">import sqlite3

# 漏洞1:硬编码密码
DB_PASSWORD = #CE9178">"SuperSecret123!"

#CE9178">"color:#569CD6;font-weight:bold">def test_database_connection():
    #CE9178">"""测试数据库连接"""
    conn = sqlite3.connect(#CE9178">'test.db')
    cursor = conn.cursor()
    
    # 漏洞2:SQL注入风险 - 直接拼接用户输入
    user_input = #CE9178">"admin' OR '1'='1"
    query = f#CE9178">"SELECT * FROM users WHERE username = '{user_input}'"
    cursor.execute(query)
    
    # 漏洞3:不安全的反序列化
    data = pickle.loads(b#CE9178">"malicious_payload")
    
    # 漏洞4:不安全的哈希算法
    password = #CE9178">"my_password"
    hashed = hashlib.md5(password.encode()).hexdigest()
    
    # 漏洞5:不安全的HTTP请求(无SSL验证)
    response = requests.get(#CE9178">'http://api.example.com/data', verify="color:#569CD6;font-weight:bold">False)
    
    # 漏洞6:使用eval执行动态代码
    user_code = #CE9178">"">print('Hello')"
    eval(user_code)
    
    conn.close()

第二步:运行Bandit扫描

执行基础扫描命令:

BASH
bandit -r .

输出示例:

代码
[main]  INFO    profile include tests: None
[main]  INFO    profile exclude tests: None
[main]  INFO    cli include tests: None
[main]  INFO    cli exclude tests: None
[main]  INFO    running on Python 3.11.4

Run started:2024-01-15 14:30:00.123456

Test results:
>> Issue: [B105:hardcoded_password_string] Possible hardcoded password: 'SuperSecret123!'
   Severity: Medium   Confidence: Medium
   Location: test_vulnerable.py:5:1
   More Info: https://bandit.readthedocs.io/en/latest/plugins/b105_hardcoded_password_string.html

>> Issue: [B608:hardcoded_sql_expressions] Possible SQL injection vector through string-based query construction.
   Severity: Medium   Confidence: Medium
   Location: test_vulnerable.py:15:28
   More Info: https://bandit.readthedocs.io/en/latest/plugins/b608_hardcoded_sql_expressions.html

>> Issue: [B301:pickle] Pickle and modules that wrap it can be unsafe when used to deserialize untrusted data
   Severity: Medium   Confidence: High
   Location: test_vulnerable.py:19:15
   More Info: https://bandit.readthedocs.io/en/latest/plugins/b301_pickle.html

>> Issue: [B303:md5] Use of insecure MD2, MD4, MD5, or SHA1 hash function.
   Severity: Medium   Confidence: High
   Location: test_vulnerable.py:23:15
   More Info: https://bandit.readthedocs.io/en/latest/plugins/b303_md5.html

>> Issue: [B501:request_with_no_cert_validation] Requests call with verify=False disabling SSL certificate checks
   Severity: Medium   Confidence: High
   Location: test_vulnerable.py:27:19
   More Info: https://bandit.readthedocs.io/en/latest/plugins/b501_request_with_no_cert_validation.html

>> Issue: [B307:eval] Use of possibly insecure function - consider using safer alternatives
   Severity: Medium   Confidence: High
   Location: test_vulnerable.py:31:4
   More Info: https://bandit.readthedocs.io/en/latest/plugins/b307_eval.html

--------------------------------------------------
6 issues found. (Sev: 0 High, 6 Medium, 0 Low)

第三步:使用自定义配置优化扫描

创建.bandit.yml配置文件:

YAML
# .bandit.yml
# 排除某些测试,减少误报
exclude_dirs:
  - ./tests/unit
  - ./docs

# 仅包含特定测试
tests:
  - B105  # 硬编码密码
  - B301  # 不安全的反序列化
  - B303  # 不安全的哈希
  - B307  # eval使用
  - B501  # 不安全的请求
  - B608  # SQL注入

# 设置严重级别阈值
skips:
  - B101  # 跳过assert语句检测(测试代码中常见)

# 自定义输出格式
output_format: json

使用配置文件运行:

BASH
bandit -r . -c .bandit.yml -f json -o bandit_report.json

查看生成的JSON报告:

JSON
{
  "errors": [],
  "generated_at": "2024-01-15T14:35:00Z",
  "metrics": {
    "_totals": {
      "CONFIDENCE.HIGH": 5,
      "CONFIDENCE.LOW": 0,
      "CONFIDENCE.MEDIUM": 1,
      "SEVERITY.HIGH": 0,
      "SEVERITY.LOW": 0,
      "SEVERITY.MEDIUM": 6,
      "loc": 35,
      "nosec": 0
    }
  },
  "results": [
    {
      "code": "5 DB_PASSWORD = \"SuperSecret123!\"\n",
      "filename": "./test_vulnerable.py",
      "issue_confidence": "MEDIUM",
      "issue_severity": "MEDIUM",
      "issue_text": "Possible hardcoded password: 'SuperSecret123!'",
      "line_number": 5,
      "line_range": [5],
      "more_info": "https://bandit.readthedocs.io/en/latest/plugins/b105_hardcoded_password_string.html",
      "test_id": "B105"
    }
    // ... 更多结果
  ]
}

**扫描不是终点,修复才是。**

04 修复漏洞:从扫描到安全代码

1
Bandit发现问题只是第一步。真正的价值在于修复。以下是针对上述漏洞的修复方案

修复1:硬编码密码 → 环境变量

问题代码:

PYTHON
DB_PASSWORD = #CE9178">"SuperSecret123!"

修复代码:

PYTHON
#CE9178">"color:#569CD6;font-weight:bold">import os

DB_PASSWORD = os.environ.get(#CE9178">'DB_PASSWORD')
#CE9178">"color:#569CD6;font-weight:bold">if "color:#569CD6;font-weight:bold">not DB_PASSWORD:
    #CE9178">"color:#569CD6;font-weight:bold">raise ValueError("DB_PASSWORD environment variable ">not ">set")

修复2:SQL注入 → 参数化查询

问题代码:

PYTHON
query = f#CE9178">"SELECT * FROM users WHERE username = '{user_input}'"
cursor.execute(query)

修复代码:

PYTHON
query = #CE9178">"SELECT * FROM users WHERE username = ?"
cursor.execute(query, (user_input,))

修复3:不安全反序列化 → JSON

问题代码:

PYTHON
data = pickle.loads(b#CE9178">"malicious_payload")

修复代码:

PYTHON
#CE9178">"color:#569CD6;font-weight:bold">import json

data = json.loads(b#CE9178">'{"safe": "payload"}')

修复4:弱哈希算法 → 强哈希

问题代码:

PYTHON
hashed = hashlib.md5(password.encode()).hexdigest()

修复代码:

PYTHON
#CE9178">"color:#569CD6;font-weight:bold">import bcrypt

# 生成盐值并哈希
salt = bcrypt.gensalt()
hashed = bcrypt.hashpw(password.encode(), salt)

修复5:不安全的HTTP请求 → 验证SSL

问题代码:

PYTHON
response = requests.get(#CE9178">'http://api.example.com/data', verify="color:#569CD6;font-weight:bold">False)

修复代码:

PYTHON
#CE9178">"color:#569CD6;font-weight:bold">import requests
#CE9178">"color:#569CD6;font-weight:bold">from requests.packages.urllib3.exceptions "color:#569CD6;font-weight:bold">import InsecureRequestWarning

# 关闭警告(仅用于演示,生产环境必须验证)
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)

# 使用HTTPS并验证证书
response = requests.get(#CE9178">'https://api.example.com/data', verify="color:#569CD6;font-weight:bold">True)

修复6:eval执行 → 安全替代方案

问题代码:

PYTHON
eval(user_code)

修复代码:

PYTHON
#CE9178">"color:#569CD6;font-weight:bold">import ast

# 使用AST解析代替eval
#CE9178">"color:#569CD6;font-weight:bold">try:
    tree = ast.parse(user_code, mode=#CE9178">'exec')
    # 仅允许安全操作
    #CE9178">"color:#569CD6;font-weight:bold">for node "color:#569CD6;font-weight:bold">in ast.walk(tree):
        #CE9178">"color:#569CD6;font-weight:bold">if "color:#4EC9B0">isinstance(node, ast.Call) "color:#569CD6;font-weight:bold">and "color:#4EC9B0">isinstance(node.func, ast.Name):
            #CE9178">"color:#569CD6;font-weight:bold">if node.func.id "color:#569CD6;font-weight:bold">not "color:#569CD6;font-weight:bold">in ['">print']:
                #CE9178">"color:#569CD6;font-weight:bold">raise ValueError("Unsafe operation detected")
    exec(compile(tree, filename=#CE9178">'<ast>', mode='exec'))
#CE9178">"color:#569CD6;font-weight:bold">except SyntaxError:
    #CE9178">"color:#569CD6;font-weight:bold">raise ValueError("Invalid Python code")

修复完成后,重新运行Bandit验证:

BASH
bandit -r .

输出应该显示0个问题:

代码
No issues found.

**修复一个漏洞,堵住一个后门。**

05 集成到CI/CD:让安全扫描自动化

手动扫描不够,将Bandit集成到持续集成流程中,实现自动化安全检测。

GitLab CI示例

创建.gitlab-ci.yml文件:

YAML
stages:
  - test
  - security

bandit-scan:
  stage: security
  image: python:3.11
  script:
    - pip install bandit
    - bandit -r . -f json -o bandit_report.json
    - |
      # 检查是否有高严重性问题
      if jq -e '.results[] | select(.issue_severity == "HIGH")' bandit_report.json > /dev/null; then
        echo "High severity issues found!"
        exit 1
      fi
  artifacts:
    paths:
      - bandit_report.json
    when: always
  only:
    - main
    - develop

GitHub Actions示例

创建.github/workflows/security-scan.yml:

YAML
name: Security Scan

on:
  push:
    branches: [ main, develop ]
  pull_request:
    branches: [ main ]

jobs:
  bandit-scan:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3
    
    - name: Set up Python
      uses: actions/setup-python@v4
      with:
        python-version: '3.11'
    
    - name: Install Bandit
      run: pip install bandit
    
    - name: Run Bandit Scan
      run: |
        bandit -r . -f json -o bandit_report.json
        cat bandit_report.json
    
    - name: Upload Bandit Report
      uses: actions/upload-artifact@v3
      with:
        name: bandit-report
        path: bandit_report.json
    
    - name: Fail on High Severity
      run: |
        if jq -e '.results[] | select(.issue_severity == "HIGH")' bandit_report.json > /dev/null; then
          echo "High severity issues found!"
          exit 1
        fi

Jenkins Pipeline示例

GROOVY
pipeline {
    agent any
    
    stages {
        stage('Security Scan') {
            steps {
                script {
                    sh 'pip install bandit'
                    sh 'bandit -r . -f json -o bandit_report.json'
                    
                    def report = readJSON file: 'bandit_report.json'
                    def highIssues = report.results.findAll { it.issue_severity == 'HIGH' }
                    
                    if (highIssues.size() > 0) {
                        error "Found ${highIssues.size()} high severity issues"
                    }
                }
            }
            post {
                always {
                    archiveArtifacts artifacts: 'bandit_report.json'
                }
            }
        }
    }
}

---

**安全不是一次性检查,而是持续的习惯。**

你的测试代码现在有了安全守门人。每次提交,Bandit都会自动扫描,发现潜在风险。这不是锦上添花,而是雪中送炭。在黑客找到你测试代码的漏洞之前,先自己找到并修复它。

行动指令:今天就在你的测试项目中集成Bandit。3步操作,10分钟配置,换来的是代码安全的长期保障。

声明:本站部分稿件版权来源于网络,如有侵犯版权,请及时联系我们。

学习资源站

  • 免费全套视频教程
  • 企业实战项目源码
  • 大厂笔试真题题库
  • 行业前瞻发展趋势

相关推荐