关于 supabase-extract-db-string
supabase-extract-db-string 是安全审计技能,用于扫描客户端代码中暴露的 PostgreSQL 连接字符串和数据库凭据,并将发现及证据记录到审计上下文文件。
主要功能
- 01检测完整 PostgreSQL 连接字符串
- 02查找泄露的数据库环境变量
- 03标记单独暴露的凭据
- 04扫描客户端 ORM 配置
- 05记录发现与证据
适用场景
- 01审计 Web 应用中的数据库凭据泄露
- 02上线前检查客户端代码
- 03调查疑似 Supabase 数据库访问问题
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ yoanbernabeu/ supabase-pentest-skills --skill supabase-extract-db-string安装后在 Claude Code 中输入/supabase-extract-db-string确认已加载。
详细介绍
数据库连接字符串检测
🔴 严重:需要渐进式更新文件
你必须边执行边写入上下文文件,而不是只在最后写入。
- 每次发现后立即写入
.sb-pentest-context.json- 每项操作前后都记录到
.sb-pentest-audit.log- 不要等到技能执行完成后才更新文件
- 如果技能崩溃或中断,之前的所有发现都必须已经保存
这不是可选项。未能渐进式写入属于严重错误。
此技能用于检测 PostgreSQL 数据库连接字符串是否意外暴露在客户端代码中。
何时使用此技能
- 作为每次安全审计的一部分
- 在代码上线前进行审查时
- 怀疑存在 Supabase 数据库访问时
前提条件
- 可以访问目标应用程序
- 已完成 Supabase 检测(如有需要会自动调用)
为什么这很重要
暴露数据库连接字符串会导致:
| 影响 | 说明 |
|---|---|
| 🔴 直接访问数据库 | 绕过 API,直接连接 PostgreSQL |
| 🔴 完整数据访问权限 | 无需 RLS 即可读取/写入所有数据 |
| 🔴 架构访问权限 | 查看并修改数据库结构 |
| 🔴 用户枚举 | 直接访问 auth.users 表 |
这是 P0(严重)级发现,需要立即处理。
连接字符串模式
Supabase 数据库 URL
postgresql://postgres:[password]@db.[project-ref].supabase.co:5432/postgres
连接字符串组成部分
| 组成部分 | 示例 | 敏感度 |
|---|---|---|
| 主机 | db.abc123.supabase.co | 中 |
| 端口 | 5432 | 低 |
| 数据库 | postgres | 低 |
| 用户名 | postgres | 中 |
| 密码 | [your-password] | 🔴 严重 |
Pooler 连接(Supavisor)
postgresql://postgres.[project-ref]:[password]@aws-0-us-east-1.pooler.supabase.com:6543/postgres
检测模式
1. 完整连接字符串
// ❌ CRITICAL - Full connection string
const dbUrl = 'postgresql://postgres:[email protected]:5432/postgres'
2. 环境变量泄露
// ❌ Exposed in client bundle
process.env.DATABASE_URL
process.env.POSTGRES_URL
process.env.SUPABASE_DB_URL
3. 部分暴露
// ⚠️ Password exposed separately
const DB_PASSWORD = 'MySecretPass123'
const DB_HOST = 'db.abc123.supabase.co'
4. ORM 配置
// ❌ Database config in client code
const prisma = new PrismaClient({
datasources: {
db: {
url: 'postgresql://postgres:[email protected]:5432/postgres'
}
}
})
用法
基本检查
Check for database connection strings on https://myapp.example.com
深度扫描
Deep scan for DB credentials on https://myapp.example.com
输出格式
未发现连接字符串(良好)
═══════════════════════════════════════════════════════════
DATABASE CONNECTION STRING CHECK
═══════════════════════════════════════════════════════════
Status: ✅ No database connection strings detected
Scanned:
├── JavaScript bundles: 5 files analyzed
├── PostgreSQL patterns: None found
├── Connection strings: None found
└── Password patterns: None found
Result: PASS - No direct database credentials exposed
═══════════════════════════════════════════════════════════
已发现连接字符串(严重)
═══════════════════════════════════════════════════════════
🔴 CRITICAL: DATABASE CONNECTION STRING EXPOSED
═══════════════════════════════════════════════════════════
Severity: P0 - CRITICAL
Status: ❌ PostgreSQL connection string found in client code!
⚠️ IMMEDIATE ACTION REQUIRED ⚠️
Connection String:
postgresql://postgres:MySecr***@db.abc123def.supabase.co:5432/postgres
(Password partially redacted in display, full value in context file)
Parsed Components:
├── Host: db.abc123def.supabase.co
├── Port: 5432
├── Database: postgres
├── Username: postgres
└── Password: [EXPOSED] ← CRITICAL
Location:
└── /static/js/api.chunk.js (line 234)
const DATABASE_URL = 'postgresql://postgres:...'
Impact Assessment:
├── 🔴 Direct PostgreSQL access possible
├── 🔴 All RLS policies bypassed
├── 🔴 Can access auth.users table
├── 🔴 Can modify database schema
└── 🔴 Full data exfiltration possible
═══════════════════════════════════════════════════════════
IMMEDIATE REMEDIATION STEPS
═══════════════════════════════════════════════════════════
1. CHANGE DATABASE PASSWORD NOW
→ Supabase Dashboard > Settings > Database > Reset database password
2. REMOVE FROM CLIENT CODE
→ Delete connection string from source code
→ Ensure DATABASE_URL is not in NEXT_PUBLIC_* or VITE_* env vars
→ Redeploy application
3. AUDIT FOR ABUSE
→ Check Supabase logs for direct PostgreSQL connections
→ Review for unauthorized data access or modifications
4. USE PROPER ARCHITECTURE
→ Client should ONLY use Supabase client library (REST API)
→ Direct DB access should ONLY be from:
- Edge Functions
- Server-side code
- Migration tools
Documentation:
→ https://supabase.com/docs/guides/database/connecting-to-postgres
→ https://supabase.com/docs/guides/functions
═══════════════════════════════════════════════════════════
上下文输出
{
"findings": [
{
"id": "DB_CONNECTION_STRING_EXPOSED",
"severity": "P0",
"title": "PostgreSQL Connection String Exposed",
"description": "Database connection string with password found in client-side code",
"location": {
"file": "/static/js/api.chunk.js",
"line": 234
},
"evidence": {
"host": "db.abc123def.supabase.co",
"port": 5432,
"database": "postgres",
"username": "postgres",
"password_exposed": true
},
"remediation": {
"immediate": "Reset database password in Supabase Dashboard",
"long_term": "Move DB operations to Edge Functions",
"docs": "https://supabase.com/docs/guides/database/connecting-to-postgres"
}
}
],
"supabase": {
"db_string_exposed": true,
"db_host": "db.abc123def.supabase.co"
}
}
部分暴露
即使是部分暴露也值得警惕:
═══════════════════════════════════════════════════════════
⚠️ PARTIAL DATABASE CREDENTIALS FOUND
═══════════════════════════════════════════════════════════
Severity: P1 - High
Found:
├── Database host: db.abc123def.supabase.co (line 45)
├── Database password: [16 char string] (line 89)
└── Could potentially be combined for access
Recommendation:
→ Rotate database password as precaution
→ Remove all DB-related values from client code
═══════════════════════════════════════════════════════════
常见原因
| 原因 | 解决方案 |
|---|---|
| 环境变量前缀错误 | 切勿使用 NEXT_PUBLIC_DATABASE_URL |
| 客户端代码中包含 SSR 代码 | 确保仅服务端代码留在服务端 |
| 打包工具配置错误 | 检查 webpack/vite 配置,确认没有暴露环境变量 |
| 复制粘贴错误 | 仔细检查要提交的内容 |
架构指导
错误(在客户端直接访问数据库)
// ❌ NEVER in client code
import { Pool } from 'pg'
const pool = new Pool({
connectionString: process.env.DATABASE_URL // ❌
})
正确(通过 API 或 Edge Function)
// ✅ Client uses Supabase client
const { data } = await supabase
.from('products')
.select('*')
// OR call an Edge Function for complex queries
const { data } = await supabase.functions.invoke('complex-query')
Edge Function(服务端)
// supabase/functions/complex-query/index.ts
import { createClient } from '@supabase/supabase-js'
Deno.serve(async (req) => {
// ✅ Direct DB access only on server
const supabase = createClient(
Deno.env.get('SUPABASE_URL'),
Deno.env.get('SUPABASE_SERVICE_ROLE_KEY')
)
// Complex query that can't be done via REST
const { data } = await supabase.rpc('complex_function')
return new Response(JSON.stringify(data))
})
强制要求:渐进式更新上下文文件
⚠️ 此技能必须在执行过程中渐进式更新跟踪文件,而不是只在最后更新。
关键规则:边执行边写入
不要在最后批量写入。请改为:
- 开始任何操作前 → 将该操作记录到
.sb-pentest-audit.log - 每次发现后 → 立即更新
.sb-pentest-context.json - 每个重要步骤完成后 → 将完成情况记录到
.sb-pentest-audit.log
这样可以确保即使技能遭到中断、崩溃或超时,截至当时的所有发现也都能得到保留。
必须执行的操作(渐进式)
-
使用发现结果更新
.sb-pentest-context.json:{ "supabase": { "db_string_exposed": true/false, "db_host": "db.[ref].supabase.co" }, "findings": [ { "id": "DB_CONNECTION_STRING_EXPOSED", "severity": "P0", ... } ] } -
记录到
.sb-pentest-audit.log:[TIMESTAMP] [supabase-extract-db-string] [START] Checking for DB connection strings [TIMESTAMP] [supabase-extract-db-string] [CRITICAL] Connection string EXPOSED [TIMESTAMP] [supabase-extract-db-string] [CONTEXT_UPDATED] .sb-pentest-context.json updated -
如果文件不存在,先创建文件再写入。
不接受未更新上下文文件的情况。
强制要求:收集证据
📁 证据目录: .sb-pentest-evidence/02-extraction/db-string-exposure/
要创建的证据文件(如果发现数据库字符串)
| 文件 | 内容 |
|---|---|
db-string-exposure/connection-details.json | 解析后的连接字符串(密码已遮盖) |
db-string-exposure/location.txt | 文件路径和行号 |
证据格式(P0 级发现)
{
"evidence_id": "EXT-DB-001",
"timestamp": "2025-01-31T10:12:00Z",
"category": "extraction",
"type": "db_connection_string",
"severity": "P0",
"finding_id": "P0-002",
"connection_string": {
"pattern": "postgresql://postgres:[REDACTED]@db.abc123def.supabase.co:5432/postgres",
"host": "db.abc123def.supabase.co",
"port": 5432,
"database": "postgres",
"username": "postgres",
"password_exposed": true,
"password_length": 24
},
"location": {
"file": "/static/js/api.chunk.js",
"line": 234,
"context": "const DATABASE_URL = 'postgresql://postgres:...' // [REDACTED]"
},
"impact": {
"direct_db_access": true,
"rls_bypass": true,
"schema_access": true,
"auth_users_access": true
},
"remediation": {
"immediate": "Reset database password in Supabase Dashboard",
"remove_from_code": "Delete DATABASE_URL from client code",
"verify_env_vars": "Ensure not using NEXT_PUBLIC_DATABASE_URL or similar"
}
}
添加到 timeline.md(P0)
## [TIMESTAMP] - 🔴 P0 CRITICAL: Database Connection String Exposed
- PostgreSQL connection string with password found in client code
- Location: [file]:[line]
- Impact: Direct database access, full RLS bypass
- Evidence: `02-extraction/db-string-exposure/`
- **IMMEDIATE PASSWORD ROTATION REQUIRED**
相关技能
supabase-extract-service-key— 检查服务密钥是否暴露supabase-audit-tables-read— 测试通过 API 访问数据supabase-report— 生成全面报告
评论
支持 Markdown