L’interface est localisée ; les présentations et documents des Skills sont traduits automatiquement par IA dans votre langue. Le code, les commandes, chemins et termes techniques restent en version originale, et le document de l’auteur fait foi.
Explorer les Skills
Développement · SKILL.md

performing-api-security-testing-with-postman

performing-api-security-testing-with-postman

使用 Postman 构建测试集合,执行结构化 API 安全测试,覆盖 OWASP API 安全 Top 10 漏洞, 包括认证绕过、授权缺陷、注入和数据暴露。测试人员创建包含多个用户角色的环境, 编写自动化安全验证测试脚本,并将 Postman 与 OWASP ZAP 和 Newman 集成以进行 CI/CD 安全测试。 当请求涉及 Postman 安全测试、API 安全集合、自动化 API 测试或使用 Postman 进行 OWASP API 测试时触发。

Independent GitHub snapshot · Automated classification · Original documentation governs

Documentation de la Skill

GitHub

name: performing-api-security-testing-with-postman description: > 使用 Postman 构建测试集合,执行结构化 API 安全测试,覆盖 OWASP API 安全 Top 10 漏洞, 包括认证绕过、授权缺陷、注入和数据暴露。测试人员创建包含多个用户角色的环境, 编写自动化安全验证测试脚本,并将 Postman 与 OWASP ZAP 和 Newman 集成以进行 CI/CD 安全测试。 当请求涉及 Postman 安全测试、API 安全集合、自动化 API 测试或使用 Postman 进行 OWASP API 测试时触发。 domain: cybersecurity subdomain: api-security tags: [api-security, postman, owasp, automated-testing, security-validation] version: 1.0.0 author: mahipal license: Apache-2.0

使用 Postman 执行 API 安全测试

适用场景

  • 构建覆盖 OWASP API 安全 Top 10 的可重复 API 安全测试套件
  • 创建通过 Newman 在 CI/CD 流水线中运行的自动化安全回归测试
  • 系统地跨多个用户角色测试 API 认证和授权
  • 将 Postman 与 OWASP ZAP 代理集成,进行手动和自动化安全测试组合
  • 在新 API 端点部署前建立基线安全测试集合

不适用于 未经授权对生产 API 使用。Postman 安全测试涉及发送潜在恶意载荷。

前置条件

  • 在活跃工作区中使用 Postman 桌面或 Web 应用
  • 目标 API 具有用于集合导入的 OpenAPI/Swagger 规范
  • 至少三个角色的测试账户:未认证用户、普通用户、管理员
  • 已安装 Newman CLI 用于 CI/CD 集成:npm install -g newman
  • OWASP ZAP 配置为本地代理(localhost:8080)用于 Postman 代理集成
  • 包含基础 URL、令牌和测试数据的 API 环境变量

工作流程

步骤 1:环境和集合设置

为多角色测试创建 Postman 环境:

// 环境:API 安全测试 - 普通用户
{
    "values": [
        {"key": "base_url", "value": "https://target-api.example.com/api/v1"},
        {"key": "auth_token", "value": ""},
        {"key": "user_email", "value": "regular@test.com"},
        {"key": "user_password", "value": "TestPass123!"},
        {"key": "user_id", "value": ""},
        {"key": "other_user_id", "value": "1002"},
        {"key": "admin_endpoint", "value": "/admin/users"},
        {"key": "test_order_id", "value": ""},
        {"key": "other_user_order_id", "value": "5003"}
    ]
}

用于自动认证的前置请求脚本:

// 集合级前置请求脚本,用于自动登录
if (!pm.environment.get("auth_token") || pm.environment.get("token_expired")) {
    const loginRequest = {
        url: pm.environment.get("base_url") + "/auth/login",
        method: "POST",
        header: {"Content-Type": "application/json"},
        body: {
            mode: "raw",
            raw: JSON.stringify({
                email: pm.environment.get("user_email"),
                password: pm.environment.get("user_password")
            })
        }
    };

    pm.sendRequest(loginRequest, (err, res) => {
        if (!err && res.code === 200) {
            const token = res.json().access_token;
            pm.environment.set("auth_token", token);
            pm.environment.set("user_id", res.json().user.id);
        }
    });
}

步骤 2:BOLA(API1)测试集合

// 测试:访问其他用户的个人资料(BOLA)
// 请求:GET {{base_url}}/users/{{other_user_id}}
// 认证:Bearer {{auth_token}}

// 测试脚本:
pm.test("BOLA:不能访问其他用户资料", function() {
    pm.expect(pm.response.code).to.be.oneOf([401, 403]);
});

pm.test("BOLA:拒绝时无用户数据泄露", function() {
    if (pm.response.code === 200) {
        const body = pm.response.json();
        pm.expect(body).to.not.have.property("email");
        pm.expect(body).to.not.have.property("phone");
        pm.expect(body).to.not.have.property("address");
        // 如果返回了完整资料,标记为 BOLA 漏洞
        console.error("BOLA 漏洞:返回了其他用户的完整资料");
    }
});

// 测试:访问其他用户的订单
// 请求:GET {{base_url}}/orders/{{other_user_order_id}}
pm.test("BOLA:不能访问其他用户订单", function() {
    pm.expect(pm.response.code).to.be.oneOf([401, 403, 404]);
});

// 测试:修改其他用户的资源
// 请求:PATCH {{base_url}}/users/{{other_user_id}}
// 请求体:{"name": "Hacked"}
pm.test("BOLA:不能修改其他用户资料", function() {
    pm.expect(pm.response.code).to.be.oneOf([401, 403]);
});

步骤 3:认证(API2)测试集合

// 测试:令牌验证
// 请求:GET {{base_url}}/users/me
// 认证:Bearer invalid_token_value

pm.test("认证:无效令牌被拒绝", function() {
    pm.expect(pm.response.code).to.be.oneOf([401, 403]);
});

// 测试:过期令牌处理
// 请求:GET {{base_url}}/users/me
// 认证:Bearer {{expired_token}}

pm.test("认证:过期令牌被拒绝", function() {
    pm.expect(pm.response.code).to.equal(401);
});

// 测试:缺少认证
// 请求:GET {{base_url}}/users/me
// 认证:无

pm.test("认证:未认证请求被拒绝", function() {
    pm.expect(pm.response.code).to.equal(401);
});

// 测试:登录中的 SQL 注入
// 请求:POST {{base_url}}/auth/login
// 请求体:{"email": "' OR 1=1--", "password": "test"}

pm.test("认证:登录中的 SQL 注入被拒绝", function() {
    pm.expect(pm.response.code).to.not.equal(200);
    pm.expect(pm.response.text()).to.not.include("token");
});

// 测试:账号枚举
// 前置:使用有效邮箱+错误密码发送,然后使用无效邮箱+错误密码发送
pm.test("认证:无账号枚举", function() {
    // 与存储的有效邮箱尝试响应进行比较
    const validEmailResponse = pm.environment.get("valid_email_response");
    const currentResponse = pm.response.text();
    pm.expect(currentResponse).to.equal(validEmailResponse);
});

步骤 4:数据暴露(API3)和 BFLA(API5)测试

// 测试:过度数据暴露检查
// 请求:GET {{base_url}}/users/me

pm.test("数据暴露:响应中无敏感字段", function() {
    const sensitiveFields = [
        "password", "password_hash", "passwordHash",
        "ssn", "social_security", "credit_card",
        "api_key", "secret_key", "mfa_secret",
        "refresh_token", "session_id"
    ];
    const responseText = pm.response.text().toLowerCase();
    sensitiveFields.forEach(field => {
        pm.expect(responseText).to.not.include('"' + field + '"');
    });
});

pm.test("数据暴露:安全响应头存在", function() {
    pm.expect(pm.response.headers.has("X-Content-Type-Options")).to.be.true;
    pm.expect(pm.response.headers.has("X-Frame-Options")).to.be.true;
    pm.expect(pm.response.headers.get("X-Content-Type-Options")).to.equal("nosniff");
});

pm.test("数据暴露:无服务器信息泄露", function() {
    pm.expect(pm.response.headers.has("Server")).to.be.false;
    pm.expect(pm.response.headers.has("X-Powered-By")).to.be.false;
});

// 测试:BFLA - 管理员端点访问
// 请求:GET {{base_url}}{{admin_endpoint}}
// 认证:Bearer {{auth_token}}(普通用户)

pm.test("BFLA:普通用户不能访问管理员端点", function() {
    pm.expect(pm.response.code).to.be.oneOf([401, 403]);
});

// 测试:BFLA - 管理员功能执行
// 请求:DELETE {{base_url}}/users/{{other_user_id}}
// 认证:Bearer {{auth_token}}(普通用户)

pm.test("BFLA:普通用户不能删除其他用户", function() {
    pm.expect(pm.response.code).to.be.oneOf([401, 403]);
});

步骤 5:批量赋值和限速测试

// 测试:通过资料更新进行批量赋值
// 请求:PUT {{base_url}}/users/me
// 请求体:{"name": "Test", "role": "admin", "is_admin": true}

pm.test("批量赋值:角色字段不被接受", function() {
    if (pm.response.code === 200) {
        const user = pm.response.json();
        pm.expect(user.role).to.not.equal("admin");
        pm.expect(user.is_admin).to.not.equal(true);
    }
});

// 测试:限速执行
// 此测试应在高迭代次数的集合运行器中运行

pm.test("限速:超过限制时返回 429", function() {
    // 此测试期望在多次迭代后触发限速
    const iterationCount = pm.info.iteration;
    if (iterationCount > 50) {
        // 50 次迭代后应看到限速
        if (pm.response.code === 429) {
            pm.expect(pm.response.headers.has("Retry-After")).to.be.true;
            console.log("在第 " + iterationCount + " 次迭代时触发限速");
        }
    }
});

// 测试:限速响应头存在
pm.test("限速:限速响应头存在", function() {
    const hasRateHeaders = pm.response.headers.has("X-RateLimit-Limit") ||
                           pm.response.headers.has("X-Rate-Limit-Limit") ||
                           pm.response.headers.has("RateLimit-Limit");
    pm.expect(hasRateHeaders).to.be.true;
});

步骤 6:Newman CI/CD 集成

# 通过 Newman CLI 运行安全测试集合
newman run "API-Security-Tests.postman_collection.json" \
    --environment "Security-Test-Environment.postman_environment.json" \
    --reporters cli,htmlextra,junit \
    --reporter-htmlextra-export ./reports/security-test-report.html \
    --reporter-junit-export ./reports/security-test-results.xml \
    --iteration-count 1 \
    --timeout-request 10000 \
    --delay-request 100 \
    --bail

# 使用不同用户角色运行
for role in "regular_user" "admin_user" "unauthenticated"; do
    echo "使用角色测试:$role"
    newman run "API-Security-Tests.postman_collection.json" \
        --environment "Security-Test-${role}.postman_environment.json" \
        --reporters cli,junit \
        --reporter-junit-export "./reports/security-${role}.xml"
done

GitHub Actions 集成:

# .github/workflows/api-security-test.yml
name: API Security Tests
on:
  pull_request:
    paths: ['src/api/**', 'openapi.yaml']

jobs:
  security-test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
      - run: npm install -g newman newman-reporter-htmlextra
      - name: Run API Security Tests
        run: |
          newman run tests/postman/api-security.json \
            --environment tests/postman/env-staging.json \
            --reporters cli,htmlextra,junit \
            --reporter-htmlextra-export reports/security.html \
            --reporter-junit-export reports/security.xml
      - uses: actions/upload-artifact@v4
        if: always()
        with:
          name: security-reports
          path: reports/

核心概念

术语定义
Postman 集合(Postman Collection)包含测试脚本的有组织 API 请求组,可共享、版本控制和自动执行
NewmanPostman 的命令行伴侣工具,可在 CI/CD 流水线中运行集合并生成测试报告
前置请求脚本(Pre-request Script)在 Postman 请求前执行的 JavaScript 代码,用于动态认证和测试数据设置
测试脚本(Test Script)在 Postman 响应后执行的 JavaScript 代码,用于针对响应验证安全断言
集合运行器(Collection Runner)Postman 功能,按顺序执行集合中所有请求,可配置迭代次数和延迟
环境变量(Environment Variables)限定在 Postman 环境范围内的键值对,用于针对不同目标、角色和配置参数化请求

工具与系统

  • Postman:用于构建、测试和记录 API 的平台,内置脚本和集合管理功能
  • Newman:支持多种报告格式(HTML、JUnit、JSON)用于 CI/CD 集成的 Postman 集合 CLI 运行器
  • OWASP ZAP:可配置为 Postman 代理的开源安全代理,用于被动扫描所有请求
  • newman-reporter-htmlextra:Newman 的增强 HTML 报告器,生成包含请求/响应数据的详细测试报告
  • Postman Flows:用于链接复杂安全测试序列和条件逻辑的可视化工作流构建器

常见场景

场景:CI/CD 的 API 安全回归套件

场景背景:一个开发团队每两周发布 API 更新。他们需要一个自动化安全测试套件,在每次拉取请求时运行,以在合并前发现授权和认证回归问题。

方法:

  1. 将 OpenAPI 规范导入 Postman 生成包含所有端点的基础集合
  2. 创建三个环境:未认证、普通用户、管理员,各有相应凭据
  3. 为每个请求添加安全测试脚本:BOLA 检查、认证验证、数据暴露扫描、请求头安全
  4. 创建专用"安全测试"文件夹,包含注入载荷、批量赋值测试和限速检查
  5. 将集合和环境导出到代码库
  6. 在 GitHub Actions 中配置 Newman,在每个影响 API 代码的 PR 时运行
  7. 设置流水线在任何安全测试失败时中止,阻止合并

常见陷阱:

  • 在集合中硬编码认证令牌,而不是使用前置请求脚本动态生成令牌
  • 未使用所有用户角色测试——只测试认证与未认证会遗漏基于角色的授权问题
  • 针对生产环境而非预发布环境运行安全测试
  • 添加新端点时未更新集合,导致覆盖存在空白
  • 在 CI/CD 中忽略 Newman 退出码,允许失败的安全测试静默通过

输出格式

## API 安全测试报告 - Postman/Newman

**集合**:API 安全测试 v2.3
**环境**:预发布 - 普通用户
**日期**:2024-12-15
**总请求数**:85
**总测试数**:234
**通过**:219
**失败**:15

### 失败测试摘要

| # | 请求 | 测试名称 | 严重性 |
|---|---------|-----------|----------|
| 1 | GET /users/1002 | BOLA:不能访问其他用户资料 | 严重 |
| 2 | GET /orders/5003 | BOLA:不能访问其他用户订单 | 严重 |
| 3 | GET /admin/users | BFLA:普通用户不能访问管理员端点 | 严重 |
| 4 | PUT /users/me | 批量赋值:角色字段不被接受 | 高 |
| 5 | GET /users/me | 数据暴露:响应中无敏感字段 | 高 |
| 6 | POST /auth/login | 认证:无账号枚举 | 中 |
| ... | ... | ... | ... |

### 建议
1. 修复 /users/{id} 和 /orders/{id} 的 BOLA——添加对象级授权检查
2. 修复 /admin/users 的 BFLA——执行基于角色的访问控制中间件
3. 修复 PUT /users/me 的批量赋值——实现字段允许列表
4. 从用户序列化中删除 password_hash 和 mfa_secret
5. 标准化登录错误消息以防止账号枚举
Skills enregistrées