[Spring Security] PasswordEncoder, BCryptPasswordEncoder - 비밀번호 암호화

Jisoo Choi·2022년 5월 20일
0

Spring Security

목록 보기
1/1

로그인 기능 구현을 위해 Spring Security를 다루다가 사용자 비밀번호 암호화를 지원하는 인터페이스 PasswordEncoder와 구현체에 대해 살펴보았다.

🐪 PasswordEncoder

Spring Security에서 지원하는 비밀번호 암호화 인터페이스이다. 단방향 암호화로 진행되며 인터페이스와 구현체를 제공한다.

  • 인터페이스 구성 요소
public interface PasswordEncoder {

	 /* Encode the raw password.(비밀번호 단방향 암호화)*/
	String encode(CharSequence rawPassword);

	/**
     * 암호화하지 않은 비밀번호(raw-)와 암호화된 비밀번호(encoded-)가 일치하는지 비교
	 * @param rawPassword the raw password to encode and match
	 */
	boolean matches(CharSequence rawPassword, String encodedPassword);

	/**
	 * 암호화된 비밀번호를 다시 암호화하고자 할 경우 true를 return하게 설정(기본적으로 false를 리턴)
	 * @param encodedPassword the encoded password to check
	 */
	default boolean upgradeEncoding(String encodedPassword) {
		return false;
	}
}

Spring Security에서 공식 지원하는 PasswordEncoder 구현 클래스들은 아래와 같다.

  • BcryptPasswordEncoder : Bcrypt 해시 함수를 사용하여 비밀번호 암호화
  • Argon2PasswordEncoder : Argon2 해시 함수를 사용하여 비밀번호 암호화
  • Pbkdf2PasswordEncoder : Pbkdf2 해시 함수를 사용하여 비밀번호 암호화
  • SCryptPasswordEncoder : SCrypt 해시 함수를 사용하여 비밀번호 암호화

이 중에서 BcryptPasswordEncoder 클래스를 사용해보았다.

🤔 BCrypt

비밀번호의 경우 데이터가 누설되면 안되기 때문에 plain text로 데이터베이스에 저장하지 않고 암호화해서 넘긴다.
이런 암호를 해시하는 경우 BCrypt를 사용하는 것을 권장한다.
BCrypt는 단순히 입력을 1회 해시하는 것이 아니라, 랜덤의 salt를 부여하여 여러번 해시를 적용하여 원래의 암호를 추측하기 어렵게 한다.

🐫 BCryptPasswordEncoder

BCrypt 라는 해시 함수를 사용한 구현체이다. 단순히 해시 하는 것 뿐만 아니라 Salt를 넣는 작업까지 하므로, 입력값이 같음에도 불구하고 매번 다른 encoded된 값을 return 해주게 된다.

 public String encode(CharSequence rawPassword) {
        String salt;
        
        if (this.strength > 0) {
            if (this.random != null) {
                salt = BCrypt.gensalt(this.strength, this.random);
            } else {
                salt = BCrypt.gensalt(this.strength);
            }
        } else {
            salt = BCrypt.gensalt();
        }
        
        // salt를 generate하고 rawPassword와 salt를 이용해 hashing을 한다
        return BCrypt.hashpw(rawPassword.toString(), salt);
    }

Bcrypt를 이용했을 경우에는 matches 함수를 잘 확인하고 사용해야한다. 입력값이 같아도 매번 출력물이 다르기 때문에 equals로 비교하려고 하면 비밀번호가 계속 일치하지 않는 상황을 겪게 될 수 있다.

예시

BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();

String encoded = passwordEncoder.encode("myPassword"); //암호화 할 비밀번호

// true
Assert.assertTrue(passwordEncoder.matches("myPassword", encoded));

// false
Assert.assertEquals(passwordEncoder.encode("myPassword"), passwordEncoder.encode("myPassword"));

📍 matches로 확인했을 경우와 equals로 확인한 결과가 다른 것을 알 수 있다.
   참고: matches(rawPassword, encoded) 이면, 첫번째 매개변수 rawPassword에 암호화된 값을 넣지 말고, 사용자가 입력한 비밀번호를 그대로 넣어주자.


Reference

profile
👩‍🚀 No worries! Just record

0개의 댓글