[Spring] Bcrypt를 이용한 비밀번호 암호화

DyungE_100·2022년 4월 22일
1

Spring

목록 보기
5/7

0. 암호화 종류와 Bcrypt

0.1 암호화 종류

1) SHA-2(Secure Hash Algorithm2)

  • 미국 국가안보국(NSA)에서 설계한 암호화 해시 함수들의 집합이다.

  • digest size는 224, 256, 512 bit로 해시함수로 구성되어있다.

  • GPU를 이용한 연산 속도가 매우 빠르기 때문에 password 암호화에는 권장되지 않는다.

    • GPU 연산 속도가 빠를수록 공격자의 하드웨어를 통한 오프라인 brute-force에 더 취약하다.
    • 빠른 해시를 사용하여 암호화를 진행할 시 공격자는 오프라인 공격으로 초당 수 십억 개의 해시를 계산할 수 있다.

2) PBKDF2

DK = PBKDF2(PRF, Password, Salt, c, dkLen)

PRF : 출력 길이가 hLen인 두 파라미터(parameter)의 의사난수 함수(pseudorandom function)

Password : 파생 키(Derived Key)가 생성되는 마스터 암호

Salt : cryptographic salt로 알려진, 비트들의 시퀀스(a sequence of bits)

c : 바라는 반복 횟수

dkLen : 바라는 파생 키의 비트 길이

DK :  생성된 파생 키
  • 해시 함수의 컨테이너 역할을 한다.

  • 검증된 해시 함수만을 사용한다.

  • 해시 함수와 salt를 적용 후 해시 함수의 반복횟수를 지정하여 암호화가 가능하다.(식 참고)

  • 가장 많이 사용되는 함수이며, ISO 표준에 적합하다. NIST에서도 승인된 알고리즘이다.
    NIST Special Publication 800-132

3) Bcrypt

BCrypt.hashpw(password, BCrypt.gensalt())

  • 블로피시 암호에 기반을 둔 암호화 해시 함수이다. Rainbow Table 공격 방지를 위해 salt를 통합한 적응형 함수 중 하나이다. 현재까지 사용 중인 가장 강력한 해시 알고리즘 중 하나이다.

  • 반복 횟수를 늘려 연산 속도를 늦출 수 있으므로 연산 능력의 증가에도 brute-force 검색 공격에 대한 저항을 유지하게 된다.

  • .NET 및 Java를 포함한 많은 플랫폼, 언어에서 사용할 수 있다.

4) Scrypt

  • 2009년에 publish된 key derivation function이다.

  • 오프라인 brute-force 공격에 대해 수 십억 번의 작업을 수행할 정도로 강력하지만, 많은 양의 메모리와 CPU를 사용한다.

  • OpenSSL 1.1이상을 제공하는 시스템에서만 작동한다.

  • 여러 언어의 라이브러리로 제공된다.

  • 다른 암호 기반 KDF에 비해 많은 양의 메모리를 사용하도록 설계되었다.

  • 하드웨어를 구현하는 데 크기와 비용이 훨씬 비싸기 때문에, 주어진 자원에서 공격자가 사용할 수 있는 병렬 처리의 양이 한정적이다.


[Bcrypt가 비밀 번호 암호화에 추천되어지는 이유??]

Bcrypt 설계자들이 기사에서 언급한 내용

That means one should make any password function as efficient as possible for the setting in which it will operate. The designers of crypt failed to do this. They based crypt on DES, a particularly inefficient algorithm to implement in software because of many bit transpositions. They discounted hardware attacks, in part because crypt cannot be calculated with stock DES hardware. Unfortunately, Biham later discovered a software technique known as bitslicing that eliminates the cost of bit transpositions in computing many simultaneous DES encryptions. While bitslicing won't help anyone log in faster, it offers a staggering speedup to brute force password searches.

SHA 종류가 무조건 나쁜 것은 아니지만, SHA의 경우 일반적으로 GPU 연산에 유리한 32bit 논리 및 산술 연산만 사용하기 때문에 공격자가 빠른 연산으로 공격하기 유리하다.

이상적으로 봤을 때는 공격자가 유리한 게임이지만, 자원의 양은 한정적이므로 공격자의 속도를 늦출수록 암호화 해독을 하기 어렵고 오래 걸리게 된다. 그러므로 어떤 암호화 함수를 쓰던지 강력하겠지만 충분한 시도 횟수와 work-factor를 고려하였을 때, 방어자는 좀 더 느리게 설계된 암호화 방식에 의존하는 것이 더 낫다.

또한 비용이 많이 드는 Scrypt보단 구현이 쉽고 비교적 강력한 Bcrypt를 사용하기 편하다. 단, ISO-27001 보안 규정을 준수해야 하는 상황이라면 PBKDF2를 사용하는 것을 권장한다.

참고) Salt에 대하여

그냥 plainText로 저장된 비밀 번호라면 해킹하기 쉽겠지만 해시 함수를 사용하면 이를 방지할 수 있다. 하지만 해시 함수는 동일한 입력값에 대해 동일한 해시를 출력하므로 이마저도 Rainbow Table을 가지고 있다면 뚫리게 된다.

그리하여 나오게 된 개념이 Salting이다. 음식에 간을 치듯이, 해시 함수에 넣기 전에 난수를 추가하므로 인해 복잡도를 올리고 보안성을 높인다. DB에는 [Salt]값과 [비밀 번호 + Salt값]의 해시가 함께 저장되며, 유저는 이후 로그인 할 때마다 실제 비밀 번호를 입력하면, 서버는 해시값을 DB와 비교하여 입장 여부를 결정한다.

하지만 갈수록 컴퓨팅 자원은 저렴하지만 빨라지는 무어의 법칙에 의해, 이마저도 무력해질 수 있다. 따라서 기존 Salting한 해시 결과에 다시 동일한 Salt를 적용하는 과정을 적용시킬 수 있는데, 이렇게 반복할 때의 반복 횟수를 Salting Round라고 하며 DB에는 [Salt값]과 Salting Round만큼 반복하여 나온 [최종 해시값]을 저장한다.

1. Bcrypt 동작 원리와 결과 해시값 해석

1. Key Setup Phase

  • cost는 원하는 연산량, 소요시간 등을 말한다. 그 외의 파라미터로는 salt, password가 있다.

password를 가지고 key stretching을 하며 연산 속도를 늦춰준다.

2. Operation Phase

  • PlainText와 CiphterText 사이로 encrypt/decrypt하는 단계이다.

  • 1) OrpheanBeholderScryDoubt 는 192bit (=24byte)이며, 1단계의 결과이다.

  • 2) 이 결과를 가지고 ekblowfish가 동작하는 ECB mode로 64번 암호화를 진행한다.

  • 3) 암호화 루프 63번의 결과 + salt 128bit (=16byte) 등을 합친 것이 최종 결과다.

3. 결과 해시값 해석

  • $2b는 bcrypt의 버전 정보이다.

  • $10은 10round를 의미하며, cost 정보를 의미한다. 즉, 2^10번 돌린 것이다.

  • 버전과 cost 정보를 제외한 나머지가 Salt + CipherText 인데 Base-64로 인코딩 된 것이다. 앞부분 22 문자를 Decode 해주면 16 바이트 Salt 가 된다. 나머지가 CipherText 이다.

2. Spring에서 Bcrypt 사용하기

Springboot 2.6.6 version, java 11version, 관리 도구는 maven을 사용하였다.
Springboot security를 사용하지 않고 pom.xml에 의존성을 추가하여 사용해보았다.

- 1) 의존성 추가

- 2) Bcrypt를 사용하는 컴포넌트 만들기

Salt를 추가하여 Bcrypt방식으로 encrypt하는 메서드와
로그인 시 입력한 기존의 패스워드와 해시된 패스워드를 비교해주는 isMatch 메서드를 작성한다.

- 3) Service를 구현할 때 가져온 DTO를 통해 암호화 진행

작성한 컴포넌트를 가져와 password 암호화를 진행해준다.
DTO를 가져와 비밀번호를 암호화하고 setter를 통해 해시된 비밀번호로 바꿔준다.
Mybatis를 이용하여 SQL문과 Mapping한 Mapper(DAO)를 통해 DB에 저장하라고 명령한다.

- 4) DB에 결과 저장 확인

다음과 같이 PostgreSQL DB에 저장된 것을 확인할 수 있다.





https://velog.io/@kylexid/%EC%99%9C-bcrypt-%EC%95%94%ED%98%B8%ED%99%94-%EB%B0%A9%EC%8B%9D%EC%9D%B4-%EC%B6%94%EC%B2%9C%EB%90%98%EC%96%B4%EC%A7%88%EA%B9%8C,
https://jusths.tistory.com/158,
https://codingdog.tistory.com/entry/bcrypt%EB%8A%94-salt%EA%B0%80-%EB%A7%A4%EB%B2%88-%EB%8B%AC%EB%9D%BC%EC%A7%80%EB%8A%94%EB%8D%B0-match%EB%A5%BC-%EC%96%B4%EB%96%BB%EA%B2%8C-%EC%9E%98-%EC%8B%9C%ED%82%AC%EA%B9%8C%EC%9A%94,

0개의 댓글