DelegatingPasswordEncoder

seongmin·2022년 11월 20일
0

Security

목록 보기
4/10
post-thumbnail

DelegatingPasswordEncoder

DelegatingPasswordEncoder 는 Spring Security에서 지원하는 PasswordEncoder 구현 객체를 생성해주는 컴포넌트로써 DelegatingPasswordEncoder를 통해 애플리케이션에서 사용할 PasswordEncoder를 결정하고, 결정된 PasswordEncoder로 사용자가 입력한 패스워드를 단방향으로 암호화 해준다.

장점

  • DelegatingPasswordEncoder 를 사용해 다양한 방식의 암호화 알고리즘을 적용할 수 있는데, 우리가 사용하고자 하는 암호화 알고리즘을 특별히 지정하지 않는다면 Spring Security에서 권장하는 최신 암호화 알고리즘을 사용하여 패스워드를 암호화 할 수 있도록 해준다.

  • 패스워드 검증에 있어서도 레거시 방식의 암호화 알고리즘으로 암호화 된 패스워드의 검증을 지원한다.

  • Delegating이라는 표현에서도 DelegatingPasswordEncoder의 특징이 잘 드러나듯이 나중에 암호화 방식을 변경하고 싶다면 언제든지 암호화 방식을 변경할 수 있다.

    • 단 이 경우, 기존에 암호화 되어 저장된 패스워드에 대한 마이그레이션 작업이 진행되어야 한다.

사용

  • DelegatingPasswordEncoder를 이용한 PasswordEncoder 생성
// PasswordEncoderFactories로 만들 수 있다.

PasswordEncoder passwordEncoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();
  • Custom DelegatingPasswordEncoder 생성

Spring Security에서 지원하는 PasswordEncoderFactories 클래스를 이용하면 기본적으로 Spring Security에서 권장하는 PasswordEncoder를 사용할 수 있지만 필요한 경우, DelegatingPasswordEncoder로 직접 PasswordEncoder를 지정해서 Custom DelegatingPasswordEncoder를 사용할 수 있다.

String idForEncode = "bcrypt";
Map encoders = new HashMap<>();
encoders.put(idForEncode, new BCryptPasswordEncoder());
encoders.put("noop", NoOpPasswordEncoder.getInstance());
encoders.put("pbkdf2", new Pbkdf2PasswordEncoder());
encoders.put("scrypt", new SCryptPasswordEncoder());
encoders.put("sha256", new StandardPasswordEncoder());

PasswordEncoder passwordEncoder = new DelegatingPasswordEncoder(idForEncode, encoders);

Map encoders 에 원하는 유형의 PasswordEncoder를 추가해서 DelegatingPasswordEncoder의 생성자로 넘겨주면 디폴트로 지정( idForEncode )한 PasswordEncoder를 사용할 수 있다.

암호화 된 Password Format

  • {id}encodedPassword

  • BCryptPasswordEncoder 로 암호화 할 경우,

    • {bcrypt}$2a$10$dXJ3SW6G7P50lGmMkkmwe.20cQQubK3.HZWzG3YB1tlRy.fqvM/BG

      • PasswordEncoder id는 “bcrypt”

      • encodedPassword는 "$2a$10$dXJ3SW6G7P50lGmMkkmwe.20cQQubK3.HZWzG3YB1tlRy.fqvM/BG” 이다.

  • Pbkdf2PasswordEncoder로 암호화 할 경우,

    • {pbkdf2}5d923b44a6d129f3ddf3e3c8d29412723dcbde72445e8ef6bf3b508fbf17fa4ed4d6b99ca763d8dc

      • PasswordEncoder id는 “pbkdf2”

      • encodedPassword는 “5d923b44a6d129f3ddf3e3c8d29412723dcbde72445e8ef6bf3b508fbf17fa4ed4d6b99ca763d8dc” 이다.


암호화 알고리즘

  • 해시(Hash) 알고리즘

해시 알고리즘은 단방향 암호화를 위한 핵심 알고리즘이다. 단방향 암호화라는 용어에서도 그 특성이 잘 드러나듯이 한번 암호화 되면 복호화 되기 어려운 특성을 가지고 있다.

데이터베이스에 암호화 되어 저장되는 패스워드 자체는 사용자가 입력한 패스워드와 비교해 올바른 패스워드를 입력했는지 검증하는 용도이기 때문에 다시 복호화 될 필요가 없다.

따라서 해시 알고리즘을 이용해 패스워드를 암호화 하는것은 괜찮은 선택이다.

  • MD5(Message Digest 5)

MD5는 초창기에 사용하던 MD2, MD4 해시 알고리즘의 결함을 보완한 알고리즘이다. 하지만 MD5 역시 단방향 알고리즘인데도 불구하고 복호화가 된 사례가 종종 발견되어 지금은 거의 사용하지 않는 알고리즘이다.

MD5에서 기억하면 좋은 것은 다이제스트(Digest)라는 용어다. 다이제스트(Digest)는 원본 메시지를 암호화한 메시지를 의미하는데 암호화 기술에 굉장히 자주 사용되는 용어이므로 기억을 하면 좋을 것 같다.

  • SHA(Secure Hash Algorithm)

MD5의 결함을 보완하기 위해서 나온 대표적인 해시 알고리즘이 SHA 알고리즘이다. SHA 알고리즘은 해시된 문자열을 만들어내기 위해 비트 회전 연산이 추가된 방식이다.
즉, 해시된 문자열의 비트 값을 회전하면서 반복적으로 해시 처리를 하는 것이다.

원본 메시지를 한번 해시 처리해도 우리가 눈으로는 알기 힘든 문자열이 생성되는데, 해시 처리된 문자열의 비트 값을 옮겨가면서 반복으로 해시 처리를 하면 아주 강력한 해시 문자열이 생성이 된다.

그런데 SHA 알고리즘으로 해시 처리된 메시지는 사람의 눈이나 머리로는 도저히 원본 메시지를 알아내기 힘들 것 같지만 컴퓨터는 알아낼 수 있다.

해커 입장에서는 사용자가 패스워드로 사용할만한 문자열들을 미리 목록(Rainbow Table)으로 만들어 놓고, 이 목록에 있는 문자열을 동일한 알고리즘으로 암호화 한 후, 탈취한 암호화 된 문자열과 서로 비교하는 작업을 통해 패스워드의 원본 문자열을 알 수 있게되는데, 이러한 공격을 Rainbow Attack이라고 한다.

  • Rainbow Attack에 대한 대응책

컴퓨터의 성능이 좋아지다보니 자동화된 Rainbow Attack을 통해 비교할 수 있는 다이제스트(Digest)의 양이 초당 50억개 이상이라고 한다.

그런데 Rainbow Attack을 100% 무력화 할 순 없겠지만 컴퓨터가 다이제스트(Digest)를 비교하는 작업의 횟수를 줄일 방법은 있다.

가장 단순한 방법은 앞에서 살펴본 SHA 알고리즘처럼 해시된 다이제스트를 또 해시하고, 또 해시된 다이제스트를 반복적으로 해시하는 것이다 (이를 키 스트레칭이라고 한다).
해시 처리가 반복되면 될수록 다이제스트(Digest)를 비교하는 횟수도 현저히 줄어든다.

또 한가지 방법은 솔트(Salt)를 이용하는 방법이다.
솔트(Salt)란 패스워드로 입력하는 원본 메시지에 임의의 어떤 문자열을 추가해서 해시 처리하는 것을 의미한다.
솔트(Salt)를 추가하면 Rainbow Table을 이용해 비교해야 되는 경우의 수가 늘어나기 때문에 완벽하지는 않지만 Rainbow Attack에 대응할 수 있다.

  • Work Factor를 추가한 Hash 알고리즘

해시 알고리즘을 연구하는 사람들의 고민 중 하나는 공격자가 Rainbow Attack과 같은 공격을 통해 해시된 메시지를 알아내려고 시도하더라도 어떻게 하면 최대한 느리게 최대한 비용이 많이 들게 할수 있을까이다.

이런 고민을 통해서 탄생한 Hash 알고리즘이 PBKDF2, bcrypt, scrypt이다.
여기서 말하는 Work Factor는 공격자가 해시 된 메시지를 알아내는데 더 느리게 더 비용이 많이 들게 해주는 특정 요소를 의미한다.

PBKDF2bcrypt의 경우 Work Factor로 솔트와 키 스트레칭을 기본적으로 사용하지만 내부적으로 훨씬 복잡한 알고리즘을 이용해서 공격자의 공격을 느리게 만든다.

scrypt는 기본적으로 다이제스트 생성 시, 메모리 오버헤드를 갖도록 설계 되어 있기 때문에 무차별 대입 공격(Brute Force Attack)을 시도하기 위해 병렬화 처리가 매우 어려운 특징이 있다.

0개의 댓글