API를 만들 때 login 기능을 구현하면서 password를 암호화하여 저장하기 위해 bcrypt를 사용하였다. Bcrypt가 password를 암호화해준다는 것은 알지만 좀 더 자세히 알아보기위해 해당 posting을 작성하고자 한다.
Bcrypt란 blowfish 암호에 기반을 둔 암호화 hash 함수로, rainbow table 공격 방지를 위해 salt를 통합한 bcrypt는 적응형 함수의 하나이다.
위의 정의로는 이해가 잘 되지 않는다. blowfish 암호는 뭐고? rainbow table은 뭐고? salt?는 뭔가?
Bcypt는 다음과 같이 구성된다.
$2b$[cost]$[22 character salt][31 character hash]
ex)
$2a$10$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LJZdL17lhWy \/ \/ \____________________/\_____________________________/ Alg Cost Salt Hash
- 2a : Hash algorithm 식별자(bcrypt)
- 10 : Cost factor (
2^10
==> 1,024 rounds)- N9qo8uLOickgx2ZMRZoMye : 16바이트(128비트) salt, base64-encoded to 22 characters
- IjZAgcfl7p92ldGxad68LJZdL17lhWy : 24바이트(192비트) hash, base64-encoded to 31 characters
- Bcrypt를 실제로 python으로 Django에서 사용한 예시를 보자.
우리는 bcrypt를 로그인 화면을 구현할 때 사용하였다.
1) password를 hash함수로 암호화 할 때
import bcrypt password = '1234' hashed_password = bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt()) print(hashed_password) #output : b'$2b$12$BZb8wpqKsSlWirtF1tpVGunnFqsFnenmCixPCQn3qYzltIh6YL1f2' print(type(hashed_password) #<class 'bytes'> hashed_password = hashed_password.decode('utf-8')
Hashed 했을 때 암호화된 출력물의 type은 'bytes'이다.
하지만, password는 DB에 str 형태로 저장이 되어야 하므로 decode를 해준다.
2) Hashed 된 password를 저장된 password와 맞는지 확인할 때
input_password = '1234' print(bcrypt.checkpw(input_password.encode('utf-8'), hashed_password.encode('utf-8'))) return True
input 받은 password를 checkpw()함수 내에서 encoding하여 encoding한 저장되있던 hashed_password와 비교한다.
같으면 True이고 다를 땐 False이다.
📖 출처 :
https://ko.wikipedia.org/wiki/Bcrypt
이번 posting에서는 암호화할 떄는 bcrypt라고 무의식적으로 사용했던 것에 대해 좀 더 자세히 알아보았다. bcrypt도 뚫리는 경우가 있다는 데 참... 기술에 발전만큼 그것을 알아내려하는 욕구? 창과 방패?의 기술 또한 대단한 것 같다... :)