단방향 해쉬란?
In [21]: import hashlib
In [22]: m = hashlib.sha256()
In [23]: m.update(b"test password")
In [24]: m.hexdigest()
Out[24]: '0b47c69b1033498d5f33f5f7d97bb6a3126134751629f4d0185c115db44c094e'
In [25]: m = hashlib.sha256()
In [26]: m.update(b"test password2")
In [27]: m.hexdigest()
Out[27]: 'd34b32af5c7bc7f54153e2fdddf251550e7011e846b465e64207e8ccda4c1aeb'
📌 단방향 해쉬 함수의 취약점들을 보안하기 위해 일반적으로 2가지 보완점들이 사용된다.
실제 비밀번호 이외에 추가적으로 랜덤 데이터를 더해서 해시값을 계산하는 방법.
salting & key stretching 대표적 라이브러리
bcrypt는 처음부터 비밀번호를 단방향 암호화 하기 위해 만들이전 해쉬함수 이다.
단방향 해쉬 함수도 몇가지 취약점이 있다.
Rainbow table attack - 미리 해쉬값들을 계산해 놓은 테이블을 Rainbow table이라고 한다.
해시 함수는 원래 패스워드를 저장하기 위해서 설계된 것이 아니라 짧은 시간에 데이터를 검색하기 위해 설계된 것. 그렇기 때문에 해시 함수는 본래 처리 속도가 최대한 빠르도록 설계되었다. 이러한 속성 때문에 공격자는 매우 빠른 속도로 임의의 문자열의 다이제스트와 해킹할 대상의 다이제스트를 비교할 수 있다(MD5를 사용한 경우 일반적인 장비를 이용하여 1초당 56억 개의 다이제스트를 대입할 수 있다). 이런 방식으로 패스워드를 추측하면 패스워드가 충분히 길거나 복잡하지 않은 경우에는 그리 긴 시간이 걸리지 않는다 (대부분 사용자의 패스워드는 길거나 복잡하지 않을 뿐 아니라, 동일한 패스워드를 사용하는 경우도 많다).
In [40]: import bcrypt
In [41]: bcrypt.hashpw(b"secrete password", bcrypt.gensalt())
Out[41]: b'$2b$12$.XIJKgAepSrI5ghrJUaJa.ogLHJHLyY8ikIC.7gDoUMkaMfzNhGo6'
In [42]: bcrypt.hashpw(b"secrete password", bcrypt.gensalt()).hex()
Out[42]: '243262243132242e6b426f39757a69666e344f563852694a43666b5165445469397448446c4d366635613542396847366d5132446d62744b70357353'
📌 위 특징 때문에 서버는 사용자가 로그인 했을 경우, 로그인 했다는 것을 어떻게 알 수 있을까요?
유저 로그인
POST /auth HTTP/1.1
Host: localhost:5000
Content-Type: application/json
{
"username": "joe",
"password": "pass"
}
access token
HTTP/1.1 200 OK
Content-Type: application/json
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZGVudGl0eSI6MSwiaWF0IjoxNDQ0OTE3NjQwLCJuYmYiOjE0NDQ5MTc2NDAsImV4cCI6MTQ0NDkxNzk0MH0.KPmI6WSjRjlpzecPvs3q_T3cJQvAgJvaQAPtk1abC_E"
}
/* access_token 복호화한 것
{
user_id = 1
} */
해더: 토큰의 타입과 해시알고리즘 정보가 들어간다
내용에는 exp와 같이 만료시간을 나타내는 공개 클레임
클라이언트와 서버간 협의하에 사용하는 비공개 클레임
서명: JWT가 원본 그대로라는 것을 확인할 때 사용하는 부분