feat(auth): 12-character minimum, 72-byte maximum and breach check for new passwords
- New passwords (create user, admin reset, own change) need at least 12 characters (ASVS 2.1.1) and may not exceed 72 bytes, which bcrypt would silently cut off. - They are checked against Have I Been Pwned with k-anonymity (only the first 5 SHA-1 characters leave the server, padded responses); an unreachable service is logged and does not block. PASSWORD_BREACH_CHECK =false disables it for offline deployments. - Login accepts existing passwords as before, capped at 256 characters to bound anonymous bcrypt work. - Password fields in the UI say the rule up front. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
This commit is contained in:
1 parent
61e32474e4
commit
0ba8996e3a
13 files changed
+212
-17
No files matched your search
@@ -7,6 +7,7 @@ import {
|
||||
import * as bcrypt from 'bcryptjs';
|
||||
import { PrismaService } from '../prisma/prisma.service';
|
||||
import { AuditLogService } from '../audit/audit-log.service';
|
||||
import { assertPasswordNotBreached } from '../common/password/password-policy';
|
||||
import { PermissionResolverService } from '../auth/permissions/permission-resolver.service';
|
||||
import { Prisma } from '../../generated/prisma';
|
||||
import { CreateUserDto } from './dto/create-user.dto';
|
||||
@@ -209,6 +210,7 @@ export class UsersService {
|
||||
await this.assertActiveRole(dto.roleId);
|
||||
await this.assertCanAssignRole(actingUserId);
|
||||
await this.assertWithinCallerPermissions(dto.roleId, actingUserId);
|
||||
await assertPasswordNotBreached(dto.password);
|
||||
const passwordHash = await bcrypt.hash(dto.password, BCRYPT_SALT_ROUNDS);
|
||||
const user = await this.prisma.user.create({
|
||||
data: {
|
||||
@@ -337,6 +339,7 @@ export class UsersService {
|
||||
}
|
||||
const target = await this.findById(id);
|
||||
await this.assertWithinCallerPermissions(target.roleId, actingUserId);
|
||||
await assertPasswordNotBreached(dto.password);
|
||||
const passwordHash = await bcrypt.hash(dto.password, BCRYPT_SALT_ROUNDS);
|
||||
const user = await this.prisma.user.update({
|
||||
where: { id },
|
||||
|
||||
Reference in new issue
Block a user