name: supabase-extract-db-string description: 关键 - 检测客户端代码中暴露的PostgreSQL数据库连接字符串。直接数据库访问是一个P0问题。
数据库连接字符串检测
🔴 关键:需要逐步文件更新
您必须逐步写入上下文文件,而不仅仅是在结束时。
- 每次发现后立即写入
.sb-pentest-context.json- 每次操作前后记录到
.sb-pentest-audit.log- 不要等到技能完成才更新文件
- 如果技能崩溃或中断,所有之前的发现必须已经保存
这不是可选的。未能逐步写入是关键错误。
此技能检测PostgreSQL数据库连接字符串是否意外暴露在客户端代码中。
何时使用此技能
- 作为每次安全审计的一部分
- 在生产前审查代码时
- 当怀疑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] |
🔴 关键 |
连接池(Supavisor)
postgresql://postgres.[project-ref]:[password]@aws-0-us-east-1.pooler.supabase.com:6543/postgres
检测模式
1. 完整连接字符串
// ❌ 关键 - 完整连接字符串
const dbUrl = 'postgresql://postgres:MySecretPass123@db.abc123.supabase.co:5432/postgres'
2. 环境变量泄露
// ❌ 在客户端包中暴露
process.env.DATABASE_URL
process.env.POSTGRES_URL
process.env.SUPABASE_DB_URL
3. 部分暴露
// ⚠️ 密码单独暴露
const DB_PASSWORD = 'MySecretPass123'
const DB_HOST = 'db.abc123.supabase.co'
4. ORM配置
// ❌ 客户端代码中的数据库配置
const prisma = new PrismaClient({
datasources: {
db: {
url: 'postgresql://postgres:pass@db.abc123.supabase.co:5432/postgres'
}
}
})
使用方式
基本检查
在 https://myapp.example.com 上检查数据库连接字符串
深度扫描
在 https://myapp.example.com 上深度扫描数据库凭证
输出格式
未找到连接字符串(良好)
═══════════════════════════════════════════════════════════
数据库连接字符串检查
═══════════════════════════════════════════════════════════
状态:✅ 未检测到数据库连接字符串
扫描内容:
├── JavaScript包:5个文件分析
├── PostgreSQL模式:未找到
├── 连接字符串:未找到
└── 密码模式:未找到
结果:通过 - 无直接数据库凭证暴露
═══════════════════════════════════════════════════════════
找到连接字符串(关键)
═══════════════════════════════════════════════════════════
🔴 关键:数据库连接字符串暴露
═══════════════════════════════════════════════════════════
严重性:P0 - 关键
状态:❌ PostgreSQL连接字符串在客户端代码中找到!
⚠️ 需要立即行动 ⚠️
连接字符串:
postgresql://postgres:MySecr***@db.abc123def.supabase.co:5432/postgres
(密码在显示中部分隐藏,完整值在上下文文件中)
解析组件:
├── 主机:db.abc123def.supabase.co
├── 端口:5432
├── 数据库:postgres
├── 用户名:postgres
└── 密码:[暴露] ← 关键
位置:
└── /static/js/api.chunk.js (第234行)
const DATABASE_URL = 'postgresql://postgres:...'
影响评估:
├── 🔴 可直接访问PostgreSQL
├── 🔴 所有RLS策略被绕过
├── 🔴 可访问auth.users表
├── 🔴 可修改数据库模式
└── 🔴 可能完全数据外泄
═══════════════════════════════════════════════════════════
立即修复步骤
═══════════════════════════════════════════════════════════
1. 立即更改数据库密码
→ Supabase控制台 > 设置 > 数据库 > 重置数据库密码
2. 从客户端代码中移除
→ 从源代码中删除连接字符串
→ 确保DATABASE_URL不在NEXT_PUBLIC_*或VITE_*环境变量中
→ 重新部署应用程序
3. 审计滥用情况
→ 检查Supabase日志中的直接PostgreSQL连接
→ 审查未经授权的数据访问或修改
4. 使用正确架构
→ 客户端应仅使用Supabase客户端库(REST API)
→ 直接数据库访问应仅来自:
- 边缘函数
- 服务器端代码
- 迁移工具
文档:
→ 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连接字符串暴露",
"description": "在客户端代码中找到带有密码的数据库连接字符串",
"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": "在Supabase控制台中重置数据库密码",
"long_term": "将数据库操作移至边缘函数",
"docs": "https://supabase.com/docs/guides/database/connecting-to-postgres"
}
}
],
"supabase": {
"db_string_exposed": true,
"db_host": "db.abc123def.supabase.co"
}
}
部分暴露
即使部分暴露也令人担忧:
═══════════════════════════════════════════════════════════
⚠️ 部分数据库凭证找到
═══════════════════════════════════════════════════════════
严重性:P1 - 高
找到:
├── 数据库主机:db.abc123def.supabase.co (第45行)
├── 数据库密码:[16字符字符串] (第89行)
└── 可能被组合以获取访问权限
建议:
→ 作为预防措施,轮换数据库密码
→ 从客户端代码中移除所有数据库相关值
═══════════════════════════════════════════════════════════
常见原因
| 原因 | 解决方案 |
|---|---|
| 错误的环境变量前缀 | 永远不要使用 NEXT_PUBLIC_DATABASE_URL |
| SSR代码在客户端中 | 确保服务器端代码仅保留在服务器端 |
| 打包器配置错误 | 检查webpack/vite配置以暴露环境变量 |
| 复制粘贴错误 | 双重检查您提交的内容 |
架构指导
错误(客户端中直接数据库)
// ❌ 永远不要在客户端代码中
import { Pool } from 'pg'
const pool = new Pool({
connectionString: process.env.DATABASE_URL // ❌
})
正确(API或边缘函数)
// ✅ 客户端使用Supabase客户端
const { data } = await supabase
.from('products')
.select('*')
// 或调用边缘函数进行复杂查询
const { data } = await supabase.functions.invoke('complex-query')
边缘函数(服务器端)
// supabase/functions/complex-query/index.ts
import { createClient } from '@supabase/supabase-js'
Deno.serve(async (req) => {
// ✅ 仅在服务器上进行直接数据库访问
const supabase = createClient(
Deno.env.get('SUPABASE_URL'),
Deno.env.get('SUPABASE_SERVICE_ROLE_KEY')
)
// 无法通过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:[时间戳] [supabase-extract-db-string] [开始] 检查数据库连接字符串 [时间戳] [supabase-extract-db-string] [关键] 连接字符串暴露 [时间戳] [supabase-extract-db-string] [上下文更新] .sb-pentest-context.json 已更新 -
如果文件不存在,在写入前创建它们。
未能更新上下文文件是不可接受的。
强制:证据收集
📁 证据目录: .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": "在Supabase控制台中重置数据库密码",
"remove_from_code": "从客户端代码中删除DATABASE_URL",
"verify_env_vars": "确保不使用NEXT_PUBLIC_DATABASE_URL或类似"
}
}
添加到timeline.md(P0)
## [时间戳] - 🔴 P0 关键:数据库连接字符串暴露
- PostgreSQL连接字符串带有密码在客户端代码中找到
- 位置:[文件]:[行]
- 影响:直接数据库访问,完全RLS绕过
- 证据:`02-extraction/db-string-exposure/`
- **需要立即密码轮换**
相关技能
supabase-extract-service-key— 检查服务密钥暴露supabase-audit-tables-read— 通过API测试数据访问supabase-report— 生成全面报告