[Spring] Bcrypt로 암호화하기
2021. 4. 11. 18:42ㆍSpring
[Spring] Bcrypt를 이용하여 비밀번호를 암호화하여 저장하는 방법
개요
- 단순 텍스트에 비밀번호를 저장하는 것은 보안상 매우 취약하다. 이 글에서는 자바를 이용하여 데이터베이스에 해시된 패스워드를 저장하는 방법을 다룬다. 이렇게 한다면 BDA들 조차도 실제 패스워드를 뺴내기 불가능하다. 기존의 MD5, SHA-1, SHA-2로 패스워드를 해싱할 수도 있지만 솔트를 치는것은 추가적인 보안을 만들 수 있다. (여기서 솔트를 친다는 말은 원문에 추가적인 문자열을 넣어서 해시를 강화한다고 이해하면 된다.) 이 글에서는 jBCrypt를 사용할 건데 그것은 패스워드를 인코딩할 때 내부적으로 랜덤 솔트를 생성하여 단순 텍스트를 인코딩하고 DB에 저장한다.( 솔트를 하게 되면 같은 문자열로 부터 다른 해시 값이 생성된다.)
Bcrypt 인코딩은 무엇인가???
bcrypt는 비밀번호 해시함수로 Niels Provos와 David Mazieres에 의해 만들어졌고 Blowfish라는 암호에 기반( 사실 너무 개념적인 이야기여서 나도 모르곗댜...)Bcrypt는 조정할 수 있는 해시알고리즘을 써서 패스워드를 저장한다. Bcrypt는 패스워드를 해싱할 때 내부적으로 랜덤한 솔트를 생성하기 때문에 같은 문자열에 대해서 다른 인코드된 결과를 반환한다. 하지만 공통된 점은 매번 길이가 60인 String을 만든다.
의존성 추가
implementation group: 'org.mindrot', name: 'jbcrypt', version: '0.3m' // gradle
- 나는 gradle여서 gradle로 의존성을 추가하였다.
Bcrypt 구현을 통한 패스워드 암호화
Bcrypt 라이브러리는 단순 텍스트 패스워드를 해시하기 위한 이미 완성된 구현체를 쓰게 해준다. hashpw() 메서드는 단순 텍스트와 랜덤한 솔트를 인자로 받는다.
private String hashPassword(String plainTextPassword) { return BCrypt.hashpw(plainTextPassword, BCrypt.gensalt()); }
암호화된 것과 원문의 매칭
원문과 암호화된 패스워드를 매칭하는 부분이다.
private void checkPass(String plainPassword, String hasedPassword) { if (BCrypt.checkpw(plainPassword, hasedPassword)) { // doSomething(); } }
프로젝트에 적용된 예시 보기
EncryptHelper.interface
public interface EncryptHelper { String encrypt(String password); boolean isMatch(String password, String hashed); }
- 이름은 EncryptHelper라고 정의하였다. 암호화와 비밀번호를 매칭해주는 두 가지 기능을 추상화하여 만들었다. 실제 구현체를 만들어보자.
BcryptImpl.java
public class BcryptImpl implements EncryptHelper { @Override public String encrypt(String password) { return BCrypt.hashpw(password,BCrypt.gensalt()); } @Override public boolean isMatch(String password, String hashed) { return BCrypt.checkpw(password,hashed); } }
- 애초에 BCrypt가 매우 간단하기 때문에 Wrapping을 해도 매우 간단하다. 내가 생각한 Wrapping을 한 이유는 다음과 같다.
- BCrypt 클래스의 이름과 내부 메서드 철자의 어려움
- 프로젝트의 특성에 맞게 새로 클래스를 구현할 수 있다.
- 애초에 BCrypt가 매우 간단하기 때문에 Wrapping을 해도 매우 간단하다. 내가 생각한 Wrapping을 한 이유는 다음과 같다.
사용할 클래스는 정의 했으니 @Bean으로 등록할 차례이다.
@EnableJpaAuditing @SpringBootApplication public class DanggeonApplication { public static void main(String[] args) { SpringApplication.run(DanggeonApplication.class, args); } @Bean public EncryptHelper encryptConfig() { return new BcryptImpl(); } }
- 일단 나는 Application에 @Bean을 등록했지만 따로 config파일을 만들어서 @Bean을 등록해도 된다.
Service에 EncryptHelper 주입하기
private final UserRepository userRepository; private final EncryptHelper encryptHelper; private JwtTokenProvider jwtTokenProvider = new JwtTokenProvider(); // private final PasswordEncoder passwordEncoder; @Autowired public UserService(UserRepository userRepository, EncryptHelper encryptHelper) { this.userRepository = userRepository; this.encryptHelper = encryptHelper; } //... }
참고
'Spring' 카테고리의 다른 글
[Spring boot] stomp를 활용해서 1:1 채팅 만들기 (3) | 2021.04.25 |
---|---|
[Spring] @Valid (0) | 2021.04.11 |
Spring으로 Token 받기 (0) | 2021.04.11 |
spring jpa localtime between (0) | 2021.03.23 |
Spring-JPA(@MappedSuperClass,@EntityListener) (0) | 2021.03.23 |