Lv 5. 위 제시된 기능 이외 ‘내’가 정의한 문제와 해결 과정

2025. 4. 18. 14:54·백엔드 부트캠프/문제풀이

1. [문제 인식 및 정의] 2. [해결 방안] 2-1. [의사결정 과정] 2-2. [해결 과정] 3. [해결 완료] 3-1. [회고] 3-2. [전후 데이터 비교]

1️⃣ 비밀번호 Valid 수정

1. [문제 인식 및 정의]

레벨 1 에서 Validation 을 수정했습니다. 비밀번호에 대한 검증인데, 회원가입 시에는 적용되고 있지 않았습니다.  새로운 비밀번호 수정 시에만 Valid 를 적용해주고 있었습니다.

회원가입 시에는 비밀번호에 대한 유효성 검증이 적용되지 않았고, 새로운 비밀번호 수정 시에만 유효성 검증이 적용되는 문제점이 존재합니다.

이로 인해, 회원가입 시에는 비밀번호 제약이 적용되지 않아 보안상 문제가 발생할 수 있다. 따라서, 비밀번호 검증 로직을 회원가입에도 적용해야 합니다.

2. [해결 방안] 

1) Entity DB 제약 추가

보통 자세한 제약은 DTO 딴에서 막는 것이 낫습니다. 비밀번호 같은 민감한 로직은 DB에서 처리하는 것이 아닌, 애플리케이션에서 처리하는 게 보안적으로도 맞기 때문입니다. RDBMS에서 문자열에 대해 정규표현식 같은 정교한 제약은 제한적이거나 비효율적인 것도 이유입니다. 물론 CHECK 제약조건 같은 건 있지만, MySQL이나 MariaDB에서는 한계가 있고, 복잡한 표현식은 지원이 미약합니다. 

그리하여 최소한의 제약인 nullable 만 추가했습니다.

User.java

@Column(nullable = false)
private String password;

2) SignupRequest 제약 추가

    @Size(min = 8, message = "비밀번호는 최소 8자 이상이어야 합니다.")
    @Pattern(regexp = "^(?=.*\\d)(?=.*[A-Z]).*$", message = "숫자와 대문자를 포함해야 합니다.")
    @NotBlank
    private String password;

- SignupRequest 에 적용 했습니다.

3. [해결 완료 - 회고] 

회원 가입 시에도 비밀번호에 대한 동일한 제약이 적용됩니다.

이를 통해 비밀번호 강도를 강화하고, 보안상의 취약점을 예방할 수 있습니다. 즉, 가입 시부터 강력한 비밀번호 정책을 적용함으로써 불필요한 보안 리스크를 줄일 수 있습니다.

회원가입 시 비밀번호 제약을 적용하여 보안이 강화되었습니다. 이제 강력한 비밀번호 정책을 통해 보안 취약점을 예방할 수 있습니다.

로그인 과정에서는 비밀번호 검증을 @Valid 어노테이션을 사용하지 않았는데, 로그인은 이미 등록된 정보를 사용하는 과정이므로 비밀번호 제약이 필요하지 않다고 판단했습니다.

 

2️⃣ Interceptor 제약 추가

1. [문제 인식 및 정의]

role이 비어있는 상황도 있을 수 있다. 라는 조언을 듣게 되었습니다. 코드 흐름에서는 userRole이 빈 값으로 설정될 가능성은 거의 없으나, JWT 토큰 자체에 문제가 있는 경우가 있을 수도 있기 때문에 제약을 한번 추가해보고자 했습니다.

2. [해결 방안] 

Interceptor 에서 가져온 요청에 userRole 이 비어있을 경우를 위해 제약사항을 추가할 것입니다.

이때 401 에러를 반환해줄겁니다.

        // role 이 비어있는 경우도 있을 경우 401 에러 반환합니다. Unauthorized
        if (role == null || role.isEmpty()) {
            response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "User role is missing.");
            return false;
        }

이런 코드를 추가함으로써 userRole 이 null 일 경우도 체크해주고자 했습니다.

3. [해결 완료 - 회고] 

request.getAttribute("userRole")로 값을 가져올 때, 해당 속성이 없거나 null인 경우 role 변수에는 null이 할당됩니다. 이 자체로는 에러가 발생하지 않지만 이후 로직에서 role이 null일 경우 NullPointerException 등 문제가 발생할 수 있으므로, 조건 처리를 통해 이를 사전에 방지할 수 있습니다.

 이와 같은 검증 로직을 추가하는 것은 보안적인 측면에서 매우 중요하다는 것을 깨달았습니다. 사용자의 role 정보가 없거나 잘못된 경우, 그에 맞는 처리 없이 로직이 진행되면 예기치 않은 오류가 발생할 수 있습니다. 이를 방지하기 위해 사전 검증을 통해 안전하게 처리하는 것이 보안상 더욱 신뢰할 수 있는 시스템을 만드는 데 기여할 겁니다. 또한, 이런 방식으로 예외를 미리 처리하는 것은 시스템 안정성뿐만 아니라 사용자 경험을 높이는 데도 도움이 됩니다.

+) 실제로 테스트 코드를 작성하다보니 알게 된 것인데, 이런식으로 토큰이 잘못 발급되면 ! null 일때가 존재했습니다. 

 

3️⃣ Comment Admin 수정 ① CommentAdminController ResponseEntity 수정

1. [문제 인식 및 정의]

- Comment Controller 를 확인해보니, 200 OK 를 반환하고 있었습니다.

- 200 OK 의 경우, 삭제 요청 처리 후, 응답 본문에 메시지나 데이터를 담을 경우 사용한다고 알고 있습니다.

- 해당 OK 를 NO CONTENT 인 204 상태코드를 줄 것입니다.

2. [해결 방안]

    public ResponseEntity<Void> deleteComment(@PathVariable long commentId) {
         commentAdminService.deleteComment(commentId);
         return ResponseEntity.noContent().build();
     }

- void 인 부분을 지우고, ReponseEntity 가 반환되도록 했습니다.

- 이렇게 되면 200 OK 가 아닌, 204 NO CONTENT 가 반환됩니다.

3. [해결 완료 - 회고] 

- RESTful한 의도 표현이 되었다고 생각합니다. DELETE는 리소스를 삭제하는 동작이기 때문에, 결과적으로 아무것도 남지 않는 게 자연스럽습니다. 그래서 "응답 본문도 없음"을 의미하는 204가 잘 어울린다고 판단했습니다. 

- 삭제 후에 굳이 "삭제되었습니다" 같은 본문 메시지를 주지 않아도, 클라이언트는 상태 코드만 보고 성공 여부를 판단할 수 있습니다.

- 204를 사용할 경우, 정말로 본문을 포함하지 않아야됩니다. 그렇지 않으면 클라이언트가 파싱에 실패할 수 있습니다.

- 만약 클라이언트에게 추가 정보를 주고 싶다면, 200 OK에 JSON 메시지를 포함하는 식으로 해야합니다.

4️⃣ Comment Admin 수정 ② CommentAdminService 리팩토링

1. [문제 인식 및 정의] 

- CommentAdmin Service 에서 삭제만을 처리하고 있었습니다.

   public void deleteComment(long commentId) {
         commentRepository.deleteById(commentId);
     }

- commentId 의 존재여부를 검증하지 않아, 해당 부분을 수정하고자 했습니다.

-  ID가 존재하지 않을 때 아무런 예외 처리를 하지 않으면 발생할 수 있는 문제가 있을 수 있습니다. 바로, 서버 에러인 500 상태코드가 반환될 수 있다는 것입니다.

2. [해결 방안] 

    @Transactional
     public void deleteComment(long commentId) {
         if (!commentRepository.existsById(commentId)) {
             throw new InvalidRequestException("Comment not found");
         }
         commentRepository.deleteById(commentId);
     }
 }

- 이런식으로 아이디가 존재하지 않을 경우 에러를 반환할 수 있도록 수정하였습니다.

3. [해결 완료 - 회고] 

- 이렇게 수정하게 된다면, 정확한 응답 제어 존재하지 않는 리소스에 대해 404 Not Found 응답을 줄 수 있습니다.

- 비즈니스 로직 일관성 유지 삭제하려는 리소스가 실제 존재하는지 명확히 파악 가능합니다.

- RESTful 설계는 "의도"를 응답 코드에 담는 것이라고 합니다. 404 Not Found 는 단순히 "없는 걸 삭제하려 했다"는 의도를 명확히 표현하기 때문에, 적절한 수정이라고 생각했습니다.

'백엔드 부트캠프 > 문제풀이' 카테고리의 다른 글

[일정 관리 앱 만들기] 트러블 슈팅  (0) 2025.03.26
Lv 3. 도전 계산기 만들기  (1) 2025.03.06
Lv 2. 클래스를 적용해 기본적인 연산을 수행할 수 있는 계산기 만들기  (0) 2025.02.27
Lv 1. 클래스 없이 기본적인 연산을 수행할 수 있는 계산기 만들기  (0) 2025.02.26
[Chapter02-1] 클래스와 객체 실습과제  (0) 2025.02.25
'백엔드 부트캠프/문제풀이' 카테고리의 다른 글
  • [일정 관리 앱 만들기] 트러블 슈팅
  • Lv 3. 도전 계산기 만들기
  • Lv 2. 클래스를 적용해 기본적인 연산을 수행할 수 있는 계산기 만들기
  • Lv 1. 클래스 없이 기본적인 연산을 수행할 수 있는 계산기 만들기
sintory-04
sintory-04
🚀🚀🚀
  • sintory-04
    Sintory Dev Blog
    sintory-04
    글쓰기 관리
  • 전체
    오늘
    어제
    • 분류 전체보기 (243)
      • 백엔드 부트캠프 (68)
        • TIL (55)
        • WIL (0)
        • 문제풀이 (6)
        • 기타 (6)
      • 백엔드 부트캠프[사전캠프] (35)
        • TIL (16)
        • 문제풀이 (17)
        • 기타 (1)
      • Troubleshooting (10)
      • 코딩 공부 (118)
        • Java (28)
        • Baekjoon-Java (24)
        • Programmers-Java (40)
        • Spirngboot (11)
        • typescript (1)
        • JavaScript (6)
        • Spring 입문 (8)
      • 프로젝트 (8)
        • ToDoApp(FireBase) (3)
        • ToDoApp(Spring) (5)
      • 기타 (3)
  • 블로그 메뉴

    • 소개
    • Github
  • 최근 글

  • 최근 댓글

  • hELLO· Designed By정상우.v4.10.3
sintory-04
Lv 5. 위 제시된 기능 이외 ‘내’가 정의한 문제와 해결 과정
상단으로

티스토리툴바