[python][django]bcrypt & jwt 실습

Hyeseong·2021년 1월 8일
0

django

목록 보기
28/35

들어가기 전👩

앞서서 인증 인가에 대한 개념을 할짝! 했으니 지금은 직접 키보드 뚜드리면서👨‍💻 몸으로 익히는 TIME을 가져봐야해요

참고 할 만한 사이트 👨

bcrypt - pypi

비밀번호 해쉬에 관한 부분 👶

Work Factor 👶

본론

실습을 위한 가상환경
python venv 혹은 conda env로 가상환경을 만들게요.

bcrypt pyjwt 요 두개를 pip로 다운받습니다.

pip install bcrypt pyjwt

bcrypt

설치가 완료되었다면 Ipython을 실행시키고 'bcrypt'를 임포트할게요.
그리고 비밀번호를 해쉬해주는 hashpwd() 함수를 사용하고 rainbow table attack을 막기위해서 salt값을 추가하도록 할게요.

아래 형식의 메소드를 구현해줘야!! -> hash🎠가 만들어져요.

bcrypt.hashpw( 바이트값, bcrypt.gensalt() )

위 내용 1~4번 더 첨언해볼게요.

- 1번 : 일반적으로 성공하는 경우에요. 시작하는 홑따옴표 앞에 b붙은건 해당 문자열을 byte로 만들어줘요.

파이썬에서 문자열을 바이트로 만드는 방법은 아래와 같이 있어요.
추가 자료 - DelfStack - Convert String to Bytes in Python

  • b'문자열'키워드👓
  • '문자열'.encode('utf-8')👓
    제가 아는 선에서는 2가지 방법이 각각 있어요.
>>> byte = b'1234'
>>> print(type(byte))
<class 'bytes'>
>>> 
>>> byte2 = '1234'.encode('utf-8')
>>> print(type(byte2))
<class 'bytes'>

- 2번 : 오류 떳조? int

왜?! byte값이 아닌 인트라서!

- 3번 : int에는 encode속성 없다~

  • 문자열에만 encode()를 사용하여 -> byte 타입으로 바꿀수 있어요👓
  • 반대로 byte -> 문자열로 바꾸려면 'byte'.decode('utf-8')해주면 되겠주?👓

- 4번 : 1번과는 다르게 '문자열'.encode('utf-8')을 사용

bcrypt.gensalt()?

여러번 호출 시🧵

랜덤한 바이트 값들이 계속 나오는걸 확인 할 수 있어요.

>>> bcrypt.gensalt()
b'$2b$12$4utpZCeHmvvIb5QiTTalCO'
>>> bcrypt.gensalt()
b'$2b$12$UENnkg4C.26rJJBZVSx.h.'
>>> bcrypt.gensalt()
b'$2b$12$bSZ8oI3gFA1aGeDxjITcfO'
>>> bcrypt.gensalt()
b'$2b$12$g8l200cGq0zK2ukvD7TDHu'
>>> bcrypt.gensalt()
b'$2b$12$XH8kdj8F8IHeXyGmoxAoDe'
>>> bcrypt.gensalt()
b'$2b$12$cHvrW8GdC9p6VE0zJzlRge'
>>> bcrypt.gensalt()
b'$2b$12$XzJRkFWF5knlwIvDhiXxL.'
>>> bcrypt.gensalt()
b'$2b$12$lR9Y04quIsOko.Hwcf13Tu'

salt값을 hash랑 어쩌구 저쩌구가 뭐라구요?🧵

아래 1번에서 gensalt()로 만든 salt값이 hashpwd()의 2번째 인자에 둬서 결국 hash_pwd변수의 값 앞부분에 위치한걸 확인 할수 있조?!

bcrypt.checkpw()

checkpw() 말 그대로 값을 비교하여 True, False를 반환하는데요. 이때 함수의 인자로는 바이트가 들어갈까요? 아니면 문자열일까요?

2번째줄에 password가 바이트라는거 확인! 그렇다면 7번째줄의 메서드에도 정황상 같은 데이터 타입을 비교할 거라는 예감 오나요?

네! 하지만 해쉬된 바이트로 bycrpt.hashpw() 값 한번 보안처리된 바이트 값이조?

즉!

checkpw( 그냥바이트값, 해쉬된 바이트값)

이라는 말인거조!

1 >>> import bcrypt
2 >>> password = b"super secret password"
3 
4 >>> hashed = bcrypt.hashpw(password, bcrypt.gensalt(14))
5 
6 
7 >>> if bcrypt.checkpw(password, hashed):
8 ...     print("It Matches!")
9 ... else:
10 ...     print("It Does not Match :(")
11

JWT

위에서 본 bcrypt는 단방향이에요.
즉, 복호화가 불가능에 가깝지만, 이제 살펴볼 JWT는 Jason Web Token을 복호화하면 Payload에 암호화하여 담긴 정보를 확인할 수 있어서 사용자가 로그인하면 백엔드 서버가 JWT 토큰을 frontend에 발행하게 되고 프런트앤드는 API를 요청시 request header의 Authorization 키에 access_token을 넣어서 보내면 백엔드 서버는 이 access_token에 담겨있는 header! payload signiture를 확인해서 인가 방법을 제공합니다.

즉, HTTP의 특성인 Stateless로 인하여 이전 사용자의 로그인을 유무를 알수 없지만 하지만 로그인시에발행한 JWT 토큰 정보를 근거로 백엔드 서버에서는 이 토큰 정보를 해석하는 decorator를 만들어서 인가가 필요한 endpoint들을 사용할 수 있어요.

참고 할 만한 사이트 👨

PyJWT - Pypi

실습

jwt.encode()

  • 첫 번째 인자는 딕셔너리 객체를 넣어줍니다.
  • 두 번째 인자는 SECRET_KEY인데요.
    • 실제 settings.py에 있는 SECRET_KEY를 끌어다가 사용해요.
  • 세 번째는 알고리즘입니다.

주의1
jwt.encode(1번째, 2번째, algorithm='HS256')
jwt.decode(1번째, 2번째, algorithms='HS256')

별표 백만개!!!(오류 잡아낸다고 힘들었어요.)😥😣

  • encode()는 algorithm이 단수형!
  • decode()는 algorithms이 복수형!

주의2
4번째 앞에 b키워드가 없다?
그건 jwt 1.7 -> 2.0 넘어가면서 byte->str으로 타입이 변경되었기 때문에 그래요.

1 >>> import jwt
2 >>> encoded = jwt.encode({'user-id': 5}, "secret", algorithm="HS256")
3 >>> print(encoded)
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzb21lIjoicGF5bG9hZCJ9.Joh1R2dYzkRvDkqv3sygm5YyK8Gi4ShZqbhK2gxcs2U


4 >>> type(encoded_jwt)
<class 'str'>

5 >>> jwt.decode(encoded, "secret", algorithms=["HS256"])
{'user-id': 5}
profile
어제보다 오늘 그리고 오늘 보다 내일...

0개의 댓글