#!/usr/bin/env bash # 封版验收安全扫描手动清单脚本 # 运行环境:本地生产预览服务 http://localhost:3000 # 前置条件:npm run start 已启动在 3000 端口 set -euo pipefail BASE_URL="${BASE_URL:-http://localhost:3000}" REPORT_DIR="${REPORT_DIR:-release-acceptance-reports/$(date +%Y%m%d-%H%M%S)}" mkdir -p "$REPORT_DIR" echo "======================================" echo "安全扫描手动清单" echo "目标: $BASE_URL" echo "报告目录: $REPORT_DIR" echo "======================================" # SEC-01 / SEC-06: 依赖漏洞扫描 echo "[SEC-01] 运行 npm audit --production..." npm audit --audit-level moderate --registry=https://registry.npmjs.org/ > "$REPORT_DIR/50-npm-audit-final.log" 2>&1 || true # SEC-02: 安全响应头检查 echo "[SEC-02] 检查安全响应头..." curl -sI "$BASE_URL/" | grep -iE 'X-Content-Type-Options|X-Frame-Options|X-XSS-Protection|Strict-Transport-Security|Content-Security-Policy' > "$REPORT_DIR/51-security-headers.log" 2>&1 || true if [ ! -s "$REPORT_DIR/51-security-headers.log" ]; then echo "未检测到安全响应头" > "$REPORT_DIR/51-security-headers.log" fi # SEC-03: 认证绕过测试 echo "[SEC-03] 测试未授权访问 /admin 与 /api/admin/models..." { echo "GET $BASE_URL/admin" curl -s -o /dev/null -w "%{http_code}\n" "$BASE_URL/admin" echo "GET $BASE_URL/api/admin/models" curl -s -o /dev/null -w "%{http_code}\n" "$BASE_URL/api/admin/models" } > "$REPORT_DIR/52-auth-bypass.log" 2>&1 # SEC-04: XSS 过滤测试 echo "[SEC-04] 测试联系表单 XSS 过滤..." curl -s -X POST "$BASE_URL/api/contact" \ -H "Content-Type: application/json" \ -d '{"name":"XSS Test","email":"xss@test.com","phone":"13800138000","subject":"XSS","message":""}' \ > "$REPORT_DIR/53-xss-test.log" 2>&1 # SEC-05: SQLi 过滤测试 echo "[SEC-05] 测试联系表单 SQLi 过滤..." curl -s -X POST "$BASE_URL/api/contact" \ -H "Content-Type: application/json" \ -d '{"name":"SQLi Test","email":"sqli@test.com","phone":"13800138000","subject":"SQLi","message":"1\x27 OR \x271\x27=\x271"}' \ > "$REPORT_DIR/54-sqli-test.log" 2>&1 # SEC-06: JWT 校验测试 echo "[SEC-06] 测试 JWT 校验..." { echo "空 token:" curl -s -o /dev/null -w "%{http_code}\n" "$BASE_URL/api/admin/models" echo "无效 token:" curl -s -o /dev/null -w "%{http_code}\n" -H "Authorization: Bearer invalid-token" "$BASE_URL/api/admin/models" echo "过期 token (expired signature):" curl -s -o /dev/null -w "%{http_code}\n" -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyLCJleHAiOjE1MTYyMzkwMjJ9.4AdcjS3X_FSn0FxL5XfKX5qJ6tE4ZfG8h0e8_xW3V7o" "$BASE_URL/api/admin/models" } > "$REPORT_DIR/55-jwt-test.log" 2>&1 # SEC-07: 敏感信息泄露扫描 echo "[SEC-07] 扫描源码中的硬编码敏感信息..." grep -R -n -E "password|secret|token|api[_-]?key" \ --include="*.ts" --include="*.tsx" \ src/ \ | grep -v "\.env" \ | grep -v "process\.env" \ | grep -v "// " \ | head -100 \ > "$REPORT_DIR/56-secrets-scan.log" 2>&1 || true if [ ! -s "$REPORT_DIR/56-secrets-scan.log" ]; then echo "未发现明显硬编码敏感信息" > "$REPORT_DIR/56-secrets-scan.log" fi echo "======================================" echo "安全扫描完成,产物保存在 $REPORT_DIR" echo "======================================"