[보안] Bcrypt 인코딩

Bcrypt 인코딩

Bcrypt의 암호화 방식을 알아보고 스프링 시큐리티로 Bcrypt 인코딩을 적용해보자.

Bcrypt 암호화 방식

  • Bcrpyt는 단방향 해시 함수를 이용한 암호화이다.
  • 단방향이기 때문에 Bcrypt 인코딩 된 암호는 복호화가 불가능하다.
  • 비밀번호 자체만 해시 함수로 암호화를 하면 평문들을 인코딩하여 비교해볼 수 있기 때문에 Bcrypt는 암호화 과정에서 salt(임의의 첨가 문자열)를 이용한다.

    ex) 비밀번호 : “1234”
    암호화(“1234” , salt) == 암호화된 문자열

  • 평문으로 비밀번호를 조회할 때 조회를 위해 salt 문자열을 알 필요는 없다. 이는 다음과 같은 특성 때문이다.

    암호화(“1234” , 암호화된 문자열) == 암호화된 문자열

  • 즉, 기존의 암호화를 했던 평문과 암호화된 문자열을 Bcrypt Encode 한다면 암호화된 문자열과 같은 문자열이 결과로 나온다.

스프링 시큐리티로 구현

스프링 시큐리티에서는 PasswordEncoderFactories로 Bcrypt Encoding 구현을 제공해 주고 있기 때문에, 다음과 같이 @Bean을 선언해서 사용할 수 있다.

    @Bean
    public PasswordEncoder passwordEncoder(){
        return PasswordEncoderFactories.createDelegatingPasswordEncoder();
    }

참고로 스프링 시큐리티의 Bcrypt Encoding은 보안을 위해 의도적으로 Encoding 시간을 살짝 늦춰서 짧은 시간 동안 여러 번의 암호화 시도를 방지한다.

가입하는 계정에 대한 Dto를 받아서 회원가입 처리를 하는 상황이라면, 다음과 같이 Encoding 할 수 있다.

Account account = Account.builder()
                .nickname(dto.getNickname())
                .email(dto.getEmail())
                .password(passwordEncoder.encode(dto.getPassword()))
                .role(Role.ROLE_USER)
                .build();

        accountRepository.save(account);

.password(passwordEncoder.encode(dto.getPassword()))로 Bcrpyt Encoding 한 비밀번호를 DB에 넣어준다.

Test Code

기존의 평문과 DB에 저장된 패스워드 값이 다른지 테스트해보자.

  @DisplayName("패스워드 인코딩 테스트")
  @Test
  public void password_enc_test() throws Exception{
      //when
      SignupDto signupDto = SignupDto.builder()
              .nickname("testUser")
              .password("12345678")
              .email("testUser@test.com")
              .build();

      //given
      mockMvc.perform(post("/sign-up")
              .content(objectMapper.writeValueAsString(signupDto))
              .contentType(MediaType.APPLICATION_JSON));

      Account account = accountRepository.findByEmail("testUser@test.com");

      //then
      Assertions.assertNotEquals(account.getPassword(),"12345678");
    }

1
평문인 “12345678”과 DB에 저장된 평문을 암호화 한 값은 다르므로 테스트 코드를 통과한다.