fix(security): security audit fixes for API vulnerabilities
All checks were successful
Build Backend / build (push) Successful in 4m47s
Build Backend / build-docker (push) Successful in 2m22s

Security fixes:
- Fix sensitive data exposure: UserResponse no longer contains email/phone
- Add UserSelfResponse for authenticated user's own data
- Protect Gorse endpoints with admin role requirement
- Add rate limiting (10 req/min) to auth endpoints
- Fix CORS configuration to use allowed origins list
- Add pagination parameter validation (max 100 per page)

Changes:
- dto/dto.go: Add UserSelfResponse type
- dto/user_converter.go: Add ConvertUserToSelfResponse
- handler/user_handler.go: Use secure response types
- middleware/cors.go: Implement origin whitelist
- middleware/ratelimit.go: Enhance rate limiter
- router/router.go: Add auth rate limit, protect Gorse
- service/admin_*.go: Use ConvertUserToResponse
This commit is contained in:
lafay
2026-03-19 13:49:51 +08:00
parent d387cc493e
commit b0f209fdf8
13 changed files with 221 additions and 162 deletions

View File

@@ -14,13 +14,10 @@ import (
// UserService 用户服务接口
type UserService interface {
// 验证码相关
SendRegisterCode(ctx context.Context, email string) error
SendPasswordResetCode(ctx context.Context, email string) error
SendCurrentUserEmailVerifyCode(ctx context.Context, userID, email string) error
SendChangePasswordCode(ctx context.Context, userID string) error
// 邮箱验证
SendRegisterCode(ctx context.Context, email, clientIP string) error
SendPasswordResetCode(ctx context.Context, email, clientIP string) error
SendCurrentUserEmailVerifyCode(ctx context.Context, userID, email, clientIP string) error
SendChangePasswordCode(ctx context.Context, userID, clientIP string) error
VerifyCurrentUserEmail(ctx context.Context, userID, email, verificationCode string) error
// 用户认证
@@ -89,25 +86,23 @@ func (s *userServiceImpl) SetLogService(logService *LogService) {
}
// SendRegisterCode 发送注册验证码
func (s *userServiceImpl) SendRegisterCode(ctx context.Context, email string) error {
func (s *userServiceImpl) SendRegisterCode(ctx context.Context, email, clientIP string) error {
user, err := s.userRepo.GetByEmail(email)
if err == nil && user != nil {
return ErrEmailExists
}
return s.emailCodeService.SendCode(ctx, CodePurposeRegister, email)
return s.emailCodeService.SendCode(ctx, CodePurposeRegister, email, clientIP)
}
// SendPasswordResetCode 发送找回密码验证码
func (s *userServiceImpl) SendPasswordResetCode(ctx context.Context, email string) error {
func (s *userServiceImpl) SendPasswordResetCode(ctx context.Context, email, clientIP string) error {
user, err := s.userRepo.GetByEmail(email)
if err != nil || user == nil {
return ErrUserNotFound
}
return s.emailCodeService.SendCode(ctx, CodePurposePasswordReset, email)
return s.emailCodeService.SendCode(ctx, CodePurposePasswordReset, email, clientIP)
}
// SendCurrentUserEmailVerifyCode 发送当前用户邮箱验证验证码
func (s *userServiceImpl) SendCurrentUserEmailVerifyCode(ctx context.Context, userID, email string) error {
func (s *userServiceImpl) SendCurrentUserEmailVerifyCode(ctx context.Context, userID, email, clientIP string) error {
user, err := s.userRepo.GetByID(userID)
if err != nil || user == nil {
return ErrUserNotFound
@@ -130,7 +125,7 @@ func (s *userServiceImpl) SendCurrentUserEmailVerifyCode(ctx context.Context, us
return ErrEmailExists
}
return s.emailCodeService.SendCode(ctx, CodePurposeEmailVerify, targetEmail)
return s.emailCodeService.SendCode(ctx, CodePurposeEmailVerify, targetEmail, clientIP)
}
// VerifyCurrentUserEmail 验证当前用户邮箱
@@ -163,7 +158,7 @@ func (s *userServiceImpl) VerifyCurrentUserEmail(ctx context.Context, userID, em
}
// SendChangePasswordCode 发送修改密码验证码
func (s *userServiceImpl) SendChangePasswordCode(ctx context.Context, userID string) error {
func (s *userServiceImpl) SendChangePasswordCode(ctx context.Context, userID, clientIP string) error {
user, err := s.userRepo.GetByID(userID)
if err != nil || user == nil {
return ErrUserNotFound
@@ -171,7 +166,7 @@ func (s *userServiceImpl) SendChangePasswordCode(ctx context.Context, userID str
if user.Email == nil || strings.TrimSpace(*user.Email) == "" {
return ErrEmailNotBound
}
return s.emailCodeService.SendCode(ctx, CodePurposeChangePassword, *user.Email)
return s.emailCodeService.SendCode(ctx, CodePurposeChangePassword, *user.Email, clientIP)
}
// Register 用户注册