코딩못하는사람

BCryptPasswordEncoder 패스워드 암호화 관련 이슈 본문

issue 기록

BCryptPasswordEncoder 패스워드 암호화 관련 이슈

공부절대안함 2021. 7. 23. 17:21

문제점

스프링 시큐리티를 활용하기 위해서는 DB에 해쉬로 암호화된 패스워드를 저장해야 한다.

따라서 BCryptPasswordEncoder에 encode 메서드를 통해 해쉬암호화를 사용하여 패스워드를 저장했다.

문제는 패스워드 변경 관련 로직 및 테스트 코드 작성에서 발생했다.

@Test
    public void 회원정보_업데이트_테스트() throws Exception {
        //given
        User user = userRepository.findByName("test").orElseThrow(NoSuchUserException::new);
        UpdatePasswordDTO updatePasswordDTO = new UpdatePasswordDTO("12345", "1234", "1234");

        //when
        userService.updateName(updateNameDto,user.getId());
        userService.updatePassword(updatePasswordDTO, user.getId());
        
        //then
        assertThat(bCryptPasswordEncoder.encode("1234")).isEqualTo(user.getPassword());
     
    }

기존 회원의 패스워드를 변경하고  잘 변경되었는지 확인하는 테스트 코드이다.

비밀번호를 "12345"->"1234"로 변경하고 junit을 활용하여 확인해보았지만 계속 실패했다.

 

원인

원인을 파악하기 위해 여러가지를 찍어보던중 해쉬로 encode되는 값이 매번 달라지는 것을 알아냈다.

System.out.println(result.getPassword());
System.out.println(bCryptPasswordEncoder.encode("12345"));

같아야 하는 값이 계속 다르게 출력되고 있었다. 그래서 BCrypt에 대해서 조사해봤다.

BCrypt는 해쉬에 솔트를 더하여 매번 다르게 값이 출력되게 만들어서 보안을 더 높인 암호화 방식이다.

따라서 솔트가 매번 다르기 때문에 encode된 값과 equals로 비교가 항상 다르기 때문에 테스트가 통과될 수 없는 구조였다. 해쉬를 하면 매번 같은 값이 나올것이라는 착각이였다.

 

해결방법

equals로 비교할 수 없는 BCryptPasswordEncoder은 비교 메서드 matches를 제공한다.

public boolean matches(CharSequence rawPassword, String encodedPassword) {
        if (rawPassword == null) {
            throw new IllegalArgumentException("rawPassword cannot be null");
        } else if (encodedPassword != null && encodedPassword.length() != 0) {
            if (!this.BCRYPT_PATTERN.matcher(encodedPassword).matches()) {
                this.logger.warn("Encoded password does not look like BCrypt");
                return false;
            } else {
                return BCrypt.checkpw(rawPassword.toString(), encodedPassword);
            }
        } else {
            this.logger.warn("Empty encoded password");
            return false;
        }
    }

따라서 테스트 코드를 다음과 같이 짜주면 해결할 수 있다.

assertThat(bCryptPasswordEncoder.matches("1234", result.getPassword())).isEqualTo(true);
assertThat(bCryptPasswordEncoder.matches("12345", result.getPassword())).isEqualTo(false);

배운점

  • 해쉬를 한번 더 공부하게 되었다.
  • 사용하는 기능에 대해서 잘 모르고 사용하는게 위험하다는 것을 또 느꼈다. 항상 제대로 알고 사용하자
Comments