Conversation
- 변경할 필요 없는 userId 필드 제거 - updateUserProfile 메서드에서 userId 제거
- /auth/user/reset - SecurePasswordGenerator 로 랜덤 비밀번호 생성 - 비밀번호는 TempPasswordResponse를 통해 응답 - user.resetPassword로 암호화된 비밀번로 저장
- 임시 비밀번호에 무조건 영어, 숫자, 특수문자가 포함되도록 보장
- db에 저장된 refresh 토큰 제거 - 클라이언트의 쿠키 삭제
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Warning
|
| Cohort / File(s) | Summary |
|---|---|
비밀번호 생성 유틸 추가backend/src/main/java/moadong/global/util/SecurePasswordGenerator.java |
보안 비밀번호 생성 컴포넌트 추가. 대소문자/숫자/특수문자 최소 1자 보장 후 셔플. generate(int length) 공개 메서드 도입. |
비밀번호 초기화 API 추가backend/src/main/java/moadong/user/controller/UserController.java |
POST /auth/user/reset 엔드포인트 추가. 서비스 호출로 임시 비밀번호 발급, 응답 반환. refresh_token 쿠키 즉시 만료 처리(삭제). |
유저 도메인 갱신backend/src/main/java/moadong/user/entity/User.java |
프로필 업데이트에서 userId 갱신 제거. resetPassword(String encodedPassword) 메서드 추가. |
요청 DTO 정리backend/src/main/java/moadong/user/payload/request/UserUpdateRequest.java |
userId 필드 제거, password만 유지. encryptPassword는 인코딩된 비밀번호만 포함해 반환하도록 변경. |
응답 DTO 추가backend/src/main/java/moadong/user/payload/response/TempPasswordResponse.java |
임시 비밀번호 반환용 record TempPasswordResponse(String tempPassword) 추가(유효성 애노테이션 포함). |
비밀번호 초기화 서비스 로직backend/src/main/java/moadong/user/service/UserCommandService.java |
reset(String userId) 추가: 사용자 조회, 8자 임시 비밀번호 생성/인코딩/적용, 리프레시 토큰 null 처리, 사용자 저장, TempPasswordResponse 반환. SecurePasswordGenerator 의존성 주입. |
Sequence Diagram(s)
sequenceDiagram
autonumber
participant C as Client
participant UC as UserController
participant S as UserCommandService
participant UR as UserRepository
participant G as SecurePasswordGenerator
participant PE as PasswordEncoder
C->>UC: POST /auth/user/reset (인증됨)
UC->>S: reset(userId)
S->>UR: findByUserId(userId)
UR-->>S: User or not found
alt 사용자 없음
S-->>UC: throw USER_NOT_EXIST
UC-->>C: 4xx 에러
else 사용자 있음
S->>G: generate(8)
G-->>S: tempPassword
S->>PE: encode(tempPassword)
PE-->>S: encodedPassword
S->>S: user.resetPassword(encodedPassword)\nuser.setRefreshToken(null)
S->>UR: save(user)
UR-->>S: saved
S-->>UC: TempPasswordResponse(tempPassword)
UC->>UC: refresh_token 쿠키 삭제 설정
UC-->>C: 200 OK + TempPasswordResponse
end
Estimated code review effort
🎯 3 (Moderate) | ⏱️ ~25 minutes
Assessment against linked issues
| Objective | Addressed | Explanation |
|---|---|---|
| 관리자 계정 비밀번호 초기화 구현 (MOA-214) | ✅ | |
| 관리자 계정 비밀번호 변경 기능 구현 (MOA-214) | ❓ | 요청/서비스에서 명시적 "비밀번호 변경(사용자 주도)" 엔드포인트나 흐름 추가는 보이지 않음; 변경은 초기화(임시비밀번호) 중심임. |
Possibly related issues
- [feature] MOA-214 관리자 계정 비밀번호 변경 및 초기화한다 #719: 임시 비밀번호 생성/초기화 API와 DTO가 해당 이슈의 기능 범위와 직접적으로 일치함.
✨ Finishing Touches
- 📝 Generate Docstrings
🧪 Generate unit tests
- Create PR with unit tests
- Post copyable unit tests in a comment
- Commit unit tests in branch
feature/#719-password-MOA-214
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.
🪧 Tips
Chat
There are 3 ways to chat with CodeRabbit:
- Review comments: Directly reply to a review comment made by CodeRabbit. Example:
I pushed a fix in commit <commit_id>, please review it.Open a follow-up GitHub issue for this discussion.
- Files and specific lines of code (under the "Files changed" tab): Tag
@coderabbitaiin a new review comment at the desired location with your query. - PR comments: Tag
@coderabbitaiin a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:@coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.@coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
Support
Need help? Create a ticket on our support page for assistance with any issues or questions.
CodeRabbit Commands (Invoked using PR/Issue comments)
Type @coderabbitai help to get the list of available commands.
Other keywords and placeholders
- Add
@coderabbitai ignoreor@coderabbit ignoreanywhere in the PR description to prevent this PR from being reviewed. - Add
@coderabbitai summaryto generate the high-level summary at a specific location in the PR description. - Add
@coderabbitaianywhere in the PR title to generate the title automatically.
Status, Documentation and Community
- Visit our Status Page to check the current availability of CodeRabbit.
- Visit our Documentation for detailed information on how to use CodeRabbit.
- Join our Discord Community to get help, request features, and share feedback.
- Follow us on X/Twitter for updates and announcements.
Test Results75 tests 75 ✅ 2s ⏱️ Results for commit 029435b. ♻️ This comment has been updated with latest results. |
There was a problem hiding this comment.
Actionable comments posted: 7
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
backend/src/main/java/moadong/user/entity/User.java (1)
38-39: 해시 비밀번호에 부적합한 @SiZe 제약 — 저장/검증 실패 가능성BCrypt/Argon2 해시는 길이가 60자+입니다. 엔티티의
@Size(min=8, max=20)는 인코딩된 값과 충돌합니다. DTO에서만 길이/정책을 검증하고, 엔티티 제약은 완화하세요.적용 예시:
- @NotNull - @Size(min = 8, max = 20) - private String password; + @NotNull + private String password; // encoded hash 저장; 길이/복잡도 검증은 요청 DTO(@Password)에서 수행Also applies to: 80-82
🧹 Nitpick comments (6)
backend/src/main/java/moadong/user/payload/request/UserUpdateRequest.java (1)
14-15: 메서드 명칭 정합성(encrypt→encode)대칭/비대칭 암호화가 아닌 해시 인코딩이므로 의미상
encodePassword가 더 적합합니다. 호출부 일괄 치환 권장.- public UserUpdateRequest encryptPassword(PasswordEncoder passwordEncoder){ + public UserUpdateRequest encodePassword(PasswordEncoder passwordEncoder){ return new UserUpdateRequest(passwordEncoder.encode(this.password)); }backend/src/main/java/moadong/global/util/SecurePasswordGenerator.java (1)
10-16: 특수문자 집합·정책 외부화하드코딩된
SPECIAL="!@#$%^"는 취약/불편할 수 있습니다. 구성값으로 외부화하고(예:application.yml) 필요 시 모호문자(O,0,l,1) 제외 옵션을 제공하세요.backend/src/main/java/moadong/user/controller/UserController.java (1)
96-99: 권한 조건 강화 고려
isAuthenticated()만으로는 탈취 토큰에 의한 오남용 위험이 있습니다. 역할 기반 조건(예: 담당자/관리자 롤) 또는 재인증(비밀번호/2FA) 요구를 검토하세요.backend/src/main/java/moadong/user/payload/response/TempPasswordResponse.java (1)
6-10: 응답 DTO에 @password 부착은 과도함출력 값까지 Bean Validation을 걸면 예외/로그에 평문 정책이 노출될 수 있습니다. 응답 DTO에서는 제거하고, 입력 DTO에서만 정책 검증하세요.
public record TempPasswordResponse( @NotNull - @Password String tempPassword ){ }backend/src/main/java/moadong/user/service/UserCommandService.java (2)
41-41: SecurePasswordGenerator 주입: Bean 등록 여부 확인 필요
@AllArgsConstructor 주입을 쓰려면 SecurePasswordGenerator가 @Component/@bean으로 컨테이너에 등록돼 있어야 합니다. 유틸 성격이면 정적 메서드로도 충분할 수 있으니 선택지 검토 바랍니다.추가가 필요하면 SecurePasswordGenerator에 아래와 같이 애노테이션만 붙이면 됩니다:
@Component public class SecurePasswordGenerator { ... }
126-142: 감사 로그와 남용 방지
- 누가(관리자 ID, IP) 언제 어떤 사용자에 대해 reset 했는지 감사 로그/이벤트를 남기세요.
- 관리자 API에 rate limit(예: 사용자 단위/관리자 단위)와 알림(과다 시도) 추가를 권장합니다.
원하시면 도메인 이벤트 발행/감사 리포지토리/RateLimiter 인터셉터 예시를 제공하겠습니다.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (6)
backend/src/main/java/moadong/global/util/SecurePasswordGenerator.java(1 hunks)backend/src/main/java/moadong/user/controller/UserController.java(2 hunks)backend/src/main/java/moadong/user/entity/User.java(1 hunks)backend/src/main/java/moadong/user/payload/request/UserUpdateRequest.java(1 hunks)backend/src/main/java/moadong/user/payload/response/TempPasswordResponse.java(1 hunks)backend/src/main/java/moadong/user/service/UserCommandService.java(5 hunks)
🔇 Additional comments (2)
backend/src/main/java/moadong/user/service/UserCommandService.java (2)
12-12: LGTM – 보안용 유틸 import 추가 적절합니다.
21-21: LGTM – 응답 DTO import 추가 적절합니다.
| @PostMapping("/reset") | ||
| @Operation(summary = "사용자 비밀번호 초기화", description = "사용자 비밀번호를 초기화합니다.") | ||
| @PreAuthorize("isAuthenticated()") | ||
| @SecurityRequirement(name = "BearerAuth") | ||
| public ResponseEntity<?> reset(@CurrentUser CustomUserDetails user, | ||
| HttpServletResponse response) { | ||
| TempPasswordResponse tempPwdResponse = userCommandService.reset(user.getUserId()); | ||
|
|
||
| ResponseCookie cookie = ResponseCookie.from("refresh_token", "") | ||
| .path("/") | ||
| .maxAge(0) | ||
| .httpOnly(true) | ||
| .sameSite("None") | ||
| .secure(true) | ||
| .build(); | ||
| response.addHeader("Set-Cookie", cookie.toString()); | ||
| return Response.ok(tempPwdResponse); | ||
| } |
There was a problem hiding this comment.
🛠️ Refactor suggestion
보안: 임시 비밀번호 응답 반환 시 캐시/로그 차단 필요
평문 비밀번호가 프록시/브라우저/서버 로그에 남을 수 있습니다. 최소한 응답 캐시 비활성화와 응답/요청 로깅 마스킹을 적용하세요. 장기적으로는 메일/SMS 전송으로 전환 권장.
패치 예시(캐시 금지 헤더):
public ResponseEntity<?> reset(@CurrentUser CustomUserDetails user,
HttpServletResponse response) {
TempPasswordResponse tempPwdResponse = userCommandService.reset(user.getUserId());
ResponseCookie cookie = ResponseCookie.from("refresh_token", "")
.path("/")
.maxAge(0)
.httpOnly(true)
.sameSite("None")
.secure(true)
.build();
response.addHeader("Set-Cookie", cookie.toString());
+ response.setHeader("Cache-Control", "no-store, no-cache, must-revalidate, max-age=0");
+ response.setHeader("Pragma", "no-cache");
return Response.ok(tempPwdResponse);
}또한, 액세스 토큰 무효화 전략(토큰 버전, 블랙리스트, 짧은 TTL)도 병행 검토 바랍니다.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| @PostMapping("/reset") | |
| @Operation(summary = "사용자 비밀번호 초기화", description = "사용자 비밀번호를 초기화합니다.") | |
| @PreAuthorize("isAuthenticated()") | |
| @SecurityRequirement(name = "BearerAuth") | |
| public ResponseEntity<?> reset(@CurrentUser CustomUserDetails user, | |
| HttpServletResponse response) { | |
| TempPasswordResponse tempPwdResponse = userCommandService.reset(user.getUserId()); | |
| ResponseCookie cookie = ResponseCookie.from("refresh_token", "") | |
| .path("/") | |
| .maxAge(0) | |
| .httpOnly(true) | |
| .sameSite("None") | |
| .secure(true) | |
| .build(); | |
| response.addHeader("Set-Cookie", cookie.toString()); | |
| return Response.ok(tempPwdResponse); | |
| } | |
| @PostMapping("/reset") | |
| @Operation(summary = "사용자 비밀번호 초기화", description = "사용자 비밀번호를 초기화합니다.") | |
| @PreAuthorize("isAuthenticated()") | |
| @SecurityRequirement(name = "BearerAuth") | |
| public ResponseEntity<?> reset(@CurrentUser CustomUserDetails user, | |
| HttpServletResponse response) { | |
| TempPasswordResponse tempPwdResponse = userCommandService.reset(user.getUserId()); | |
| ResponseCookie cookie = ResponseCookie.from("refresh_token", "") | |
| .path("/") | |
| .maxAge(0) | |
| .httpOnly(true) | |
| .sameSite("None") | |
| .secure(true) | |
| .build(); | |
| response.addHeader("Set-Cookie", cookie.toString()); | |
| response.setHeader("Cache-Control", "no-store, no-cache, must-revalidate, max-age=0"); | |
| response.setHeader("Pragma", "no-cache"); | |
| return Response.ok(tempPwdResponse); | |
| } |
| ResponseCookie cookie = ResponseCookie.from("refresh_token", "") | ||
| .path("/") | ||
| .maxAge(0) | ||
| .httpOnly(true) | ||
| .sameSite("None") | ||
| .secure(true) | ||
| .build(); | ||
| response.addHeader("Set-Cookie", cookie.toString()); |
There was a problem hiding this comment.
💡 Verification agent
🧩 Analysis chain
쿠키 제거 시 Domain 정합성 확인
로그인 시 설정한 refresh_token의 Domain/Path와 동일해야 삭제됩니다. 현재 Domain 미설정 상태입니다. 발급부와 동일하게 맞추는지 확인 부탁드립니다.
아래 스크립트로 발급부 설정을 점검하세요:
🏁 Script executed:
#!/bin/bash
# refresh_token 쿠키 설정 위치/속성 확인
rg -nC2 "ResponseCookie\.from\(\s*\"refresh_token\"" --type=javaLength of output: 1706
🏁 Script executed:
#!/bin/bash
sed -n '1,200p' backend/src/main/java/moadong/user/util/CookieMaker.javaLength of output: 795
refresh_token 삭제 쿠키에 domain 설정 추가
UserController.java의 로그아웃(63–67행) 및 비밀번호 재설정(104–110행) 삭제 로직에서 ResponseCookie 빌더에 .domain(".moadong.com")을 추가해 주세요.
🤖 Prompt for AI Agents
In backend/src/main/java/moadong/user/controller/UserController.java around
lines 63–67 and 104–111, the ResponseCookie builders for clearing the
refresh_token do not set the cookie domain; update both builders to include
.domain(".moadong.com") in the fluent chain before build() so the Set-Cookie
includes the correct domain when removing the refresh_token.
| public void resetPassword(String encodedPassword) { //초기화된 비밀번호 업데이트 | ||
| this.password = encodedPassword; | ||
| } |
There was a problem hiding this comment.
🛠️ Refactor suggestion
비밀번호 초기화 시 보안 후속처리 누락
resetPassword 호출 시점 기록과 세션 토큰 무효화를 엔티티/도메인 이벤트로 일관되게 다루면 안전합니다(토큰 버전 증가 또는 passwordChangedAt 비교).
예시 스니펫(참고):
+ private Date passwordChangedAt;
...
public void resetPassword(String encodedPassword) { //초기화된 비밀번호 업데이트
this.password = encodedPassword;
+ this.passwordChangedAt = new Date();
+ this.refreshToken = null;
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| public void resetPassword(String encodedPassword) { //초기화된 비밀번호 업데이트 | |
| this.password = encodedPassword; | |
| } | |
| // in User.java, add at the top of the class alongside the other fields: | |
| private Date passwordChangedAt; | |
| ... | |
| // update the resetPassword method: | |
| public void resetPassword(String encodedPassword) { // 초기화된 비밀번호 업데이트 | |
| this.password = encodedPassword; | |
| this.passwordChangedAt = new Date(); | |
| this.refreshToken = null; | |
| } |
🤖 Prompt for AI Agents
In backend/src/main/java/moadong/user/entity/User.java around lines 80–82,
resetPassword currently only assigns the new encoded password; you must also
record the password-change moment and invalidate existing sessions/tokens.
Modify resetPassword to set a passwordChangedAt timestamp (e.g., Instant.now())
and/or increment a tokenVersion field, and publish a domain event (e.g.,
UserPasswordResetEvent) so downstream services can revoke sessions; ensure this
runs in the same transaction as the password update and that JWT/session
validation logic checks passwordChangedAt/tokenVersion to reject old tokens.
| public TempPasswordResponse reset(String userId) { | ||
| User user = userRepository.findUserByUserId(userId) | ||
| .orElseThrow(() -> new RestApiException(ErrorCode.USER_NOT_EXIST)); | ||
|
|
||
| //랜덤 임시 비밀번호 생성 | ||
| TempPasswordResponse tempPwdResponse = new TempPasswordResponse( | ||
| securePasswordGenerator.generate(8)); | ||
|
|
||
| //암호화 | ||
| user.resetPassword(passwordEncoder.encode(tempPwdResponse.tempPassword())); | ||
|
|
||
| user.updateRefreshToken(null); | ||
| userRepository.save(user); | ||
|
|
||
| return tempPwdResponse; | ||
| } | ||
|
|
There was a problem hiding this comment.
💡 Verification agent
❓ Verification inconclusive
임시 비밀번호를 응답 본문으로 반환하는 것은 고위험 보안 이슈입니다.
- 즉시: 응답/액세스 로그에서 본문 마스킹, 캐시 방지 헤더(no-store) 적용, APM/디버그 로거에 노출 금지.
- 근본: API 응답으로 비밀번호 전달을 제거하고, 일회성 리셋 토큰+아웃오브밴드(이메일/SMS)로 전환 권장.
원하시면 컨트롤러/필터 레벨 마스킹 및 헤더 설정 패치를 제안하겠습니다.
임시 비밀번호 평문 반환 차단
- 서비스(
UserCommandService.reset)에서TempPasswordResponse에 평문 비밀번호를 포함하지 않도록 삭제 - 로그·액세스 기록 마스킹,
Cache-Control: no-store헤더 적용, APM/디버거 노출 방지 - 근본 대책: API 응답 대신 이메일/SMS 일회성 리셋 토큰 방식으로 전환
🤖 Prompt for AI Agents
In backend/src/main/java/moadong/user/service/UserCommandService.java around
lines 126 to 142, the method currently generates a plaintext temporary password,
places it in TempPasswordResponse and returns it — remove returning or storing
the plaintext in any API response or logs; instead generate a one-time reset
token (or store only a hashed temporary credential) and send the reset
link/token via email/SMS, clear any temp secrets from memory immediately, ensure
no plaintext is written to logs or caches, add Cache-Control: no-store on the
endpoint response, and update callers/tests to expect a token-sent
acknowledgement (not the password) while persisting only hashed values or token
metadata server-side with expiry.
| TempPasswordResponse tempPwdResponse = new TempPasswordResponse( | ||
| securePasswordGenerator.generate(8)); | ||
|
|
There was a problem hiding this comment.
💡 Verification agent
❓ Verification inconclusive
임시 비밀번호 길이 8 → 최소 16자로 상수/설정화하세요.
매직넘버 제거 및 구성 가능하게 하여 보안 정책을 코드 수정 없이 바꿀 수 있게 하는 것이 좋습니다.
아래 diff로 생성 길이를 상수로 치환하세요:
- TempPasswordResponse tempPwdResponse = new TempPasswordResponse(
- securePasswordGenerator.generate(8));
+ TempPasswordResponse tempPwdResponse = new TempPasswordResponse(
+ securePasswordGenerator.generate(TEMP_PASSWORD_LENGTH));그리고 클래스 상단에 상수 추가:
// 클래스 필드 영역
private static final int TEMP_PASSWORD_LENGTH = 16; // 정책에 따라 16~20 권장추가로, 생성기가 대/소문자+숫자+기호를 모두 포함하도록 보장하는지 점검 바랍니다.
임시 비밀번호 길이 매직 넘버 제거 및 상수화
securePasswordGenerator.generate(8)의 8을 private static final int TEMP_PASSWORD_LENGTH 또는 외부 설정(application.yml 등)으로 분리하고 기본값을 16 이상으로 지정하세요.
생성 로직이 대문자·소문자·숫자·특수문자를 모두 포함하도록 구현되어 있는지도 검증 바랍니다.
| user.resetPassword(passwordEncoder.encode(tempPwdResponse.tempPassword())); | ||
|
|
||
| user.updateRefreshToken(null); | ||
| userRepository.save(user); | ||
|
|
There was a problem hiding this comment.
🛠️ Refactor suggestion
비밀번호 재설정 시 기존 Access Token 무효화 전략 필요
refresh 토큰만 null 처리하면 유출된 Access Token은 만료 시점까지 유효합니다. User에 passwordChangedAt(또는 tokenVersion)을 기록하고, JWT 검증 시 이전에 발급된 토큰을 거부하도록 하는 방식을 권장합니다.
원하시면 User 필드/필터/JWT 클레임 변경까지 포함한 패치안을 드리겠습니다.
Zepelown
left a comment
There was a problem hiding this comment.
고생하셨습니다.
버그 하나 있는 거 같은데 수정 부탁드릴게요
- 최소 길이 검증 추가
|
수정 완료 됐슴다 |
There was a problem hiding this comment.
Actionable comments posted: 0
♻️ Duplicate comments (1)
backend/src/main/java/moadong/global/util/SecurePasswordGenerator.java (1)
20-33: 이전 지적사항 해결됨: 길이(+3) 버그 수정 및 최소 길이 검증 추가 OK
for (int i = 3; i < length; i++)로 수정되어 요청 길이 그대로 생성되고, 최소 길이(8) 검증도 추가되었습니다.
🧹 Nitpick comments (3)
backend/src/main/java/moadong/global/util/SecurePasswordGenerator.java (3)
10-16: 특수문자 집합 확대 또는 정책화 권장현 집합(
!@#$%^)은 너무 좁습니다. 기본값을 확장하거나(메일/SMS 전송 이슈가 없다면) 구성값으로 관리하는 편이 좋습니다.적용 예:
- private static final String SPECIAL = "!@#$%^"; + private static final String SPECIAL = "!@#$%^&*()_-+=[]{}:;,.?";
15-18: 길이 정책 상수화(12+ 권장) 및 상한 추가임시 비밀번호 길이는 12~16을 권장합니다(NIST는 길이 중심 권고). 상수화해 호출부와 정책을 일관되게 관리하면 좋습니다. 상한도 두어 오용을 방지하세요.
+ private static final int MIN_LENGTH = 12; + private static final int MAX_LENGTH = 128; @@ - if (length < 8) { - throw new IllegalArgumentException("Length must be at least 8");} + if (length < MIN_LENGTH) { + throw new IllegalArgumentException("Length must be >= " + MIN_LENGTH); + } + if (length > MAX_LENGTH) { + throw new IllegalArgumentException("Length must be <= " + MAX_LENGTH); + }호출부(UserCommandService 등)에서 현재
generate(8)사용 시 함께 상향이 필요한지 확인 부탁드립니다.Also applies to: 20-23
19-37: 임시 비밀번호 전달 방식 보안 가드레일 제안API 응답으로 직접 전달하는 현재 방식은 위험도가 있습니다. 아래 가드레일을 고려해 주세요.
- 단회 노출(one-time display) 및 즉시 만료(예: 5–10분) 토큰화 또는 최초 로그인 시 강제 변경.
- 재발급 시 이전 임시 비밀번호 즉시 무효화 및 리프레시 토큰 전부 폐기.
- 관리자·대상 사용자·요청 IP 등 감사 로그 남기기 + 레이트 리미트.
- 문자/메일 전송을 도입할 때, 전송 매체에 안전한 문자셋(모호 문자 제외) 사용.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (1)
backend/src/main/java/moadong/global/util/SecurePasswordGenerator.java(1 hunks)
🔇 Additional comments (2)
backend/src/main/java/moadong/global/util/SecurePasswordGenerator.java (2)
39-48: 셔플 구현 적절Fisher–Yates 방식으로
SecureRandom사용하며 편향 없어 보입니다. 좋습니다.
7-9:SecureRandom재사용 OK인스턴스 필드로 재사용해 보안·성능 균형이 좋습니다. 상태가 없으므로 빈으로 두는 것도 타당합니다.
Also applies to: 17-18
#️⃣연관된 이슈
📝작업 내용
중점적으로 리뷰받고 싶은 부분(선택)
논의하고 싶은 부분(선택)
🫡 참고사항
Summary by CodeRabbit
신기능
변경