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

3步集成Bandit,你的Python测试代码漏洞无处遁形_千锋教育

来源:千锋教育
发布时间:2026-07-03 18:17:04

千锋教育品牌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

输出示例:

text
bandit 1.7.6
  python version: 3.11.4

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

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

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

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

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

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

test_vulnerable.py - 一个包含安全漏洞的测试文件

import os

import pickle

import hashlib

import requests

import sqlite3

漏洞1:硬编码密码

DB_PASSWORD = "SuperSecret123!"

def test_database_connection():

"""测试数据库连接"""

conn = sqlite3.connect('test.db')

cursor = conn.cursor()

漏洞2:SQL注入风险 - 直接拼接用户输入

user_input = "admin' OR '1'='1"

query = f"SELECT * FROM users WHERE username = '{user_input}'"

cursor.execute(query)

漏洞3:不安全的反序列化

data = pickle.loads(b"malicious_payload")

漏洞4:不安全的哈希算法

password = "my_password"

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

漏洞5:不安全的HTTP请求(无SSL验证)

response = requests.get('http://api.example.com/data', verify=False)

漏洞6:使用eval执行动态代码

user_code = "print('Hello')"

eval(user_code)

conn.close()

text

<div style="margin:24px 0;border:1px solid #E3F2FD;border-radius:8px;background:#FAFAFA;overflow:hidden;"><div style="display:flex;align-items:center;gap:12px;padding:12px 20px;background:linear-gradient(135deg,#E3F2FD,#BBDEFB);"><span style="width:36px;height:36px;background:#2196F3;color:#fff;border-radius:50%;display:inline-flex;align-items:center;justify-content:center;font-weight:bold;font-size:16px;flex-shrink:0;">第二步:</span><span style="font-size:17px;font-weight:700;color:#1565C0;">运行Bandit扫描</span></div><div style="padding:16px 20px;"><p>执行基础扫描命令:</p>
<div style="margin:16px 0;border-radius:8px;overflow:hidden;border:1px solid #E0E0E0;"><div style="background:#263238;color:#B0BEC5;padding:6px 16px;font-size:12px;font-family:Consolas,monospace;"><span style="text-transform:uppercase;letter-spacing:1px;">bash</span></div><pre style="background:#1E272E;color:#E0E0E0;padding:16px 20px;margin:0;overflow-x:auto;font-size:14px;line-height:1.7;font-family:Consolas,"Courier New",monospace;"><code>bandit -r .</code></pre></div>
<p>输出示例:</p>
<div style="margin:16px 0;border-radius:8px;overflow:hidden;border:1px solid #E0E0E0;"><div style="background:#263238;color:#B0BEC5;padding:6px 16px;font-size:12px;font-family:Consolas,monospace;"><span style="text-transform:uppercase;letter-spacing:1px;">text</span></div><pre style="background:#1E272E;color:#E0E0E0;padding:16px 20px;margin:0;overflow-x:auto;font-size:14px;line-height:1.7;font-family:Consolas,"Courier New",monospace;"><code>[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:
&gt;&gt; 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

&gt;&gt; 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

&gt;&gt; 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

&gt;&gt; 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

&gt;&gt; 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

&gt;&gt; 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)</code></pre></div>
<h3 id="第三步使用自定义配置优化扫描" style="color:#1976D2;margin-top:24px;">第三步:使用自定义配置优化扫描</h3>
<p>创建<code style="background:#F3E5F5;color:#6A1B9A;padding:1px 6px;border-radius:3px;font-size:0.9em;font-family:Consolas,monospace;">.bandit.yml</code>配置文件:</p></div></div>
# .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 修复漏洞:从扫描到安全代码

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

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

问题代码:

python
DB_PASSWORD = "SuperSecret123!"

修复代码:

python
import os

DB_PASSWORD = os.environ.get('DB_PASSWORD')
if not DB_PASSWORD:
    raise ValueError("DB_PASSWORD environment variable not set")

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

问题代码:

python
query = f"SELECT * FROM users WHERE username = '{user_input}'"
cursor.execute(query)

修复代码:

python
query = "SELECT * FROM users WHERE username = ?"
cursor.execute(query, (user_input,))

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

问题代码:

python
data = pickle.loads(b"malicious_payload")

修复代码:

python
import json

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

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

问题代码:

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

修复代码:

python
import bcrypt

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

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

问题代码:

python
response = requests.get('http://api.example.com/data', verify=False)

修复代码:

python
import requests
from requests.packages.urllib3.exceptions import InsecureRequestWarning

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

# 使用HTTPS并验证证书
response = requests.get('https://api.example.com/data', verify=True)

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

问题代码:

python
eval(user_code)

修复代码:

python
import ast

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

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

bash
bandit -r .

输出应该显示0个问题:

text
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分钟配置,换来的是代码安全的长期保障。

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

学习资源站

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

相关推荐

  • 你以为测试只看技术?面试官前列眼就淘汰了你_千锋教育 01职业形象决定薪资天花板2023年某招聘平台数据显示:面试前15秒,面试官对候选人的前列印象已经形成。后续的沟通,不过是在验证这个印象。软件测试工程师,这个常年被定义为"找bug的人"的岗位,薪资差距可以拉到3倍以上。同城同经验,有人月薪
  • 测试代码覆盖率:Jacoco与Istanbul实战,团队效率提升70%_千锋教育 01为什么覆盖率是团队的内耗黑洞代码覆盖率,这个看似简单的指标,正在吞噬团队效率。根据2023年某调研报告,67%的团队在覆盖率目标上存在分歧:开发说“我测了全部”,测试说“你漏了关键路径”。双方各执一词,根源在于——工具没选对,标准没对齐
  • 3步集成Bandit,你的Python测试代码漏洞无处遁形_千锋教育 01为什么测试代码是黑客的“后门”?测试代码——开发者眼中最安全的角落,却是黑客眼里最甜美的果实。2023年,某知名云服务商遭遇数据泄露,攻击者并非直接攻破生产环境,而是通过一个暴露的测试API端点,获取了数据库访问凭证。这个测试端点,本该
  • 面试官3秒刷掉90%简历?测试简历这样写,通过率翻5倍_千锋教育 01简历第一关:3秒法则,你踩了多少雷?面试官筛选一份简历的平均时间:6秒。前3秒决定去留。你的简历如果在前3秒没有抓住眼球,直接出局。数据告诉你真相:&#9658;85%的测试简历包含“熟悉软件测试流程”、“熟练掌握测试用例设计方法”等无
  • 数据驱动测试:1个框架让测试覆盖提升300%,代码量减少60%_千锋教育 01痛点:测试代码的“复制粘贴”地狱每个测试工程师都经历过这样的场景:测试一个登录功能,需要验证10组不同的用户名和密码。于是你机械地复制了10个测试方法,每个方法只改了输入参数和预期结果。代码膨胀到1000行,维护成本飙升,新增一个测试场
  • 网上资源多到爆炸,为什么90%的软件测试学员依然学不会?_千锋教育 01资源爆炸时代,为什么你还在原地踏步?打开浏览器,搜索“软件测试学习资源”,结果超过1亿条。B站上《0基础学软件测试》视频播放量破千万,知乎上“如何系统学习软件测试”问题有3000+回答。但现实很残酷:90%的自学者在3个月内放弃,87%