performing-api-security-testing-with-postman

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Performing API Security Testing with Postman

使用Postman执行API安全测试

When to Use

使用场景

  • Building repeatable API security test suites for OWASP API Security Top 10 coverage
  • Creating automated security regression tests that run in CI/CD pipelines via Newman
  • Testing API authentication and authorization across multiple user roles systematically
  • Integrating Postman with OWASP ZAP proxy for combined manual and automated security testing
  • Establishing a baseline security test collection for new API endpoints before deployment
Do not use against production APIs without authorization. Postman security testing involves sending potentially malicious payloads.
  • 构建可重复的API安全测试套件,覆盖OWASP API Security Top 10漏洞
  • 创建可通过Newman在CI/CD流水线中运行的自动化安全回归测试
  • 系统地测试多用户角色下的API身份验证与授权机制
  • 将Postman与OWASP ZAP代理集成,结合手动与自动化安全测试
  • 在新API端点部署前建立基线安全测试集合
注意:未经授权请勿针对生产API执行测试。Postman安全测试会发送潜在恶意负载。

Prerequisites

前提条件

  • Postman Desktop or web application with an active workspace
  • Target API with OpenAPI/Swagger specification for collection import
  • Test accounts for at least three roles: unauthenticated, regular user, admin
  • Newman CLI installed for CI/CD integration:
    npm install -g newman
  • OWASP ZAP configured as local proxy (localhost:8080) for Postman proxy integration
  • API environment variables for base URL, tokens, and test data
  • 拥有活跃工作区的Postman桌面版或网页版应用
  • 带有OpenAPI/Swagger规范的目标API,用于导入集合
  • 至少三个角色的测试账号:未认证用户、普通用户、管理员
  • 安装用于CI/CD集成的Newman CLI:
    npm install -g newman
  • 配置OWASP ZAP作为本地代理(localhost:8080),用于Postman代理集成
  • 包含基础URL、令牌和测试数据的API环境变量

Workflow

工作流程

Step 1: Environment and Collection Setup

步骤1:环境与集合设置

Create Postman environments for multi-role testing:
json
// Environment: API Security Test - Regular User
{
    "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"}
    ]
}
Pre-request script for automatic authentication:
javascript
// Collection-level pre-request script for auto-login
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);
        }
    });
}
创建用于多角色测试的Postman环境:
json
// Environment: API Security Test - Regular User
{
    "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"}
    ]
}
自动身份验证的预请求脚本:
javascript
// Collection-level pre-request script for auto-login
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);
        }
    });
}

Step 2: BOLA (API1) Test Collection

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

javascript
// Test: Access other user's profile (BOLA)
// Request: GET {{base_url}}/users/{{other_user_id}}
// Auth: Bearer {{auth_token}}

// Test script:
pm.test("BOLA: Cannot access other user profile", function() {
    pm.expect(pm.response.code).to.be.oneOf([401, 403]);
});

pm.test("BOLA: No user data leaked on denial", 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");
        // Flag as BOLA if full profile returned
        console.error("BOLA VULNERABILITY: Full profile returned for other user");
    }
});

// Test: Access other user's order
// Request: GET {{base_url}}/orders/{{other_user_order_id}}
pm.test("BOLA: Cannot access other user order", function() {
    pm.expect(pm.response.code).to.be.oneOf([401, 403, 404]);
});

// Test: Modify other user's resource
// Request: PATCH {{base_url}}/users/{{other_user_id}}
// Body: {"name": "Hacked"}
pm.test("BOLA: Cannot modify other user profile", function() {
    pm.expect(pm.response.code).to.be.oneOf([401, 403]);
});
javascript
// Test: Access other user's profile (BOLA)
// Request: GET {{base_url}}/users/{{other_user_id}}
// Auth: Bearer {{auth_token}}

// Test script:
pm.test("BOLA: Cannot access other user profile", function() {
    pm.expect(pm.response.code).to.be.oneOf([401, 403]);
});

pm.test("BOLA: No user data leaked on denial", 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");
        // Flag as BOLA if full profile returned
        console.error("BOLA VULNERABILITY: Full profile returned for other user");
    }
});

// Test: Access other user's order
// Request: GET {{base_url}}/orders/{{other_user_order_id}}
pm.test("BOLA: Cannot access other user order", function() {
    pm.expect(pm.response.code).to.be.oneOf([401, 403, 404]);
});

// Test: Modify other user's resource
// Request: PATCH {{base_url}}/users/{{other_user_id}}
// Body: {"name": "Hacked"}
pm.test("BOLA: Cannot modify other user profile", function() {
    pm.expect(pm.response.code).to.be.oneOf([401, 403]);
});

Step 3: Authentication (API2) Test Collection

步骤3:身份验证(API2)测试集合

javascript
// Test: Token validation
// Request: GET {{base_url}}/users/me
// Auth: Bearer invalid_token_value

pm.test("Auth: Invalid token rejected", function() {
    pm.expect(pm.response.code).to.be.oneOf([401, 403]);
});

// Test: Expired token handling
// Request: GET {{base_url}}/users/me
// Auth: Bearer {{expired_token}}

pm.test("Auth: Expired token rejected", function() {
    pm.expect(pm.response.code).to.equal(401);
});

// Test: Missing authentication
// Request: GET {{base_url}}/users/me
// Auth: None

pm.test("Auth: Unauthenticated request rejected", function() {
    pm.expect(pm.response.code).to.equal(401);
});

// Test: SQL injection in login
// Request: POST {{base_url}}/auth/login
// Body: {"email": "' OR 1=1--", "password": "test"}

pm.test("Auth: SQLi in login rejected", function() {
    pm.expect(pm.response.code).to.not.equal(200);
    pm.expect(pm.response.text()).to.not.include("token");
});

// Test: Account enumeration
// Pre-request: Send login with valid email + wrong password, then invalid email + wrong password
pm.test("Auth: No account enumeration", function() {
    // Compare with stored response from valid email attempt
    const validEmailResponse = pm.environment.get("valid_email_response");
    const currentResponse = pm.response.text();
    pm.expect(currentResponse).to.equal(validEmailResponse);
});
javascript
// Test: Token validation
// Request: GET {{base_url}}/users/me
// Auth: Bearer invalid_token_value

pm.test("Auth: Invalid token rejected", function() {
    pm.expect(pm.response.code).to.be.oneOf([401, 403]);
});

// Test: Expired token handling
// Request: GET {{base_url}}/users/me
// Auth: Bearer {{expired_token}}

pm.test("Auth: Expired token rejected", function() {
    pm.expect(pm.response.code).to.equal(401);
});

// Test: Missing authentication
// Request: GET {{base_url}}/users/me
// Auth: None

pm.test("Auth: Unauthenticated request rejected", function() {
    pm.expect(pm.response.code).to.equal(401);
});

// Test: SQL injection in login
// Request: POST {{base_url}}/auth/login
// Body: {"email": "' OR 1=1--", "password": "test"}

pm.test("Auth: SQLi in login rejected", function() {
    pm.expect(pm.response.code).to.not.equal(200);
    pm.expect(pm.response.text()).to.not.include("token");
});

// Test: Account enumeration
// Pre-request: Send login with valid email + wrong password, then invalid email + wrong password
pm.test("Auth: No account enumeration", function() {
    // Compare with stored response from valid email attempt
    const validEmailResponse = pm.environment.get("valid_email_response");
    const currentResponse = pm.response.text();
    pm.expect(currentResponse).to.equal(validEmailResponse);
});

Step 4: Data Exposure (API3) and BFLA (API5) Tests

步骤4:数据泄露(API3)与BFLA(API5)测试

javascript
// Test: Excessive data exposure check
// Request: GET {{base_url}}/users/me

pm.test("Data Exposure: No sensitive fields in response", 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("Data Exposure: Security headers present", 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("Data Exposure: No server info leaked", function() {
    pm.expect(pm.response.headers.has("Server")).to.be.false;
    pm.expect(pm.response.headers.has("X-Powered-By")).to.be.false;
});

// Test: BFLA - Admin endpoint access
// Request: GET {{base_url}}{{admin_endpoint}}
// Auth: Bearer {{auth_token}} (regular user)

pm.test("BFLA: Regular user cannot access admin endpoint", function() {
    pm.expect(pm.response.code).to.be.oneOf([401, 403]);
});

// Test: BFLA - Admin function execution
// Request: DELETE {{base_url}}/users/{{other_user_id}}
// Auth: Bearer {{auth_token}} (regular user)

pm.test("BFLA: Regular user cannot delete other users", function() {
    pm.expect(pm.response.code).to.be.oneOf([401, 403]);
});
javascript
// Test: Excessive data exposure check
// Request: GET {{base_url}}/users/me

pm.test("Data Exposure: No sensitive fields in response", 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("Data Exposure: Security headers present", 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("Data Exposure: No server info leaked", function() {
    pm.expect(pm.response.headers.has("Server")).to.be.false;
    pm.expect(pm.response.headers.has("X-Powered-By")).to.be.false;
});

// Test: BFLA - Admin endpoint access
// Request: GET {{base_url}}{{admin_endpoint}}
// Auth: Bearer {{auth_token}} (regular user)

pm.test("BFLA: Regular user cannot access admin endpoint", function() {
    pm.expect(pm.response.code).to.be.oneOf([401, 403]);
});

// Test: BFLA - Admin function execution
// Request: DELETE {{base_url}}/users/{{other_user_id}}
// Auth: Bearer {{auth_token}} (regular user)

pm.test("BFLA: Regular user cannot delete other users", function() {
    pm.expect(pm.response.code).to.be.oneOf([401, 403]);
});

Step 5: Mass Assignment and Rate Limiting Tests

步骤5:批量赋值与速率限制测试

javascript
// Test: Mass assignment via profile update
// Request: PUT {{base_url}}/users/me
// Body: {"name": "Test", "role": "admin", "is_admin": true}

pm.test("Mass Assignment: Role field not accepted", 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);
    }
});

// Test: Rate limiting enforcement
// This test should be run with the Collection Runner at high iteration count

pm.test("Rate Limiting: Returns 429 when limit exceeded", function() {
    // This test expects to be rate-limited after many iterations
    const iterationCount = pm.info.iteration;
    if (iterationCount > 50) {
        // After 50 iterations, we should see rate limiting
        if (pm.response.code === 429) {
            pm.expect(pm.response.headers.has("Retry-After")).to.be.true;
            console.log("Rate limiting enforced at iteration " + iterationCount);
        }
    }
});

// Test: Rate limit headers present
pm.test("Rate Limiting: Rate limit headers present", 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;
});
javascript
// Test: Mass assignment via profile update
// Request: PUT {{base_url}}/users/me
// Body: {"name": "Test", "role": "admin", "is_admin": true}

pm.test("Mass Assignment: Role field not accepted", 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);
    }
});

// Test: Rate limiting enforcement
// This test should be run with the Collection Runner at high iteration count

pm.test("Rate Limiting: Returns 429 when limit exceeded", function() {
    // This test expects to be rate-limited after many iterations
    const iterationCount = pm.info.iteration;
    if (iterationCount > 50) {
        // After 50 iterations, we should see rate limiting
        if (pm.response.code === 429) {
            pm.expect(pm.response.headers.has("Retry-After")).to.be.true;
            console.log("Rate limiting enforced at iteration " + iterationCount);
        }
    }
});

// Test: Rate limit headers present
pm.test("Rate Limiting: Rate limit headers present", 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;
});

Step 6: Newman CI/CD Integration

步骤6:Newman CI/CD集成

bash
undefined
bash
undefined

Run security test collection via Newman CLI

Run security test collection via 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
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

Run with different user roles

Run with different user roles

for role in "regular_user" "admin_user" "unauthenticated"; do echo "Testing with role: $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 Integration:**
```yaml
for role in "regular_user" "admin_user" "unauthenticated"; do echo "Testing with role: $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集成:**
```yaml

.github/workflows/api-security-test.yml

.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/
undefined
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/
undefined

Key Concepts

核心概念

TermDefinition
Postman CollectionOrganized group of API requests with test scripts that can be shared, version-controlled, and executed automatically
NewmanCommand-line companion for Postman that enables running collections in CI/CD pipelines and generating test reports
Pre-request ScriptJavaScript code that executes before a Postman request, used for dynamic authentication and test data setup
Test ScriptJavaScript code that executes after a Postman response, used to validate security assertions against the response
Collection RunnerPostman feature that executes all requests in a collection sequentially with configurable iterations and delays
Environment VariablesKey-value pairs scoped to a Postman environment that parameterize requests for different targets, roles, and configurations
术语定义
Postman Collection一组组织有序的API请求,附带测试脚本,可共享、版本控制并自动执行
NewmanPostman的命令行工具,支持在CI/CD流水线中运行集合并生成测试报告
Pre-request Script在Postman请求执行前运行的JavaScript代码,用于动态身份验证和测试数据设置
Test Script在Postman响应返回后运行的JavaScript代码,用于针对响应验证安全断言
Collection RunnerPostman的功能,可按顺序执行集合中的所有请求,支持配置迭代次数和延迟
Environment Variables作用于Postman环境的键值对,用于为不同目标、角色和配置参数化请求

Tools & Systems

工具与系统

  • Postman: API platform for building, testing, and documenting APIs with built-in scripting and collection management
  • Newman: CLI runner for Postman collections supporting multiple reporters (HTML, JUnit, JSON) for CI/CD integration
  • OWASP ZAP: Open-source security proxy that can be configured as Postman's proxy to scan all requests passively
  • newman-reporter-htmlextra: Enhanced HTML reporter for Newman that generates detailed test reports with request/response data
  • Postman Flows: Visual workflow builder for chaining complex security test sequences with conditional logic
  • Postman: API平台,用于构建、测试和文档化API,内置脚本和集合管理功能
  • Newman: Postman集合的CLI运行器,支持多种报告格式(HTML、JUnit、JSON),用于CI/CD集成
  • OWASP ZAP: 开源安全代理,可配置为Postman的代理,被动扫描所有请求
  • newman-reporter-htmlextra: Newman的增强HTML报告器,生成包含请求/响应数据的详细测试报告
  • Postman Flows: 可视化工作流构建器,用于通过条件逻辑链接复杂的安全测试序列

Common Scenarios

常见场景

Scenario: API Security Regression Suite for CI/CD

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

Context: A development team releases API updates bi-weekly. They need an automated security test suite that runs on every pull request to catch authorization and authentication regressions before merge.
Approach:
  1. Import the OpenAPI spec into Postman to generate a base collection with all endpoints
  2. Create three environments: unauthenticated, regular user, admin with appropriate credentials
  3. Add security test scripts to each request: BOLA checks, auth validation, data exposure scanning, header security
  4. Create a dedicated "Security Tests" folder with injection payloads, mass assignment tests, and rate limit checks
  5. Export the collection and environments to the repository
  6. Configure Newman in GitHub Actions to run on every PR affecting API code
  7. Set the pipeline to fail on any security test failure, blocking the merge
Pitfalls:
  • Hardcoding authentication tokens in collections instead of using pre-request scripts for dynamic token generation
  • Not testing with all user roles - only testing authenticated vs unauthenticated misses role-based authorization issues
  • Running security tests against production instead of staging environments
  • Not updating the collection when new endpoints are added, leaving gaps in coverage
  • Ignoring Newman exit codes in CI/CD, allowing failing security tests to pass silently
背景:开发团队每两周发布一次API更新。他们需要一个自动化安全测试套件,在每次拉取请求时运行,在合并前捕获授权和身份验证回归问题。
实施步骤:
  1. 将OpenAPI规范导入Postman,生成包含所有端点的基础集合
  2. 创建三个环境:未认证用户、普通用户、管理员,并配置相应凭证
  3. 为每个请求添加安全测试脚本:BOLA检查、身份验证验证、数据泄露扫描、头部安全检测
  4. 创建专门的“安全测试”文件夹,包含注入负载、批量赋值测试和速率限制检查
  5. 将集合和环境导出到代码仓库
  6. 在GitHub Actions中配置Newman,在所有影响API代码的PR上运行测试
  7. 设置流水线在任何安全测试失败时终止,阻止合并
常见陷阱:
  • 在集合中硬编码身份验证令牌,而非使用预请求脚本动态生成令牌
  • 未测试所有用户角色——仅测试已认证与未认证用户会遗漏基于角色的授权问题
  • 在生产环境而非预发布环境运行安全测试
  • 添加新端点时未更新集合,导致测试覆盖存在缺口
  • 在CI/CD中忽略Newman退出码,允许失败的安全测试静默通过

Output Format

输出格式

undefined
undefined

API Security Test Report - Postman/Newman

API安全测试报告 - Postman/Newman

Collection: API Security Tests v2.3 Environment: Staging - Regular User Date: 2024-12-15 Total Requests: 85 Total Tests: 234 Passed: 219 Failed: 15
集合: API安全测试 v2.3 环境: 预发布环境 - 普通用户 日期: 2024-12-15 总请求数: 85 总测试数: 234 通过: 219 失败: 15

Failed Tests Summary

失败测试摘要

#RequestTest NameSeverity
1GET /users/1002BOLA: Cannot access other user profileCritical
2GET /orders/5003BOLA: Cannot access other user orderCritical
3GET /admin/usersBFLA: Regular user cannot access admin endpointCritical
4PUT /users/meMass Assignment: Role field not acceptedHigh
5GET /users/meData Exposure: No sensitive fields in responseHigh
6POST /auth/loginAuth: No account enumerationMedium
............
#请求测试名称严重程度
1GET /users/1002BOLA: 无法访问其他用户的个人资料关键
2GET /orders/5003BOLA: 无法访问其他用户的订单关键
3GET /admin/usersBFLA: 普通用户无法访问管理员端点关键
4PUT /users/me批量赋值: 角色字段不被接受
5GET /users/me数据泄露: 响应中无敏感字段
6POST /auth/login身份验证: 无账号枚举漏洞
............

Recommendations

建议

  1. Fix BOLA on /users/{id} and /orders/{id} - add object-level authorization checks
  2. Fix BFLA on /admin/users - enforce role-based access control middleware
  3. Fix mass assignment on PUT /users/me - implement field allowlist
  4. Remove password_hash and mfa_secret from user serialization
  5. Standardize login error messages to prevent account enumeration
undefined
  1. 修复/users/{id}和/orders/{id}的BOLA漏洞——添加对象级授权检查
  2. 修复/admin/users的BFLA漏洞——实施基于角色的访问控制中间件
  3. 修复PUT /users/me的批量赋值漏洞——实现字段白名单
  4. 从用户序列化中移除password_hash和mfa_secret字段
  5. 标准化登录错误信息,防止账号枚举
undefined