2월 22, 2022

[인증&인가] bcrypt

bcypt라는 salting과 key stretching(해싱을 여러번 반복함)을 담당하는 라이브러리를 사용하여 사용자가 입력한 password의 암호화를 진행합니다.



bcrypt는 "해싱 알고리즘" , 즉 일종의 블랙박스 같은 것입니다.


'hello'라는 string을 넣으면, 블랙박스를 거쳐서 랜덤한 값이 나옵니다.
여기서 hello를 몇번 넣던간에. 블랙박스는 항상 같은 해쉬값을 뱉어냅니다.
그러나 역으로 해쉬값 -> 'hello'로 거슬러 올라가기는 불가능합니다.

bcrypt는 고의적으로 느리게 설계됐습니다. 이는 가끔식 DB가 공격당할 수 있기 때문입니다.
좀 더 자세히 설명해보겠습니다.
대부분의 사람은 각기 다른 비밀번호를 기억하기 힘들기 때문에, 비슷한 패턴 혹은 완전히 똑같은 비밀번호를 이 사이트, 저 사이트에서 돌려쓰고는 합니다.
이렇게 같게 설정된 비밀번호는 여러 사이트의 DB에 저장돼 있습니다.

만약 해커가 이들 중 한 사이트의 DB에 접근하는 데 성공했다면 어떻게 될까요?
해커는 DB에서 얻어낸 pw로, 이를 여기저기 다른 사이트에서 사용할 수 있습니다.

따라서, 해커가 DB에 접근해도 사용자의 비번을 알 수 없도록 비밀번호를 암호화해서 DB에 저장해야 합니다. 이때 해싱을 하기 위해 bcrypt를 사용합니다.
이제 해커는 DB를 얻어내도, 해싱된 pw값만을 가지고 있습니다. 

그러나 이것도 완벽한 보안 방법은 아닙니다.
해커들은 password와 그것의 bcrypt hash를 가지고 Dictionary attack 이라는 것을 합니다.
Dictionary와 훔쳐낸 db를 일일이 대조하며, 해싱값에 일치하는 password를 찾아내는 것이죠
따라서 , 이를 방지하기위해, password를 바로 해싱하지 않고 salt라는 것을 씁니다.

salt는 단순 스트링입니다.

password + salt를 해싱하고, 이것을 DB에 저장한다면 기존의 딕셔너리 공격은 통하지 않습니다.

그러나 해커가 salt값에도 접근하게 된다면, 해커는 이 salt값을 가지고 또 다른 딕셔너리를 만들어 공격을 시도할 수 있습니다. 

그러나, 앞서 설명했듯이 bcrypt는 매우 느리기에, 이 딕셔너리를 만드는데 시간이 한참 걸립니다. 그래서 공격이 무의미하게 만들어버리죠. 이것이 bcrypt를 굳이 느리게 만든 이유입니다.


  • bcrypt는 str이 아닌 Bytes 형태의 데이터를 암호화하기에, pw를 암호화할시 bytes로 만들어줘야 합니다.
  • 이때 encode()를 사용하는데, 알아볼 수 있는 형태로 만들기 위해 utf-8 유니코드 문자 규격을 사용합니다
  • .encode() 의 기본값은 'utf-8'입니다
  • str을 encode하면 bytes / bytes를 decode하면 str입니다
  • 암호화를 마친 데이터의 타입 또한 bytes입니다.
  • 암호화한 비밀번호가 맞는지 확인하기 위하여
    • bcrypt.checkpw(사용자로부터 입력받은 패스워드, 저장된 암호화된 패스워드)
    • 이때 두 인자의 데이터 타입은 모두 Bytes여야 합니다