Bcrypt & JWT

jinatra·2021년 8월 24일
0

WEB

목록 보기
2/3
post-thumbnail

Bcrypt & JWT

인증(Authentication), 인가(Authorization)


Bcrypt

Bcrypt란?

인증(Authentication) - 유저의 identification을 확인하는 절차

인증에 사용되는 함수 중 하나라고 생각하면 된다.
이를 알기 위해선 먼저 해쉬 함수의 개념에 대해 알아야 한다.


Hash Function (해쉬 함수)

임의의 길이의 데이터를 고정된 길이의 데이터로 매핑하는 함수

특정 문자열을 변환시켜주는 함수라고 생각하면 된다.
예를 들어, 비밀번호로 '1234'를 입력하면 'dsf234kgfdfgadks324'와 같이 출력이 된다.


One-Way Hash Function (단방향성 해쉬 함수)

원본 메시지를 변환하여 암호화된 메시지인 다이제스트(digest) 생성
원본 메시지 → 암호화 메시지로 출력이 되지만,
반대인 암호화 메시지 → 원본 메시지 역출력은 불가하다.


Salting & Key Stretching

단방향 해쉬함수의 경우, 결과값을 모아놓은 Rainbow Table과 같은 취약점이 있어 여러 방법들이 추가로 사용된다.

그 중 Bcrypt에 사용되는 두가지 방법이 Salting과 Key Stretching이다.

Salting

암호화하고자 하는 데이터를 해싱할 때, 데이터 자체만 넣고 해싱하게 되면 보안에 취약하므로 부가적인 데이터(salt, 소금)도 같이 넣고 해싱을 돌리는 개념이다.

말그대로 중요한 데이터에 양념을 친다는 느낌이다.

Key Stretching

키를 늘린다. 즉, 여러번 반복한다는 의미이다.
단방향 해쉬값을 계산 한 후 그 해쉬값을 또 해쉬 하고, 또 이를 반복하는 것이다.
Key Stretching을 한다면 같은 시간에 컴퓨터가 비교할 수 있는 횟수가 기하급수적으로 줄어들어 보안에 효과적이다.


Bcrypt

Salting과 Key Stretching을 구현한 함수로써, 처음부터 비밀번호를 단방향 해쉬화하기 위해서 만들어졌다.


Bcrypt를 통한 암호화 과정

bcrypt 라이브러리의 내장함수(bcrypt.hashpw)를 이용해 암호화하고자 하는 정보를 암호화시킬 수 있다.

아래 예시를 보자.

# pip install bcrypt (in terminal)

import bcrypt

password = 'dontkillmyvibe'
hashed_password = bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt())

print(hashed_password)

# >>> b'$2b$12$itUvCIfHC0YAjNfjpBjFlOtAv1fPDiiALuuQqlI.CkwUVg863JAF6'
  • import bcrypt : 먼저 bcrypt 라이브러리를 설치한 후 파이썬에 들어가 import
  • hashed_password = bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt()) : 해싱을 위해 passwordbytes 타입으로 인코드해주고, salt를 추가

여기서 굉장히 중요한 개념이 나오는데,

bcrypt의 경우엔 str이 아닌 bytes 데이터를 암호화 하기에 항상 bytes 타입으로 지정이 되었는지 확인해주어야 한다.


Bcrypt를 통한 암호화 데이터 확인 과정

bcrypt 라이브러리는 또한 내장함수(bcrypt.checkpw())를 이용해 암호화된 데이터와 입력된 데이터를 확인해주는 역할도 한다.

# 위에 이어서, 

password_for_check ='dontkillmyvibe'

bcrypt.checkpw(password_for_check.encode('utf-8', hashed_password)

# >>> True

일치하는지 확인하고자 하는 데이터와 암호화된 데이터를 위와같이 비교할 수 있다.


JWT

JWT란?

JSON Web Tokens - 유저 정보를 담은 JSON 데이터를 암호화 해서 클라이언트와 서버간에 주고 받는 것

토큰이 어떤 개념인지는 HTTP 통신 글에서 대강 알고 있다.
암호화된 유저 정보로써, 인증된 유저에게 할당하는 인증서와 같은 개념이다.

JWT는 이러한 토큰을 생성하는 방법 중 하나이다.


JWT를 통한 Token 생성

jwt에 내장된 함수(jwt.encode())를 이용하여 토큰을 생성할 수 있다.

아래 예시를 보자.

# pip install bcrypt

import jwt

SECRET_KEY = 'SECRET_KEY in settings.py'

access_token = jwt.encode({'id' : 7}, SECRET_KEY, algorithm = 'HS256')

print(access_token)

# >>> eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpZCI6N30.jW8QJBjNyFrvcdxUFNYlpYBR8wVgS-I67YAgfUQYUoY
  • SECRET_KEY = 'SECRET_KEY in settings.py' : 인증에 사용될 랜덤 조합키인데, 우리가 settings.py에서 뽑아놓은 SECRET_KEY가 들어간다.

  • access_token = jwt.encode({'id' : 7}, SECRET_KEY, algorithm = 'HS256') : jwt 내장함수를 사용하여 토큰을 사용하고, 해당 토큰을 출력하면 str형태로 출력이 된다.


위 예시에서는 id를 지정해줬지만, 실제로는 아래와 같이 db에서 불러온다고 생각하면 된다.

token = jwt.encode({'id':User.objects.get(email=data['email']).id}, SECRET_KEY, algorithm='HS256')

JWT를 통해 생성된 Token 확인

로그인이 성공하면 토큰이 발급되므로, 우리는 발급된 토큰을 프론트 엔드 엔지니어에게 전해주면 된다.

토큰이 맞는지(진짜 id가 7인지) 확인해보자.

# 위에 이어서,

header = jwt.decode(access_token, SECRET_KEY, algorithms = 'HS256')

print(header)

# >>> {id:7}

7번 id가 맞았다!!

우리가 발급된 토큰은 header에 포함되어 전해진다고 한다.





Take Away

인증, 인가에 대한 대강의 개념

대강 어떤 느낌인지는 알겠다.
진짜 느낌만 알겠는게 문제지만..

실제로는 다양한 암호화 방식이 쓰일텐데, 우리가 배우고 쓰는 개념이 현업에서도 많이 쓰이는지 궁금하다.


bcrypt, ?

단방향 해쉬함수와 단방향 해쉬함수를 쓰는 라이브러리, 함수에 대해서만 알아봤는데 실제로는 더 다양할 듯 하다.
단방향 해쉬함수를 쓰는 다른 라이브러리도 존재할 지 알아보고 싶다.

++ 추가

PBKDF2

bcrypt 말고도 PBKDF2라는 라이브러리가 있다고 한다.
salting 후 key stretching 을 임의로 선택할수있는 function이며, 아주 가볍고 구현하기 쉬운 장점이 있다고 한다.
미국표준기술(NIST) 에서 승인된 알고리즘이고 미국 정부 시스템에서도 사용하는 알고리즘 이라고 하는데, 이 라이브러리와 bcrypt 사이에 어떤 장단이 존재하는지 알아봐야할 듯 하다.





참고
https://beoksuya.tistory.com/m/153
https://k0102575.github.io/articles/2020-03/hash

profile
으악

0개의 댓글