우리는 수많은 웹사이트 속에 있고,
웹사이트 수 만큼 존재하는 각자의 ID가 있다.
웹에서는 어떻게 ID, PW를 보관하고 비교하고 암호화할 수 있을까??
위키에 따르면 bcrypt는 비밀번호 해시함수다. (Hash
형 자료구조 참고)
Niels Provos와 David Mazieres에 의해 만들어졌으며 Blowfish라는 암호에 기반하였다.
일단 우리는 터미널에서 해당 입력어를 통해 install한다!
pip install bcrypt
그런 다음, import bcrypt
를 해주고, 비밀번호를 암호화를 설정해준다!
암호화하는 방법은 의외로 간단하다!
bcrypt.hashpw(문자열.encode('utf-8'), bcrypt.gensalt())
위와 같은 코드로 작성하면 되는데, 받는 인자는 다음과 같다.
실제 프로젝트에 적용해보면,
import json
from django.views import View
from django.http import JsonResponse
import bcrypt
from .models import Accounts
class AccountView(View):
def post(self, request):
data = json.loads(request.body)
# 필수사항 미입력시
try:
email = data['email']
password = bcrypt.hashpw(data['password'].encode('utf-8'), bcrypt.gensalt())
.
.
.
mysql> select password from accounts;
+-----------------------------------------------------------------+
| password |
+-----------------------------------------------------------------+
| 12345678 |
| b'$2b$12$TqRaIL6suby0BQHBVfNL6udGCgBxc0F3Uz5KtsUkqaHlT6xJZlxFy' |
+-----------------------------------------------------------------+
2 rows in set (0.00 sec)
이와같은 결과가 나온다.
mysql에도 예전에는 '12345678'로 들어갔던 암호가 알수없는 문자열로 들어간걸 볼 수 있다! (위대한 암호화!!)
이건 더 쉽다!(너무 쉽다 쉬워!!)
bcrypt
의 checkpw()
를 쓰면 된다. 이 함수는 2개의 인자를 갖는데,
으로 비교해주면 쉽게 결과가 나온다.
# password 있는지 확인
if 'password' in data:
password = bcrypt.checkpw(data['password'].encode('utf-8'), account.password)
else:
return JsonResponse({'message': 'KEY_ERROR'}, status=400)
[01/Feb/2021 07:12:10] "POST /account/login HTTP/1.1" 200 22
잘 연결이 되는것을 확인 할 수 있다!
이번에 쓸 라이브러리는 pyjwt
!
JWT는 JSON Web Token라는 약어로 정보를 안전하게 전송하기 위해 정의된 공개된 표준(RFC 7519)이다. 이 라이브러리는 아래와 같은 특징을 가지고 있다.
JSON
객체를 사용하여 자가수용적이다.stateless
같은 속성이 상쇄된다.
pip install pyjwt
해당 JWT를 다운받아준다. (python이라서 pyjwt)
import jwt # 라이브러리 이름은 pyjwt지만 import는 jwt로 사용!
class LoginView(View):
def post(self, request):
data = json.loads(request.body)
access_token = data.get('token')
if access_token:
payload = jwt.decode(access_token, my_settings.SECRET, algorithms=my_settings.ALGORITHM)
if Accounts.objects.filter(email=payload['email']):
print('-------------------------- token!!')
return JsonResponse({'message': 'SUCCESS', 'token': access_token, 'info': payload}, status=200)
try:
...
access_token = jwt.encode({'email' : account.email}, my_settings.SECRET, algorithm=my_settings.ALGORITHM)
return JsonResponse({'message': 'SUCCESS', 'token': access_token}, status=200)
except KeyError:
return JsonResponse({'message': 'KEY_ERROR'}, status=400)
import
는 jwt
로 해주면 된다.
먼저, try
안에 있는 access_token
이라는 변수를 보면 jwt.encode()가 실행되었다.
해당 코드의 jwt.encode()에는 3가지 인자를 받아서 사용했다.
해당 인자를 바탕으로 생성하게 되면 salt가 추가되어 잘 양념된 JWT값이 나오게 된다!
HTTP/1.1 200 OK
Content-Length: 162
Content-Type: application/json
Date: Tue, 02 Feb 2021 01:20:02 GMT
Referrer-Policy: same-origin
Server: WSGIServer/0.2 CPython/3.8.5
Vary: Origin
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
{
"message": "SUCCESS",
"token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJlbWFpbCI6InRqZHduczAzMDlAbmF2ZXIuY28ua3IifQ.2m-qLIVJ__TT1pEnUjEkOSOvptcbozg6MvKIvRFIZBQ"
}
try
문 밖에 있는 if문들
을 살펴보자
첫번째 if
에서는 token
이라는 키가 있어 값이 있다면 해당 token
이 우리가 발행한게 맞는지 검사하는 decode()
를 실행하게 된다.
그뒤 payload
변수를 만들어 jwt.decode()를 실행하게 된다.
jwt.decode()도 3가지의 인자를 가지게 된다.
encode()
할 때 사용되었던 동일한 SECTER_KEYencode()
할 때 사용되었던 동일한 ALGORITHMSrequest.body
에 발급받은 토큰의 정보를 보내주면 아래와 같이 잘 실행되어 'email'의 정보를 받아올 수 있다.
(id의 종류로는 3개가 있지만 지금의 경우엔 'email'을 사용했다.)
http POST 127.0.0.1:8000/account/login email="abc@naver.com"
password=12345678
token='eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJlbWFpbCI6InRqZHduczAzMDlAbmF2ZXIuY28ua3IifQ.2m-qLIVJ__TT1pEnUjEkOSOvptcbozg6MvKIvRFIZBQ'
{
"info": {
"email": "abc@naver.com"
},
"message": "SUCCESS",
"token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJlbWFpbCI6InRqZHduczAzMDlAbmF2ZXIuY28ua3IifQ.2m-qLIVJ__TT1pEnUjEkOSOvptcbozg6MvKIvRFIZBQ"
}
Bcrypt
종류를 처음 알게 되었다. (비밀키, 공개키만 알고 있었다.)JWT
의 특징들과 쓰게되는 이유JWT
가 가지는 각 부분들에 대한 정보JWT
의 encode()
, decode()
의 사용 방법SCERET_KEY
를 주고, 왜 그것을 git
에 올리면 안되는지ㅋㅋㅋㅋhash
동작 방법을 알지만, 어렵게 느껴진다.. 만드신분들 감사합니다...ㅎㅎJWT
가 다양한 언어에서 쓰이는 것을 보고 또 우리의 편의성을 위해 다른분들이 고생했다는 것을 절실히 깨닫는 오늘의 공부..발전하는 암호화기술, 그것을 부수려 발전하는 해킹기술... 그리고 그뒤를 맹렬히(?) 따라가는 나!!
오 성준님 이번 글 많이 도움됐어요. 감사합니당.