Django 8. bcrypt를 통한 비밀번호 암호화

jiffydev·2020년 10월 13일
0

1. 인증(Authentication) & 인가(Authorization)

비밀번호 암호화에 관한 이야기를 하기 전에 웹에서의 인증과 인가에 대해 설명하고자 한다. 둘 다 API에서 자주 구현되는 기능들이다. 인증은 한 유저가 유효한 유저인지 검증하는 과정이다. 결국 유저의 아이디와 비밀번호가 등록된 것과 일치하는지 확인하는 절차이며, 그 과정에서 아이디, 비밀번호를 생성할 수 있는 기능이 필요하게 된다.
인가는 어떤 기능과 관련해서 유저가 그 기능을 request할 권한이 있는가를 확인하는 절차이다. 예를 들면 학교 홈페이지에서 학생은 교수나 직원만이 열람할 수 있는 페이지에 접근할 권한이 없어, 학생 아이디로 페이지를 열게되면 권한이 없다고 뜨는 것 등이 있다.

2. Django에서의 유저 비밀번호 저장

인증/인가에 관한 지식이 없이 처음 유저데이터를 생성하는 뷰를 만들게 되면, 보통은 입력받은 비밀번호를 그대로 데이터베이스에 저장하게 된다. 하지만 비밀번호를 있는 그대로 넣게 되면 DB가 해킹당했을 때의 타격이 엄청날 것이다. 그렇기 때문에 비밀번호를 입력받은 후 이를 다시 암호화 해 DB에 넣는 과정을 추가하게 되었다.

3. bcrypt

비밀번호를 암호화 하는 알고리즘은 많이 존재하지만, 간단하면서도 강력한 암호화 기능을 제공하는 것은 bcrypt이다. 파이썬 뿐만아니라 다른 언어에서도 사용이 가능하기 때문에 사용자도 많다. 그래서 장고로 프로젝트를 할 때는 bcrypt를 사용해 비밀번호 암호화를 구현하고자 한다.

3-1. 설치

bcrypt를 사용하기 위해서는 우선 모듈 설치가 필요하다.
pip install bcrypt를 입력해 설치한 후 import bcrypt로 import 한 후 사용한다.

3-2. 비밀번호 암호화

유저가 입력한 비밀번호를 암호화하기 위해서는 bcrypt.hashpw()메소드를 사용한다. 메소드의 인자로는 입력받은 유저의 비밀번호와 salt를 넣는데, 여기서 salt란 실제 비밀번호 이외에 추가적으로 무작위 데이터를 해시값에 더하는 방식으로 보안을 더 강화하는 요소이다. bcrypt에서는 gensalt()로 자동으로 salt를 생성할 수 있다. 따라서 비밀번호를 암호화 하는 코드는 hashed_password = bcrypt.hashpw(입력받은 비밀번호, gensalt()) 와 같이 된다. 그런데 입력받은 비밀번호를 그대로 넣으면 TypeError: Unicode-objects must be encoded before hashing 이와 같은 에러가 발생한다.
오류의 내용인즉슨, 입력받은 비밀번호는 문자형(유니코드)이기 때문에 바이트형으로 인코딩이 필요하다는 말이다. 그래서 입력받은 비밀번호를 인코딩하는 절차가 필요한데, encoded_password = 입력받은 비밀번호.encode('utf-8')로 인코딩을 해준 후에 hashpw에 넣어주면 된다.
암호화된 비밀번호인 hashed_password를 출력해 보면 b'nmijyft2@#$mfnjshK'등과 같은 의미없는 문자들의 나열이 나오고, type을 출력하면 bytes형이 나온다.

3-3. 비밀번호 저장

비밀번호를 암호화 했다면 암호화된 비밀번호를 DB에 저장해야 한다. 저장하는 방법은 두 가지 정도로 나눌 수 있는데, 하나는 처음부터 모델에서 비밀번호 필드를 BinaryField로 지정해 해싱된 비밀번호를 그대로 넣는 방법이고 다른 하나는 해싱된 비밀번호를 decode해서 문자열로 변환 후 문자열 데이터를 CharField에 넣는 방법이다.
첫 번째 방법은 모델을 설계할 때 필드만 잘 설정해 주면 암호화 된 비밀번호를 그대로 넣기만 하면 되니 간단하다. 두 번째 방법은 조금 복잡한데, decoded_hashed_pw = hashed_password.decode('utf-8')을 통해 문자열로 만들어 준 후 decode 된 비밀번호를 DB에 넣어야 한다.

3-4. 로그인

비밀번호를 잘 저장했다면 유저가 로그인 할 때는 입력한 비밀번호와 저장된 비밀번호가 같은지 확인해야 한다. 유저가 입력한 비밀번호는 문자열이고, 우리가 저장한 비밀번호는 암호화 된 값인데 어떻게 비교해야 할까?
정답은 bcrypt에서 제공하는 checkpw()메소드를 사용하는 것이다. 이 메소드는 유저가 입력한 비밀번호와 저장된 비밀번호를 인자로 받는데, hashpw()와 마찬가지로 반드시 bytes 타입으로 입력해야 한다. 그래서 만약 위에서 첫 번째 방법으로 DB에 저장했다면 입력받은 비밀번호만 encode를 통해 bytes형으로 바꿔주면 되고, 두 번째 방법을 사용했다면 입력받은 비밀번호와 저장된 비밀번호 모두 encode를 해 주어야 한다.

요약

  1. bcrypt를 설치하여 사용한다.
  2. 비밀번호 암호화는 hashpw(입력받은 비밀번호, gensalt())로 할 수 있다. (입력받은 비밀번호는 우선 encode 할 것)
  3. DB에 넣을 때는 필드 타입을 BinaryField로 하여 바로 넣거나 CharField라면 decode 해서 넣는다.
  4. 로그인 시에는 checkpw(입력받은 비밀번호, 저장된 비밀번호)로 일치하는지 확인한다. 두 인자 모두 bytes타입이어야 하므로, 필요에 따라 encode를 한다.
profile
잘 & 열심히 살고싶은 개발자

0개의 댓글