스프링 시큐리티 인 액션을 보고서
비밀번호를 암호화하는 방식을 구현했다.
책을 참고해서 암호화 방식을 구현했는데, 비밀번호는 복호화가 불가능한 해시를 사용하는 것이 더 좋다는 말을 들었다.
해싱과 암호화는 데이터 보안에 사용되는 개념으로,
Hash는 단방향 암호화 기법 Encryption은 양방향 암호화 기법이다.
Hash는 복호화가 불가능해서, 비밀번호를 저장할 때 탈취의 가능성을 염두에 둔다면 사용할 수 있는 단방향 암호화 방식이다. 같은 데이터를 동일한 해시 알고리즘으로 암호화할 때 항상 같은 결과가 나오기에 복호화가 불가능해도 사용자 인증이 가능하다.
Why Hashing is preferred in spring security for password encryption ?
암호화는 서버 관리자나 개발자가 알고리즘과 키를 알면 암호화된 데이터를 쉽게 복호화할 수 있다.
해시의 경우, 한번 해싱된 데이터는 원래의 형식으로 복원할 수 없다. 해시 값을 갖고 있어도 원래의 데이터를 알아낼 수 없어서 보안성이 높다.
[Spring] 비밀번호 암호화에 대한 고찰
이글과 스프링 시큐리티 공식문서를 보니 Rain table이라는 문제가 여전히 존재하는 거 같다.
모든 비밀번호에 대해 해시값을 기록하고 무차별적으로 공격하는 것을 레인보우 테이블이라고 한다. 시간이 걸리더라도 언젠가는 뚫릴 수 있는 것.
이를 막기 위해서는 해쉬 함수를 만들기 전에 평문값에 salt라는 랜덤값을 추가로 넣어서 해시 함수를 만들 수 있다.
[Spring Security] Bcrypt의 salt는 무엇일까?
이 글을 보면서 BCryptEncoder가 내부적으로 처리를 해주는 것을 알게 됐다. 비밀번호와 같이 salt가 해시처리된다.
@Service
@RequiredArgsConstructor
public class UserService {
private final BCryptPasswordEncoder bCryptPasswordEncoder;
private final UserRepository userRepository;
public Long save(JoinRequestServiceDto requestDto){
String hash = bCryptPasswordEncoder.encode(requestDto.getPassword());
User user = new User(requestDto.getLoginId()
, requestDto.getName()
, hash
, requestDto.getAddress()
, requestDto.getBirthdate());
return userRepository.save(user).getId();
}
}
테스트를 해보니 실제로 비밀번호가 해시로 암호화돼서 돌아갔다.
그리고 match 메서드를 사용하니 비밀번호를 복호화하는 과정없이도 유저의 credential을 확인할 수 있었다.
match 메서드가 실제로 잘 작동하는건지 확인하기 위해서 실패하는 테스트도 작성했다.
테스트는 무사히 통과했다!