access token
을 클라이언트에게 전송 ➡️ 유저의 로그인 성공 후 다음부턴 access token
을 첨부해서 request 서버에 전송하므로 유저는 매번 로그인하지 않아도 된다. 0b47c69b1033498d5f33f5f7d97bb6a3126134751629f4d0185c115db44c094e
이라는 값이 나온다. 그리고 비슷한 비밀번호를 넣으면 완전히 다른 값이 나오는데 이러한 효과를 avalance라고 하며 이는 해킹을 어렵게 만드는 하나의 요소이다. salting
, key stretching
#가상환경에서 설치 후에
pip install bcrypt
#python shell
>>>import bcrypt
>>>password = "1234"
bcrypt.hashpw(password, bcrypt.gensalt())
라고 치면 TypeError: Unicode-objects must be encoded before hashing.
이라는 오류가 발생한다. 해싱 전에 반드시 인코딩 되어야 한다는 뜻이다. 여기서 인코딩(코드화, 암호화)은 str -> 유니코드로, 디코딩(복호화)은 유니코드 -> str을 의미한다.
>>> encoded_password = password.encode('utf-8') #패스워드 인코딩하기
>>> encoded_password
b'1234'
#타입 확인
>>> type(encoded_password)
<class 'bytes'>
>>> type(password)
<class 'str'>
#다시 디코딩 하면 원래 비밀번호 확인 가능
>>> decoded_password = encoded_password.decode('utf-8')
>>> decoded_password
'1234'
#패스워드 해쉬하기
>>> hashed_password = bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt())
>>> hashed_password
b'$2b$12$Ix7J4Nzf5hToF3tafBAqy.4DkF3xnnDuBmPf2P0M4LwLazvCG.fmO'
# 솔트를 만들때마다 계속 다른 솔트값이 랜덤으로 만들어짐을 확인할 수 있음.
>>> bcrypt.gensalt()
b'$2b$12$MthmJbSBXc3CldcFOprFIu'
>>> bcrypt.gensalt()
b'$2b$12$pxqbHoWwx5JZafjdoSEt6u'
>>> bcrypt.gensalt()
b'$2b$12$KHm7ZMg2rqwWqpm/BvZJ3u'
#솔트값을 만들어 따로 넣어주는 것도 가능함.
salt = bcrypt.gensalt()
>>> salt
b'$2b$12$x4x5sJDkfTRtvCSu.FzSaO'
>>> hashed_password = bcrypt.hashpw(password.encode('utf-8'),salt)
>>> hashed_password
b'$2b$12$x4x5sJDkfTRtvCSu.FzSaOxbZQBHBm7obaSNQF14P4bMPoSu6uK5y'
#위의 솔트값이 hashed_password에 추가되어 있는 것을 확인 가능함.
주의할 점은 데이터베이스에 저장할때 문자열이 아닌 해쉬된 패스워드를 디코딩해서 저장해야함!
>>> bcrypt.checkpw('1234'.encode('utf-8'),hashed_password)
True
>>> bcrypt.checkpw('123'.encode('utf-8'),hashed_password)
False
로그인할때 '1234'라는 패스워드를 받았다고 가정했을때, 인코딩한 '1234'와 데이터베이스에서 str형태로 저장된 비밀번호를 인코딩해 가져온 값이 둘이 동일한지 체크해야한다.
그리고 bcrypt는 단방향 해쉬 알고리즘이라서 솔틍하고, 스트레칭하면 복호화가 불가능에 가깝지만,jwt는 복호화하면 페이로드에 암호정보를 확인할수 있어서 사용자가 로그인하면 백엔드 서버가 토큰을 프론트엔드에 발행하고, 프론트엔드는 api를 요청할때 토큰을 넣어서 보맨면 백엔드는 그것을 확인하고 인가를 제공한다. 토큰을 사용하게 되면 백엔드 서버는 토큰 정보를 해석하는 데코레이터를 만들어 인가가 필요한 엔드포인트들을 사용할 수 있다.
>>> encoded_jwt = jwt.encode({'user_id':5 },'secret' , algorithm="HS256")
>>> encoded_jwt
'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjo1fQ.K4UUqOCE7e7M4yo9LTs2gUaJURg-8DAajx95oj-QIgQ'
중요한 점은 절대 유저의 패스워드와 같은 개인정보를 넣으면 안된다. 유저id는 단순한 숫자로 보기 때문에 가능하다.
>>> jwt.decode(encoded_jwt, 'secret' , algorithms='HS256')
{'user_id': 5}
이렇게 JWT를 디코드 메소드로 복호화하면 유저아이디를 확인할 수 있다.
access token
을 생성한다. access token
에는 유저 정보를 확인할 수 있는 정보가 들어가 있어야 한다.(ex) user id) ➡️ 유저가 request를 보낼때 access token
을 첨부해서 보낸다. access token
을 복호화 한다. access token
이라는 암호화된 유저 정보를 첨부해서 request를 보내게 된다. 그러면 서버에서는 access token
을 복호화해서 해당 유저 정보를 얻게 된다. 이렇게 복호화해서 얻은 유저 아이디를 통해 해당 유저가 누구인지 알 수 있다. acess token
을 생성하는 대표적인 방법은 JWT이다. JWT는 말 그대로 유저 정보를 담을 JSON 데이터를 암호화해서 클라이언트와 서버간에 주고 받는다. access_token
인eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZGVudGl0eSI6MSwiaWF0IjoxNDQ0OTE3NjQwLCJuYmYiOjE0NDQ5MTc2NDAsImV4cCI6MTQ0NDkxNzk0MH0.KPmI6WSjRjlpzecPvs3q_T3cJQvAgJvaQAPtk1abC_E
복호화하면 다음과 같은 정보를 얻을 수 있고, 얻은 유저 아이디를 통해 해당 유저가 누구인지 알 수 있다. {
user_id = 1
}
access_token
을 생성하는 방법은 다양한데, 그중 널리 쓰이는 방법이 JWT이다.