Bcrypt는 무엇이고 왜 사용할까???

HeavyJ·2023년 9월 26일
0

자바/스프링부트

목록 보기
17/17

현재 IT 회사의 인턴으로 백엔드 개발 직무에서 일하고 있습니다😃. 제가 맡은 업무는 기존 몽고 DB에 존재하는 유저 정보를 Postgresql로 이관시키는 과정에서 암호화된 패스워드가 plain password와 일치하는지 검증하는 작업을 합니다.

이 과정에서 Bcrypt 암호화에 대해 알게 되었고 공유하면 좋은 내용들이 많아 포스팅을 하게 됐습니다!

1. 암호화의 종류 -> 단방향 or 양방향

먼저, Bcrypt 암호화에 대해 알아보기 전에 암호화의 방식에는 크게 2가지가 있습니다.

  • 단방향 암호화
  • 양방향 암호화

단방향과 양방향의 가장 큰 차이점이 뭘까요??
바로, 복호화에 있습니다.

단방향 알고리즘은 암호화만 가능하고 복호화가 불가능한 반면, 양방향 알고리즘은 암호화도 가능하고 복호화도 가능합니다.

양방향 알고리즘은 크게 대칭키, 비대칭키 방식을 사용하여 암호화 복호화가 진행이 됩니다.
간단하게 설명하면 대칭키는 암호화와 복호화에 같은 키가 사용되는 암호화 방식이고 비대칭키는 암호화와 복호화에 사용되는 키가 다른 방식입니다.

2. 패스워드에 왜 단방향 암호화 방식을 사용할까?

그렇다면 생각해볼 점은 왜 단방향 방식을 패스워드에 적용을 할까요?

결론부터 말하자면 보안 때문입니다.

비밀번호의 경우 유출될 경우 해커가 사용자 행세를 하며 사이트 혹은 플랫폼을 사용할 우려가 있습니다. 이런 상황을 방지하기 위해 복호화가 불가능한 단방향 암호화를 사용하는 것입니다.

3. BCrypt를 사용하는 이유

단방향 암호화 방식의 한계

단방향 암호화 방식은 주로 해시 알고리즘을 이용하여 구현하고 있습니다. 근데 이 해시 알고리즘에는 치명적인 약점이 존재합니다. 해시 알고리즘은 동일한 평문에 대하여 항상 동일 해시값을 갖게 됩니다. 즉, 특정 해시 알고리즘에 대해 특정 평문이 어떤 해시값을 갖는지 알 수 있다는 위험 요소가 존재합니다.
실제로, 함수의 해시 값들을 대량으로 정리한 레인보우 테이블이 존재하는데 이 레인보우 테이블의 해시값을 사용해서 사용자의 패스워드를 유추하여 공격하는 해킹 방식을 레인보우 공격이라고 합니다.

단방향 암호화의 단점을 보완하자

이렇게 동일한 평문이 동일한 해시값으로 귀결되는 상황을 막기 위해 솔팅과 키 스트레칭 기법을 사용할 수 있습니다.

⚡️솔팅

솔팅은 단방향 해시로 암호화를 진행할 경우 본래 데이터에 추가 랜덤 데이터를 더해 암호화를 진행하는 방식입니다.
추가 데이터가 포함되었기 때문에 원래 데이터의 해시값에서 달라지는 효과를 볼 수 있습니다.

⚡️키 스트레칭

단방향 해시값을 계산한 뒤에 그 해시값을 다시 해시하고 이를 다시 해시하는 반복 방식입니다.
여기서 round수라는 값을 보게 되는데 이 round 수는 키 스트레칭을 구현하는 중요한 매개변수입니다. 높은 라운드 수를 사용할수록 해시 연산을 더욱 복잡하게 만들어 레인보우 테이블 공격을 어렵게 만듭니다. 왜냐하면 라운드 수가 높을 수록 비밀번호 해시 생성 시간이 오래 걸리기 때문에 공격자의 공격 속도를 늦출 수 있습니다.
SpringBoot의 Spring Security에서 사용하는 BCrypt 기본 라운드 수는 10입니다.

4. BCrypt 암호화된 패스워드를 분석해보자

저는 이 사이트에서 BCrypt 암호화를 해봤습니다.
https://bcrypt-generator.com/


helloworld라는 plain text를 round 수 10으로 암호화를 하니까

$2a$10$mg0rqIsmYYOpCjuBNkh/8.7CP8QBjxcZ/DMUMDMlEtsJUrj2moPSC

해당 암호화 패스워드를 얻을 수 있었습니다.
여기서, $2a는 bcrypt의 버전정보입니다. 버전에 따라 $2a, $2b가 나오기도 합니다.
그리고 $10은 round 수를 의미합니다. round 수가 증가할 수록 연산의 cost가 증가하게 됩니다.

나머지 문자열은 솔트와 해시 값이 섞여 들어가있습니다.

$2a$10$BBOLHKF6hpcLFGEnocmNNuepiEFkhRVCJr9FAOgZbAhdGjsjK0kne
$2a$10$y7vbCdXsyx6.oLcm9AZLzOnx.9SL220CdIWGhAjOa7xZ0n4zyKu.i
$2a$10$cuCHdHIkcMrNUDedHPPdYu8P2OeWvIzeQU5MI2WPiv4/yZG3h/dhC

3번 더 암호화를 했을때 결과가 다 다르게 나옵니다.
솔트로 인해 round 수가 동일해도 다른 해시값이 도출되는 결과를 확인할 수 있습니다.

5. 패스워드 매칭은 어떻게 하는거지?

솔트값을 사용하면서 매번 다른 해시값이 나온다는 것은 오히려 패스워드 매칭을 불가능하게 만들지 않을까라는 생각이 듭니다.

하지만, BCrypt의 솔트 저장 방식이 이 문제를 해결해줍니다.

BCrypt는 솔트를 생성한 해시결과에 붙이는(포함하는) 방식으로 암호화 패스워드를 만듭니다. 즉, 검증을 할 때 해시 값 내부에 솔트 값이 포함되어 있기 때문에 솔트 값을 따로 저장하지 않아도 해싱된 값과 평문을 비교할 수 있게 됩니다.

검증을 할 때 추가적인 정보 필요없이 단순히 plain text와 암호화된 패스워드 이 두가지만 존재하면 일치하는지 불일치하는지 확인할 수 있습니다.

솔트를 그냥 해시값에 포함시켜도 안전한건가?

Salt 값이 노출되어도 Rainbow 테이블을 새로 만들기 어렵습니다. 실제로 10자리 입력값을 대상으로 레인보우 테이블을 만든다고 했을 때 1년 이상 걸린다고 합니다.
만약 round 수가 증가되면 rainbow 테이블 만드는 시간도 곱절로 늘어나기 때문에 공격자가 엄청나게 많은 시간과 노력을 하지 않는 이상 공격하기가 쉽지 않을 것입니다.

profile
There are no two words in the English language more harmful than “good job”.

0개의 댓글