4.6.3 生产数据不能明文给测试——生产数据脱敏与测试数据生成
一句话破题
生产数据是调试的最佳素材,但直接使用会泄露隐私——脱敏是让数据"可用但不可识别"的关键技术。
为什么需要脱敏?
敏感信息类型:
- 个人身份信息(姓名、身份证、手机号)
- 认证信息(密码、Token)
- 财务信息(银行卡、交易记录)
- 业务敏感数据
脱敏策略
| 策略 | 说明 | 示例 |
|---|---|---|
| 替换 | 用假数据替换 | 张三 → 用户A |
| 遮蔽 | 部分隐藏 | 13812345678 → 138****5678 |
| 哈希 | 不可逆转换 | email → hash(email) |
| 随机化 | 完全随机 | 真实数据 → faker数据 |
| 保留格式 | 保持格式一致 | 有效手机号 → 假手机号 |
脱敏脚本示例
typescript
// scripts/sanitize.ts
import { PrismaClient } from '@prisma/client'
import { faker } from '@faker-js/faker'
import crypto from 'crypto'
const prisma = new PrismaClient()
async function sanitizeUsers() {
const users = await prisma.user.findMany()
for (const user of users) {
await prisma.user.update({
where: { id: user.id },
data: {
// 替换姓名
name: faker.person.fullName(),
// 保留格式的邮箱
email: `user_${hashId(user.id)}@example.com`,
// 替换手机号
phone: faker.phone.number(),
// 重置密码为统一测试密码
password: await hashPassword('test123456')
}
})
}
}
function hashId(id: string): string {
return crypto.createHash('md5').update(id).digest('hex').slice(0, 8)
}
async function main() {
console.log('Starting data sanitization...')
await sanitizeUsers()
await sanitizeOrders()
await sanitizePayments()
console.log('Sanitization completed!')
}
main()
.catch(console.error)
.finally(() => prisma.$disconnect())分字段脱敏
typescript
// lib/sanitizers.ts
export const sanitizers = {
// 姓名:完全替换
name: () => faker.person.fullName(),
// 邮箱:保留域名结构
email: (original: string) => {
const domain = original.split('@')[1] || 'example.com'
return `user_${faker.string.alphanumeric(8)}@${domain}`
},
// 手机号:遮蔽中间4位
phone: (original: string) => {
return original.slice(0, 3) + '****' + original.slice(-4)
},
// 身份证:保留前6后4
idCard: (original: string) => {
return original.slice(0, 6) + '********' + original.slice(-4)
},
// 地址:只保留城市
address: (original: string) => {
const city = original.match(/.+?(市|区)/)?.[0] || ''
return city + faker.location.streetAddress()
},
// 金额:保留数量级
amount: (original: number) => {
const magnitude = Math.floor(Math.log10(original))
return faker.number.float({
min: 10 ** magnitude,
max: 10 ** (magnitude + 1),
fractionDigits: 2
})
}
}生产数据导出流程
bash
# 1. 导出生产数据
pg_dump -U postgres -d production > prod_backup.sql
# 2. 导入到临时库
psql -U postgres -d temp_sanitize < prod_backup.sql
# 3. 运行脱敏脚本
DATABASE_URL=postgresql://localhost/temp_sanitize npx tsx scripts/sanitize.ts
# 4. 导出脱敏后的数据
pg_dump -U postgres -d temp_sanitize > sanitized_backup.sql
# 5. 导入到测试环境
psql -U postgres -d test < sanitized_backup.sql使用 Faker 生成真实感数据
typescript
import { faker } from '@faker-js/faker'
// 设置中文环境
faker.locale = 'zh_CN'
// 生成用户数据
function generateUser() {
return {
name: faker.person.fullName(),
email: faker.internet.email(),
phone: faker.phone.number(),
avatar: faker.image.avatar(),
bio: faker.lorem.paragraph(),
createdAt: faker.date.past()
}
}
// 生成订单数据
function generateOrder(userId: string) {
return {
userId,
orderNo: faker.string.alphanumeric(16).toUpperCase(),
amount: faker.number.float({ min: 10, max: 1000, fractionDigits: 2 }),
status: faker.helpers.arrayElement(['PENDING', 'PAID', 'SHIPPED', 'COMPLETED']),
createdAt: faker.date.recent()
}
}脱敏验证检查
typescript
async function verifySanitization() {
// 检查是否还有真实邮箱
const realEmails = await prisma.user.count({
where: {
email: { not: { contains: '@example.com' } }
}
})
if (realEmails > 0) {
throw new Error(`Found ${realEmails} unsanitized emails!`)
}
// 检查密码是否统一重置
const users = await prisma.user.findMany({
select: { password: true }
})
const uniquePasswords = new Set(users.map(u => u.password))
if (uniquePasswords.size !== 1) {
console.warn('Warning: Passwords are not uniformly reset')
}
console.log('Sanitization verification passed!')
}自动化脱敏管道
yaml
# .github/workflows/sanitize.yml
name: Sanitize Production Data
on:
schedule:
- cron: '0 0 * * 0' # 每周日执行
jobs:
sanitize:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Export production data
run: |
pg_dump $PROD_DATABASE_URL > backup.sql
env:
PROD_DATABASE_URL: ${{ secrets.PROD_DATABASE_URL }}
- name: Create temp database
run: |
createdb temp_sanitize
psql -d temp_sanitize < backup.sql
- name: Run sanitization
run: npx tsx scripts/sanitize.ts
env:
DATABASE_URL: postgresql://localhost/temp_sanitize
- name: Export sanitized data
run: pg_dump temp_sanitize > sanitized.sql
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: sanitized-data
path: sanitized.sql本节小结
- 生产数据脱敏是合规和安全的必要步骤
- 根据数据类型选择合适的脱敏策略
- 使用 Faker 生成真实感的测试数据
- 建立自动化脱敏管道保持数据新鲜
