Django | 인증 & 인가 ①Bcrypt

김민호·2021년 9월 25일
0

DJANGO

목록 보기
4/18
post-thumbnail

인증 (Authentication)

1. 로그인 절차

  1. 유저 아이디와 비밀번호 생성
  2. 유저 비번 암호화해서 DB에 저장
  3. 유저 로그인
  4. 유저가 입력한 비밀번호를 암호화 한 후 암호화된 이 비밀번호와 DB에 저장된 유저 비밀번호와 비교
  5. 일차하면 로그인 성공
  6. 로그인 성공하면 access token을 클라이언트에게 전송
  7. 유저는 로그인 성공 후 다음 요청부터는 access token을 첨부해서 서버에 전송함으로서 매번 로그인하지 않아도 됨

2. 유저 비밀번호 암호화

  • 유저의 비밀번호는 절대 그대로 DB에 저장하지 않는다
    • DB가 해킹당하면 유저 비밀번호 그대로 노출
    • 외부 해킹이 아니더라도 내부 관계자들이 비밀번호를 볼 수도 있음
  • 유저의 비밀번호는 꼭 암호화해서 저장하자
    • DB가 해킹당해도 비밀번호가 노출되지 않으며
    • 내부 관계자들도 볼 수 없음
  • 비밀번호 암호에는 단방향 해쉬 함수(one-way hash function)가 일반적으로 쓰임
    • 단방향 해시 함수는 원본 메세지를 변환하여 암호화된 메세지인 다이제스트(digesg)를 생성한다.
    • 단방향이라고 불리는 이유 : 원본메세지 → 암호화된 메세지를 구하기는 쉽지만 그 반대는 구할 수 없기 때문
    • Avalanche effect : 비밀번호가 한 글자만 다르더라도 해쉬 함수의 값은 완전히 다르게 나오는 효과
    • 해쉬 함수 : 데이터를 입력받으면 일정한 길이의 비트열로 반환시켜주는 함수
      입력값의 길이가 달라도 출력값은 항상 고정된 길이로 반환되며,
      동일한 값이 입력되면 언제나 동일한 출력값을 반환함
      한 글자만 달라져도 출력값은 완전히 달라짐

비밀번호 암호화 실습

  • "password"라는 비번과 2라는 숫자 하나 더 붙은 "password2"라는 비번의 해쉬 함수 값이 완전히 다른 것을 확인할 수 있음
  • import hashlib : 파이썬에 내장된 해쉬 함수 라이브러리 불러오기
  • sha256() :
    • 이건 hash를 만드는 여러 함수 중에 하나임.
    • SHA1, SHA224, SHA256, SHA384, SHA512 이런 종류가 있음.
    • sha256()은 SHA(Secure Hash Algorithm) 알고리즘의 한 종류로서 256 비트로 구성되며 64자리 문자열을 반환. 2의 256 제곱만큼의 경우의 수가 만들어질 수 있기 때문에 비교적 안전하다고 평가
  • a.hexdigest() : 암호화된 메세지로 반환하겠다는 의미

3. Bcrypt

1) 개념

Bcrpyt(비크립트)란 단방향 해쉬 함수에도 취약점들이 있고 이런 취약점들을 보완하기 위해 SaltingKey Streching 이라는 기법을 추가하여 사용되는 암호 해시함수 오픈소스 라이브러리

  • Rainbow table : 단방향 해쉬 함수의 취약점.미리 해쉬값을 계산해서 입력값이랑 연결해놓은 테이블. 일반적으로 해쉬값을 보면 암호화가 되어서 비번을 알수 없지만, 그 암호화된 비번을 레인보우 테이블에서 찾아보면 입력값(비밀번호)를 찾을 수 있음
  • Salting : 실제 비밀번호에 추가적으로 소금을 뿌리는 것처럼 랜덤 데이터를 뿌려서(더해서) 해시값을 생성하는 것. 이러면 비밀번호가 간단하더라도 salt와 함께 해쉬했기 때문에 레인보우 테이블에서 찾을 수 없음
  • Key Streching : 단방향 해쉬값을 계산한 후 그 해쉬값을 또 해쉬하면서 반복

2) bcrpyt의 메소드

  • gensalt() : 소금생성기. salt는 해시 함수에서 암호화된 비밀번호를 생성할 때 추가되는 바이트 단위의 임의의 문자열. 실행할 때마다 랜덤한 값들이 생성됨
  • hashpw(password, salt) : 비밀번호와 salt를 인자로 받아서 암호화된 비밀번호를 생성함. salt = bcrypt.gensalt()
  • checkpw(password, hashedPassword) : boolean 타입으로 비밀번호와 암호화된 비밀번호를 인자로 받아 같을 경우 true, 다를 경우 false를 반환. 로그인시 패스워드 확인할 때 사용.
    인자1 = 사용자가 입력한 패스워드
    인자2 = 해시된 값

3) 실습

>>> import bcrypt
>>> pw = '1234'
>>> bcrypt.hashpw(pw, bcrypt.gensalt())

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/macbookpro/miniconda3/envs/westagram/lib/python3.8/site-packages/bcrypt/__init__.py", line 80, in hashpw
    raise TypeError("Unicode-objects must be encoded before hashing")
    
TypeError: Unicode-objects must be encoded before hashing

먼저 password = '1234' 라는 패스워드를 bcrypt를 이용해서 해싱해려고 하니까 TypeError가 발생했고 "유니코드 객체는 해싱전에 인코딩 되어야 한다" 고 써있음

:: 인코딩(encoding)

  • 파이썬의 문자열을 byte 코드인 utf-8, euc-kr, ascii 형식으로 변환(문자열 → 숫자)
  • Bcrypt에서 암호화할 때는 str 형태가 아니라 bytes 데이터를 이용하게 되는데 암호화할 때 암호화할 내용을 bytes화 해줘야 함
  • 인코딩한다는 것은 쉽게 말해서 값에 .encode('utf-8') 를 붙여주라는 말
>> encoded_pw=pw.encode('utf-8')
>> encoded_pw
b'1234' # 바이트화 되었음


:: 디코딩(decoding)

  • utf-8, euc-kr, ascii 형식의 바이트 코드를 문자열로 변환(숫자 → 문자열)
  • 디코딩한다는 것은 쉽게 말해서 값에 .decode('utf-8')를 붙여주라는 말
>> decoded_pw = encoded_pw.decode('utf-8')
>> decoded_pw
'1234' # 다시 문자열이 되었음
  • 인코딩하여 다시 해싱
  • salt = bcrypt.gensalt() 이렇게 솔트값을 salt라는 변수에 담아서 사용하기도 함
In [9]: import bcrypt

In [10]: bcrypt.hashpw(b"secret password", bcrypt.gensalt())
Out[10]: b'$2b$12$PbMmldZR8JC0uq8wVxYpV.UTQYfccTnh1kK8VHdHwvCATdreOu37G'

In [11]: bcrypt.hashpw(b"secret password", bcrypt.gensalt()).hex() 🔴
Out[11]: '2432622431322433504465626e4c64643542776b3546754e38524b4c2e50714b334e6d57324264534e453346642f656f7453476758532f6961307761'
profile
개발자로서의 삶은 https://velog.io/@maxminos 에서 기록하고 있습니다 😀

0개의 댓글