본문 바로가기

spring/security

[Spring security] PasswordEncoder 살펴보기

들어가면서

도서 : 스프링 시큐리티 인 액션을 보고 내용을 정리한 글입니다. 자세한 내용은 책을 보는 것을 추천합니다.
이번 내용은 스프링 시큐리티의 암호화를 담당하는 모듈을 다루었다.

PasswordEncoder 인터페이스

비밀번호는 민감한 정보이다. 외부에 노출이 된다면 중요한 정보를 탈취당할 수 있기 때문에 단단히 챙겨하는 정보이다. 이런 민감한 정보를 안전하게 보관하기 위해서 암호화를 하는데 스프링 시큐리티에서는 이런 암호화를 처리하는 역할을 인터페이스로 정의하고 있다. 바로 PasswordEncoder이다.

스프링 시큐리티를 적용하고 있다면 이 구현체 빈으로 등록하면 정의된 역할에 맞게 암호화를 적용할 수 있다.

PasswordEncoder 구현체

BCryptPasswordEncoder, Argon2PasswordEncoder, DelegatingPasswordEncoder, Pbkdf2PasswordEncoder, SCryptPasswordEncoder와 같은 구현체가 있다. 제공하는 구현체는 모두 비밀번호와 같이 민감한 정보에 사용하는 느린 해시를 사용하는 알고리즘을 구현한 구현체들로 서비스에 맞는 알고리즘을 선택해서 사용하면 된다. 각 알고리즘에 대해서는 너무 방대해서 좀 더 공부를 해봐야 할 듯...

사용 방법은 다음 예제 처럼 선언을 해서 사용을 한다. 구현된 알고리즘에 따른 인자들을 제공하고 기본 값으로도 사용이 가능하다.

BCryptPasswordEncoder bcrypt = new BCryptPasswordEncoder();
new BCryptPasswordEncoder(4); // 4 ~ 31 까지 길이 지정
Argon2PasswordEncoder argon2 = new Argon2PasswordEncoder();
new Argon2PasswordEncoder(16, 32, 1, 1 << 12, 3);
Pbkdf2PasswordEncoder pbkdf2 = new Pbkdf2PasswordEncoder();
new Pbkdf2PasswordEncoder("secret", 4);
SCryptPasswordEncoder scrypt = new SCryptPasswordEncoder();
new SCryptPasswordEncoder(16384, 8, 1, 32, 64);

DelegatingPasswordEncoder

특정 상황에 따라서 다른 알고리즘을 사용하고 싶을 때, 사용하는 구현체이다. 생성시 패스워드 구현체를 맵으로 저장한 매핑 정보를 넘겨서 만들 수 있다.
책에서는 디폴트 구현체를 생성자를 통해서 지정할 수 있다고 하는데 테스트를 하니까 아닌 것 같다. 디폴트 구현체를 지정하기 위해서는 setDefaultPasswordEncoder()를 통해서 지정을 해주어야 한다.

var map = new HashMap<String, PasswordEncoder>();
map.put("bcrypt", new BCryptPasswordEncoder());
map.put("no", noOpPasswordEncoder);

var encoder = new DelegatingPasswordEncoder("bcrypt", map);
encoder.setDefaultPasswordEncoderForMatches(map.get("no"));

Salt?

공개키 기반 알고리즘은 암호화와 복호화에 필요한 키가 같기 때문에 역해싱 과정을 통해서 데이터를 추출할 수 있다. 이런 공격을 레인보우 테이블이라고 하는데 이 과정은 리소스가 많이 드는 작업이지만 한번 공개키를 공격자가 알아내면 서비스를 이용하는 모든 고개의 데이터 정보를 공격자가 쉽게 볼 수 있어서 불안하다.

이런 한계를 극복하기 위한 해결책으로 Salt가 있다.
Salt는 데이터의 임의의 데이터를 가미한 이후에 해싱하는 기법을 사용할 때, 임의의 데이터를 salt라고 한다.

PasswordEncoder 구현체에서 Salt의 길이를 지정하면 암호화를 할 때, 지정한 길이의 Salt를 추가한 암호화 기법을 적용해준다.
더욱 더 안전하게 암호화를 사용할 수 있도록 편하게 사용할 수 있는 좋은 기능!!

key stretching

키 스트레칭은 무차별 대입 공격(브루드 포트 공격)에 대비하여 키를 대입하는데 필요한 자원의 총량을 늘려서 공격자의 자원을 낭비시키기 위한 기법이다.
구현 방법으로는 두가지가 있다.

  1. 반복적 해싱
    해시를 만들 때, 해시 함수를 여러번 반복적으로 실행하여 계산량을 늘리는 방법!
  1. 메모리 요구 사항이 큰 암호화 해시 기능 사용
    메모리 바인딩된 공격자의 공격을 막는데 효과적!

Reference

도서 : Spring security in action
키 스트레칭 : 여기