彩虹表攻击与Nest密码存储
文章目录
- 前言
- 🧨 什么是彩虹表攻击?
- 📷 图中解析
- 左侧是彩虹表:
- 右侧是用户数据库中的数据:
- 🔐 如何防御彩虹表攻击?
- ✅ 1. **使用 Salt 加密(推荐)**
- ✅ 2. **使用强哈希函数(如 bcrypt、scrypt、argon2)**
- ✅ 3. **不要用明文密码或简单哈希算法(如 md5/sha1)**
- ✅ 总结推荐实践
- Prisma + bcrypt 加密存储密码 实战示例
- ✅ 1. Prisma 模型定义
- ✅ 2. 安装 bcrypt
- ✅ 3. 注册:加密后存入数据库
- ✅ 4. 登录:验证密码是否匹配
- ✅ 5. 测试示例
- 🔐 安全建议
- **NestJS + Prisma + bcrypt + JWT 登录授权系统** 实战模板
- 📦 技术栈
- ✅ 1. 安装依赖
- ✅ 2. 用户模型(Prisma)
- ✅ 3. AuthModule 结构
- ✅ 4. DTO 文件
- ✅ 5. JWT 策略(jwt.strategy.ts)
- ✅ 6. AuthService(auth.service.ts)
- ✅ 7. AuthController(auth.controller.ts)
- ✅ 8. AuthModule 配置(auth.module.ts)
- ✅ 9. 使用 JWT 守卫保护路由(可选)
- ✅ 10. JWT Guard(jwt-auth.guard.ts)
- 🧪 示例请求
- 注册
- 登录
- 登录成功后返回
前言
一种常见的密码破解方式:彩虹表攻击(Rainbow Table Attack),我们一步步解释:
🧨 什么是彩虹表攻击?
彩虹表攻击是一种基于预计算哈希值反查密码的攻击方式:
- 攻击者先构建一个表格:记录常见密码及其哈希值(如 MD5/SHA1);
- 获取某网站数据库中的用户密码哈希值;
- 在彩虹表中查找匹配的哈希值,反推出原始密码。
📷 图中解析
左侧是彩虹表:
明文密码 | 对应哈希值 |
---|---|
picture1 | ab2ca3349e27 |
hithere | e3f49eabe8950 |
mypassword | 0b0a91823da1d0 |
monkey | a1d01066dd8036 |
右侧是用户数据库中的数据:
id | password (hash) | |
---|---|---|
1 | *a@@a.com | 0b0a91823da1d0 |
攻击者对照彩虹表发现这个哈希值对应 mypassword
,于是破解成功!
🔐 如何防御彩虹表攻击?
✅ 1. 使用 Salt 加密(推荐)
给每个密码增加一个**随机字符串(Salt)**再进行哈希:
password = "mypassword"
salt = "a1b2c3d4"
hash = SHA256("mypassworda1b2c3d4")
即使两个用户用相同密码,生成的哈希也不同!这样彩虹表根本没法提前计算所有组合。
✅ 2. 使用强哈希函数(如 bcrypt、scrypt、argon2)
这些哈希算法设计为:
- 计算慢(防止暴力破解)
- 自带 Salt(内置加盐)
- 可配置强度(提高成本)
例如使用 bcrypt
存密码:
import bcrypt from 'bcrypt';const saltRounds = 10;
const hash = await bcrypt.hash("mypassword", saltRounds);
验证时用:
await bcrypt.compare("mypassword", hashFromDb); // true or false
✅ 3. 不要用明文密码或简单哈希算法(如 md5/sha1)
这些算法太快太弱,容易被彩虹表破解。
✅ 总结推荐实践
做法 | 是否推荐 | 说明 |
---|---|---|
明文存密码 | ❌ 绝对禁止 | 泄露即全部破防 |
MD5/SHA1 | ❌ 不推荐 | 无加盐太容易被破解 |
哈希 + Salt | ✅ 推荐 | 每个用户不同结果,防彩虹表 |
bcrypt/scrypt/argon2 | ✅ 推荐 | 更安全的现代密码哈希方法 |
Prisma + bcrypt 加密存储密码 实战示例
以下是使用 Prisma + bcrypt 实现注册和登录时密码加密与验证的完整示例,适合用在 NestJS、Express、Fastify 等 Node.js 框架中。
✅ 1. Prisma 模型定义
// schema.prisma
model User {id Int @id @default(autoincrement())email String @uniquepassword String // 存加密后的哈希值createdAt DateTime @default(now())
}
✅ 2. 安装 bcrypt
npm install bcrypt
# or
pnpm add bcrypt
✅ 3. 注册:加密后存入数据库
import bcrypt from 'bcrypt';
import { PrismaClient } from '@prisma/client';const prisma = new PrismaClient();
const SALT_ROUNDS = 10;async function register(email: string, plainPassword: string) {const hashedPassword = await bcrypt.hash(plainPassword, SALT_ROUNDS);const user = await prisma.user.create({data: {email,password: hashedPassword,},});console.log('User created:', user);
}
✅ 4. 登录:验证密码是否匹配
async function login(email: string, plainPassword: string) {const user = await prisma.user.findUnique({where: { email },});if (!user) {throw new Error('用户不存在');}const isMatch = await bcrypt.compare(plainPassword, user.password);if (!isMatch) {throw new Error('密码错误');}console.log('登录成功:', user);
}
✅ 5. 测试示例
await register('test@example.com', 'mypassword');
// 存入数据库后为 hashed:$2b$10$... (加密值)await login('test@example.com', 'mypassword'); // ✅ 登录成功
await login('test@example.com', 'wrongpass'); // ❌ 抛出密码错误
🔐 安全建议
项目 | 建议值 |
---|---|
SALT_ROUNDS | 10~12 ,生产建议 12+ |
哈希算法 | bcrypt 是安全主流选择,argon2 更现代但略复杂 |
防止爆破 | 建议结合 JWT + 登录限速(如 express-rate-limit) |
NestJS + Prisma + bcrypt + JWT 登录授权系统 实战模板
按模块拆解讲解,包含注册、登录、密码加密、JWT 签发与验证。
📦 技术栈
@nestjs/jwt
:签发和验证 Tokenbcrypt
:密码加密@prisma/client
:数据库 ORMPassport
:认证策略(JWT)
✅ 1. 安装依赖
npm install @nestjs/jwt @nestjs/passport passport passport-jwt bcrypt
npm install -D @types/passport-jwt @types/bcrypt
✅ 2. 用户模型(Prisma)
model User {id Int @id @default(autoincrement())email String @uniquepassword StringcreatedAt DateTime @default(now())
}
✅ 3. AuthModule 结构
src/
├── auth/
│ ├── auth.module.ts
│ ├── auth.service.ts
│ ├── auth.controller.ts
│ ├── jwt.strategy.ts
│ └── dto/
│ ├── login.dto.ts
│ └── register.dto.ts
✅ 4. DTO 文件
// dto/register.dto.ts
export class RegisterDto {email: string;password: string;
}// dto/login.dto.ts
export class LoginDto {email: string;password: string;
}
✅ 5. JWT 策略(jwt.strategy.ts)
import { Injectable } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport';
import { ExtractJwt, Strategy } from 'passport-jwt';@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {constructor() {super({jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),secretOrKey: 'secretKey', // 改为读取 .env 中 JWT_SECRET});}async validate(payload: any) {return { userId: payload.sub, email: payload.email };}
}
✅ 6. AuthService(auth.service.ts)
import { Injectable } from '@nestjs/common';
import { PrismaService } from '../prisma/prisma.service';
import * as bcrypt from 'bcrypt';
import { JwtService } from '@nestjs/jwt';@Injectable()
export class AuthService {constructor(private prisma: PrismaService,private jwtService: JwtService,) {}async register(email: string, password: string) {const hash = await bcrypt.hash(password, 10);return this.prisma.user.create({data: { email, password: hash },});}async validateUser(email: string, password: string) {const user = await this.prisma.user.findUnique({ where: { email } });if (!user) return null;const isMatch = await bcrypt.compare(password, user.password);return isMatch ? user : null;}async login(user: any) {const payload = { sub: user.id, email: user.email };return {access_token: this.jwtService.sign(payload),};}
}
✅ 7. AuthController(auth.controller.ts)
import { Controller, Post, Body, UnauthorizedException } from '@nestjs/common';
import { AuthService } from './auth.service';
import { RegisterDto, LoginDto } from './dto';@Controller('auth')
export class AuthController {constructor(private authService: AuthService) {}@Post('register')register(@Body() dto: RegisterDto) {return this.authService.register(dto.email, dto.password);}@Post('login')async login(@Body() dto: LoginDto) {const user = await this.authService.validateUser(dto.email, dto.password);if (!user) throw new UnauthorizedException('Invalid credentials');return this.authService.login(user);}
}
✅ 8. AuthModule 配置(auth.module.ts)
import { Module } from '@nestjs/common';
import { JwtModule } from '@nestjs/jwt';
import { PassportModule } from '@nestjs/passport';
import { AuthService } from './auth.service';
import { AuthController } from './auth.controller';
import { JwtStrategy } from './jwt.strategy';
import { PrismaModule } from '../prisma/prisma.module';@Module({imports: [PrismaModule,PassportModule,JwtModule.register({secret: 'secretKey', // 读取自 .envsignOptions: { expiresIn: '1d' },}),],providers: [AuthService, JwtStrategy],controllers: [AuthController],
})
export class AuthModule {}
✅ 9. 使用 JWT 守卫保护路由(可选)
import { UseGuards, Controller, Get } from '@nestjs/common';
import { JwtAuthGuard } from './jwt-auth.guard';@Controller('profile')
export class ProfileController {@UseGuards(JwtAuthGuard)@Get()getProfile(@Request() req) {return req.user;}
}
✅ 10. JWT Guard(jwt-auth.guard.ts)
import { Injectable } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';@Injectable()
export class JwtAuthGuard extends AuthGuard('jwt') {}
🧪 示例请求
注册
POST /auth/register
{"email": "user@example.com","password": "123456"
}
登录
POST /auth/login
{"email": "user@example.com","password": "123456"
}
登录成功后返回
{"access_token": "eyJhbGciOiJIUzI1NiIsInR..."
}