Skip to content

[feature] 비밀번호 변경 시 아이디/이전 비밀번호 동일 여부 검증 추가하고 초기화 api 비인증 사용자에게 제공한다#728

Merged
alsdddk merged 3 commits intodevelop/befrom
feature/#727-password-enhancement-MOA-220
Sep 8, 2025
Merged

[feature] 비밀번호 변경 시 아이디/이전 비밀번호 동일 여부 검증 추가하고 초기화 api 비인증 사용자에게 제공한다#728
alsdddk merged 3 commits intodevelop/befrom
feature/#727-password-enhancement-MOA-220

Conversation

@alsdddk
Copy link
Collaborator

@alsdddk alsdddk commented Sep 6, 2025

#️⃣연관된 이슈

#727

📝작업 내용

비밀번호 변경 시 검증 로직(아이디/이전 비밀번호 동일 여부)을 추가하고 초기화를 비로그인 상태에서 가능하도록 개선

스크린샷 2025-09-06 19 43 55 스크린샷 2025-09-06 19 42 53

중점적으로 리뷰받고 싶은 부분(선택)

리뷰어가 특별히 봐주었으면 하는 부분이 있다면 작성해주세요

ex) 메서드 XXX의 이름을 더 잘 짓고 싶은데 혹시 좋은 명칭이 있을까요?

논의하고 싶은 부분(선택)

논의하고 싶은 부분이 있다면 작성해주세요.

🫡 참고사항

Summary by CodeRabbit

  • 신규 기능
    • 비밀번호 정책 강화: 아이디와 동일한 비밀번호 및 이전 비밀번호 재사용을 금지하며, 위반 시 명확한 오류 메시지를 제공합니다.
  • 변경 사항
    • 비밀번호 재설정 방식 개선: 사용자 ID 입력으로 비로그인 상태에서도 재설정을 요청할 수 있도록 변경되었습니다.
    • 임시비밀번호 응답의 유효성 처리 일부 조정이 적용되었습니다.

- 아이디와 동일한지, 이전 비밀번호와 동일한지 체크
- 각각 702-1, 702-2 ErrorCode 설정
- 로그인 여부와 상관없이 userId 만으로 초기화 하도록 수정
- 브라우저의 쿠키 제거 로직 삭제
@vercel
Copy link

vercel bot commented Sep 6, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
moadong Ready Ready Preview Comment Sep 6, 2025 2:32pm

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 6, 2025

Warning

.coderabbit.yaml has a parsing error

The CodeRabbit configuration file in this repository has a parsing error and default settings were used instead. Please fix the error(s) in the configuration file. You can initialize chat with CodeRabbit to get help with the configuration file.

💥 Parsing errors (1)
Validation error: Invalid regex pattern for base branch. Received: "**" at "reviews.auto_review.base_branches[0]"
⚙️ Configuration instructions
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Walkthrough

비밀번호 변경 시 사용자 ID 및 이전 비밀번호 동일성 검증을 서비스에 추가하고, 비밀번호 초기화 API를 요청 본문 기반(UserResetRequest)으로 변경하며 관련 DTO/컨트롤러/에러코드를 추가했습니다.

Changes

Cohort / File(s) Summary
Error codes
backend/src/main/java/moadong/global/exception/ErrorCode.java
에러 코드 2종 추가: PASSWORD_SAME_AS_USERID, PASSWORD_SAME_AS_OLD. import com.google.api.Http; 불필요한 import 추가.
User API Controller
backend/src/main/java/moadong/user/controller/UserController.java
/reset 엔드포인트 시그니처 변경: 인증 컨텍스트/쿠키 제거, @RequestBody @Validated UserResetRequest 수신으로 변경 및 서비스 반환값 바로 응답. 보안 어노테이션 제거.
Request DTO
backend/src/main/java/moadong/user/payload/request/UserResetRequest.java
UserResetRequest 레코드 신설: @NotNull @UserId String userId.
User service validation
backend/src/main/java/moadong/user/service/UserCommandService.java
비밀번호 변경 시 검증 추가: 비밀번호==아이디 경우 PASSWORD_SAME_AS_USERID 예외, 비밀번호==기존 비밀번호 경우 PASSWORD_SAME_AS_OLD 예외 발생. 기존 흐름 이후에 암호화·저장 및 토큰 처리 유지.
Response DTO
backend/src/main/java/moadong/user/payload/response/TempPasswordResponse.java
tempPassword 컴포넌트에서 @Password 검증 제거(현재는 @NotNull String tempPassword). 관련된 사용되지 않는 import 잔존 가능.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor Client
  participant Controller as UserController
  participant Service as UserCommandService

  rect rgb(245,248,255)
    Note over Client,Controller: 비밀번호 초기화 (변경된 흐름)
    Client->>Controller: POST /users/reset { userId }
    Controller->>Service: reset(userId)
    Service-->>Controller: TempPasswordResponse
    Controller-->>Client: 200 TempPasswordResponse
  end
Loading
sequenceDiagram
  autonumber
  actor Client
  participant Controller as UserController
  participant Service as UserCommandService
  participant Repo as UserRepository

  rect rgb(245,255,245)
    Note over Client,Service: 비밀번호 변경 검증 추가
    Client->>Controller: PATCH /users/me/password { newPassword }
    Controller->>Service: update(userId, newPassword, ...)
    alt newPassword == userId
      Service-->>Controller: throw PASSWORD_SAME_AS_USERID
      Controller-->>Client: 400 702-1
    else newPassword == oldPassword
      Service-->>Controller: throw PASSWORD_SAME_AS_OLD
      Controller-->>Client: 400 702-2
    else 변경 진행
      Service->>Repo: save(encryptedPassword)
      Repo-->>Service: OK
      Service-->>Controller: UpdateResponse
      Controller-->>Client: 200 UpdateResponse
    end
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Assessment against linked issues

Objective Addressed Explanation
비밀번호 변경 시 동일 비밀번호 방지(아이디/이전 비밀번호) MOA-220
비밀번호 초기화 API 개선(요청 본문 기반으로 수정) MOA-220

Assessment against linked issues: Out-of-scope changes

Code Change Explanation
불필요한 import 추가: import com.google.api.Http; (backend/src/main/java/moadong/global/exception/ErrorCode.java) 사용되지 않는 import로, MOA-220 요구사항과 무관함.
@Password 검증 제거: TempPasswordResponse.tempPassword (backend/src/main/java/moadong/user/payload/response/TempPasswordResponse.java) linked issue에서 명시되지 않은 응답 DTO의 검증 주석 제거로 의도된 범위인지 불분명함.

Possibly related issues

Possibly related PRs

Suggested labels

✨ Feature

Suggested reviewers

  • lepitaaar
  • Zepelown
  • PororoAndFriends

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 113d89e and 99505db.

📒 Files selected for processing (1)
  • backend/src/main/java/moadong/user/payload/response/TempPasswordResponse.java (0 hunks)
💤 Files with no reviewable changes (1)
  • backend/src/main/java/moadong/user/payload/response/TempPasswordResponse.java
✨ 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/#727-password-enhancement-MOA-220

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@alsdddk alsdddk added 📬 API 서버 API 통신 작업 💾 BE Backend labels Sep 6, 2025
@github-actions
Copy link

github-actions bot commented Sep 6, 2025

Test Results

80 tests   77 ✅  7s ⏱️
14 suites   3 💤
14 files     0 ❌

Results for commit 99505db.

♻️ This comment has been updated with latest results.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

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/service/UserCommandService.java (1)

131-134: 치명적: Refresh 토큰 DB 미갱신으로 재발급 검증 실패
UserCommandService.java:131–134에서 쿠키만 설정하고 user.refreshToken을 갱신하지 않아 이후 재발급 검증이 불가능합니다. user.updateRefreshToken(...) 호출 후 userRepository.save(user)를 수행한 뒤 쿠키를 설정해야 합니다.

@@ -131,4 +131,8 @@
-        userRepository.save(user);
-
-        String newRefreshToken = jwtProvider.generateRefreshToken(user.getUsername()).getToken();
-        ResponseCookie cookie = cookieMaker.makeRefreshTokenCookie(newRefreshToken);
-        response.addHeader("Set-Cookie", cookie.toString());
+        String newRefreshToken = jwtProvider.generateRefreshToken(user.getUserId()).getToken();
+        user.updateRefreshToken(new RefreshToken(newRefreshToken, new Date()));
+        userRepository.save(user);
+
+        ResponseCookie cookie = cookieMaker.makeRefreshTokenCookie(newRefreshToken);
+        response.addHeader("Set-Cookie", cookie.toString());
🧹 Nitpick comments (3)
backend/src/main/java/moadong/global/exception/ErrorCode.java (1)

3-3: 불필요한 import 제거

import com.google.api.Http;는 사용되지 않습니다. 정리하지 않으면 정적 분석/포매터에서 경고됩니다.

-import com.google.api.Http;
backend/src/main/java/moadong/user/service/UserCommandService.java (1)

117-126: 아이디 비교는 영속 엔티티 기준으로, 입력값 유효성 확인 권장

  • userId.equals(...) 대신 user.getUserId()로 비교해 신뢰 가능한 소스 사용 권장.
  • DTO에서 password가 null/blank가 아닌지 검증되어 있는지 확인 필요.
-        if (userId.equals(userUpdateRequest.password())) {
+        if (user.getUserId().equals(userUpdateRequest.password())) {
             throw new RestApiException(ErrorCode.PASSWORD_SAME_AS_USERID);
         }
backend/src/main/java/moadong/user/payload/request/UserResetRequest.java (1)

6-11: userId 공백 문자열 방지용 검증 보강 제안

@NotNull만으로는 빈 문자열을 막지 못합니다. @NotBlank(또는 @Size) 추가 권장.

-import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.NotBlank;
@@
-        @NotNull
+        @NotBlank
         @UserId
         String userId
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between f67c2d0 and 113d89e.

📒 Files selected for processing (4)
  • backend/src/main/java/moadong/global/exception/ErrorCode.java (2 hunks)
  • backend/src/main/java/moadong/user/controller/UserController.java (2 hunks)
  • backend/src/main/java/moadong/user/payload/request/UserResetRequest.java (1 hunks)
  • backend/src/main/java/moadong/user/service/UserCommandService.java (1 hunks)
🔇 Additional comments (1)
backend/src/main/java/moadong/global/exception/ErrorCode.java (1)

38-40: 비밀번호 검증용 에러 코드 추가 적절

메시지와 상태코드 선택이 목적에 부합합니다. 클라이언트/문서에 신규 코드(702-1, 702-2) 반영만 확인해주세요.

Comment on lines +99 to 101
public ResponseEntity<?> reset(@RequestBody @Validated UserResetRequest userResetRequest) {
TempPasswordResponse tempPwdResponse = userCommandService.reset(userResetRequest.userId());
return Response.ok(tempPwdResponse);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

치명적: 비인증 사용자의 비밀번호 초기화 결과(임시 비밀번호)를 응답 본문으로 반환

누구나 타인의 userId로 임시 비밀번호를 받아 계정 탈취가 가능합니다. 최소한 응답에 임시 비밀번호를 포함하지 말고, 검증된 채널(등록된 이메일/SMS)로만 전달해야 합니다. 또한 다음 보강을 권장합니다:

  • 사용자 확인(이메일 토큰/OTP), CAPTCHA, IP/계정 단위 rate limiting 및 감사 로깅
  • 응답은 일반 메시지(202/200)로 한정, 재시도 쿨다운
  • 여러 기기 세션 무효화(이미 updateRefreshToken(null) 사용 중이나, 초기화 시에도 재검토)
-    public ResponseEntity<?> reset(@RequestBody @Validated UserResetRequest userResetRequest) {
-        TempPasswordResponse tempPwdResponse = userCommandService.reset(userResetRequest.userId());
-        return Response.ok(tempPwdResponse);
-    }
+    public ResponseEntity<?> reset(@RequestBody @Validated UserResetRequest userResetRequest) {
+        // 서비스는 임시 비밀번호를 외부 채널로 전송하도록 변경하고(추가 작업 필요),
+        // API 응답에는 비밀번호를 포함하지 않습니다.
+        userCommandService.reset(userResetRequest.userId());
+        return Response.ok("비밀번호 초기화 요청이 접수되었습니다.");
+    }
📝 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.

Suggested change
public ResponseEntity<?> reset(@RequestBody @Validated UserResetRequest userResetRequest) {
TempPasswordResponse tempPwdResponse = userCommandService.reset(userResetRequest.userId());
return Response.ok(tempPwdResponse);
public ResponseEntity<?> reset(@RequestBody @Validated UserResetRequest userResetRequest) {
// 서비스는 임시 비밀번호를 외부 채널로 전송하도록 변경하고(추가 작업 필요),
// API 응답에는 비밀번호를 포함하지 않습니다.
userCommandService.reset(userResetRequest.userId());
return Response.ok("비밀번호 초기화 요청이 접수되었습니다.");
}
🤖 Prompt for AI Agents
In backend/src/main/java/moadong/user/controller/UserController.java around
lines 99-101, do not return the temporary password in the HTTP response body;
instead change the endpoint to perform server-side verification (e.g., require
email token/OTP or CAPTCHA before reset), trigger delivery of the temporary
password only via a verified channel (registered email/SMS) and log the action
for audit, apply IP/account rate-limiting and retry cooldown, invalidate all
sessions/refresh tokens as part of the reset, and finally respond with a generic
success status/message (202 or 200) without any secret material in the response
body.

Copy link
Member

@Zepelown Zepelown left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

비밀번호 검증에 @ Password과 같은 비밀번호 형식 검증도 있으면 좋을 거 같아요.
아마 global annotation에 있을 겁니다.
이를 이용해서 dto에서 검증을 하면 될 것 같아요.
아니면 서비스에서 Password Validator 클래스를 이용해도 될 겁니다.

@alsdddk
Copy link
Collaborator Author

alsdddk commented Sep 6, 2025

비밀번호 검증에 @ Password과 같은 비밀번호 형식 검증도 있으면 좋을 거 같아요.

아마 global annotation에 있을 겁니다.

이를 이용해서 dto에서 검증을 하면 될 것 같아요.

아니면 서비스에서 Password Validator 클래스를 이용해도 될 겁니다.

그 UserUpdateRequest에서 @password로 검증하고 있다고 판단해서 따로 추가하진 않았습니다. 이걸론 검증이 부족할까요?

@Zepelown Zepelown self-requested a review September 6, 2025 11:24
Copy link
Member

@Zepelown Zepelown left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

비밀번호 검증 로직이 없는 줄 알았네요.
죄송합니다.
고생하셨어요!

Copy link
Contributor

@lepitaaar lepitaaar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

수고하셨습니다

@alsdddk alsdddk merged commit 80852ae into develop/be Sep 8, 2025
5 checks passed
@alsdddk alsdddk deleted the feature/#727-password-enhancement-MOA-220 branch September 26, 2025 06:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

📬 API 서버 API 통신 작업 💾 BE Backend

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

Comments