[westagram] bcrypt & JWT

do yeon kim·2022년 7월 14일
0

bcrypt & JWT

패스워드 암호화?

회원가입시 사용자로부터 아이디와 비밀번호를 받게 된다. 그리고 DB에 저장하게 된다.

이때 DB에 사용자로부터 입력받은 패스워드 그대로 저장하게 될시 개인정보에 대한 유출이 발생할 가능성이 있다. 그러므로 패스워드를 저장하기 전에 암호화해서 저장을 하게 된다. 이때 일반적으로 단방향 해쉬 함수가 쓰인다. 단방향 해쉬함수란 원본 메시지를 암호화하면 암호화된 메시지인 다이제스트를 생성한다.
암호화된 메시지로는 원본 메시지를 알수 없는데, 이런 특성을 단방향성이라고 한다.

하지만 단방향성 암호화도 문제점이 있다.

여러 데이터가 축적이 되면 레이보우 테이블(미리 해쉬값들을 계산해 놓은 테이블)과 같이 다이제스트를 모아둔 데이터가 생기게 되고, 이를 활용해서 암호화된 메시지로 원본 메시지를 알 수 있다.

단방향성 암호화의 취약점을 보완하기 위한 방법으로 두가지 해결방법이 있다.

  • salting
    실제 데이터 이외의 랜덤한 데이터를 추가해서 해쉬값을 구하는 것이다.
  • key stretching
    단방향 해쉬값을 구한 뒤, 여러번 반복해서 늘리는 것을 의미한다.

salting 과 key stretching을 구현함 함수중 일반적으로 사용하는 것이 bcrypt이다.



bcrypt
암호화하기

pip install bcrypt
bcrypt는 라이브러리로 설치를 해주어야 한다.

import bcrypt

password = '1234'
hashed_password = bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt())
print(hashed_password)
b'$2b$12$YFs9rh.1LgJwZuf9ibyjpuLvBoCaGX0MzedFWF2Jo0zU3lMZurZ4a'

bcrypt는 string데이터가 아닌 byte데이터를 암호화한다.
따라서 암호화시 password를 먼저 byte데이터로 변경시켜 주어야 한다.

  • encode()
    string를 바이트로 변경시킨다.
  • decode()
    바이트를 string로 변경시킨다.

bcypt.hashpw(바이트된 패스워드, salting을 위한 함수)
패스워드를 암호화 한다.

bycpy.gensalt()
레이보우 테이블등의 취약점을 보완하기 위해서 랜덤한 함수를 더해주는 과정이다.

decode('utf-8)
데이터베이스에 저장할 때는 다시 decode해서 string타입으로 저장한다.

hashed_pwd = bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt()).decode('utf-8')


비밀번호 확인하기

bcrypt로 이루어진 암호는 단방향암호라고 했다. 다시 본래의 비밀번호로 변경이 불가능 한데 어떻게 비밀번호를 확인 할 수 있는 것일까?

new_password = '1234'
bcrypt.checkpw(new_password.encode('utf-8'),hashed_password.encode('utf-8'))
True

bcrypt.checkpw("사용자로 부터 입력받은 패스워드", "해쉬화된 암호")를 이용해서 확인 할 수 있다.

주의할 점은 두 인자 모두 바이트 타입이어야 한다는 것이다.



인증 & 인가?

인증은 특정 서비스에 대해 서비스를 이용가능한 유저의 신원을 확인하는 것이다. 우리는 로그인을 이용해서 유저에 대한 인증을 확인 할 수 있다.

그렇다면 인가란 무엇일까?
인가는 인증이 선행되어지고 난 뒤의 행동이다.
로그인을 해서 특정 서비스의 유저라는 것이 확인 되었다.
특정 서비스가 게시물에 해당한다면, 유저는 자신의 게시물을 쓰고, 수정하고, 삭제 할 수 있는 권한이 있다.
하지만 다른 사람의 게시물에 대한 수정과 편집은 불가능하다.

여기서 권한이 인가에 해당한다.
즉 인가란, 인증된 사용자에 대한 자원 접근 권한 확인이다.



로그인 후 인증 & 인가

HTTP프로토콜의 특성 중 stateless라는 특성이 있다. stateless는 HTTP통신의 선후 작업에 연관성이 없다는 것을 의미한다. 그렇기 때문에 현재 요청으로 로그인을 완료했다고 해도, 다음의 요청에는 또 로그인을 요청하게 된다. 서버 측에서 유저가 누군지 모르는 것이다. 그렇다면 웹페이지를 이동할 때 마다 로그인을 하게 되고, 이는 굉장히 불편하다.

이때 사용하는 것이 쿠키, 세션, 토큰, JWT와 같은 인증 & 인가 방법이다.
우리 프로젝트에서는 JWT를 이용한다.



JWT

로그인을 성공하게 되면 서버측에서 JWT라는 토큰을 먼저 보내주고, 유저 측에서는 이후 페이지 이용시 request에 JWT를 함께 보낸다.

JWT를 이용해서 유저에 대한 인증을 하기 때문에 계속해서 로그인을 하지 않아도 된다.

import jwt #패키지명은 pyjwt이지만 임포트할때의 이름은 jwt입니다.

SECRET = 'secret' #'랜덤한 조합의 비밀번호' 예제이므로 단순하게 'secret'이라고 하겠습니다.

access_token = jwt.encode({'id' : 1}, SECRET, algorithm = 'HS256')
print(access_token)
'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpZCI6MX0.-xXA0iKB4mVNvWLYFtt2xNiYkFpObF54J9lj2RwduAI'

header = jwt.decode(access_token, SECRET, algorithm = 'HS256')
print(header)
{'id': 1}

0개의 댓글