JSON Web Token
JWT란 무엇인가?

JWT는 session과 같이 클라이언트가 서버에 data를 요청할 때 서버가 클라이언트가 신뢰할 수 있는 확인 할 떄 쓰인다.
즉 인증( Authentication )을 위해 사용된다.
JWT vs 세션(Session)

세션의 특징
- 세션은 클라이언트를 구분하기 위해 서버에 DB를 두고 Session ID를 관리한다.
- Session ID는 쿠키(Cookie)를 통해 클라이언트에게 전달된다.
- Session ID를 통해 더 이상 로그인 ID와 PW를 보내지 않고 서버에 클라이언트가 누군지 확인한다.
세션은 클라이언트를 강제로 로그아웃 시키거나, ban을 하기 쉽다.
하지만 많은 유저를 감당해야 하는 서비스의 경우 그 만큼 session ID를 서버에 보관해야하고 요청 마다 Session ID를 DB에 검색해야 되니 서버에 부담이 크다
JWT의 특징
- 클라이언트의 로그인ID PW를 받으면 서버는 토큰을 발행해 클라이언트에게 전달한다.
- 클라이언트는 이후 발급된 토큰으로 자신을 증명한다.
토큰의 경우 클라이언트에서 보관하기 때문에 많은 유저가 몰려도 서버에 부담이 없다.
다만, 서버측에서 유저의 행동을 제한할 수 없다. 즉 강제로그아웃 기능을 할 수 가 없다.
JWT 주의사항
현재 많은 서비스들이 자사 서버의 부담을 줄이기 위해 토큰기반의 인증을 사용하고 있다.
하지만 JWT를 그냥 막 썼다간 아주 큰 보안 이슈를 경험하게 될 것이다.
다음은 JWT를 쓸 때 주의해야할 보안 이슈를 소개하려고 한다.
1. None Attack

위의 사이트는 간단하게 jwt의 인코딩을 할 수 있도록 보여주는 사이트다.
위의 Header 부분을 보면 alg 라는 항목이 있을것이다.
이 부분은 암호화를 하는 알고리즘을 나타내는데 암호화에는 대칭방식 비대칭 방식이 존재한다.
위의 경우 'HS256' 방식으로 암호화를 진행중이다.
만약 저 부분을 해커다 다음과 같이 변경해서 접근을 하면 어떨까?
{
"alg":None,
"type":jwt
}
대부분의 jwt 관련 lib은 이 문제를 막는 코드를 기본적으로 사용하지만 본인이 설정하지 않으면 막지 않는 경우도 있다.
혹은, 개발자가 암호화에 관심이 없어 None으로 설정한 경우도 있다.
이럴 경우 바로 토큰을 해커에게 빼앗기게되고 서버는 속수무책으로 data를 해킹당하게 된다.
그러니 반드시 암호화를 꼭 하고 None 공격을 막도록 코드에서 설정을 해주어야 한다.
# middleware.py
from rest_framework_simplejwt.authentication import JWTAuthentication
from rest_framework_simplejwt.exceptions import InvalidToken
class CustomJWTAuthenticationMiddleware:
def __init__(self, get_response):
self.get_response = get_response
self.jwt_authentication = JWTAuthentication()
def __call__(self, request):
auth_header = request.headers.get('Authorization')
if auth_header:
try:
# Decode and verify the token
validated_token = self.jwt_authentication.get_validated_token(auth_header.split()[1])
# Check the algorithm
# 여기서 None attack을 막는다.
if validated_token['alg'] == 'none':
raise InvalidToken('Invalid algorithm')
except InvalidToken:
return HttpResponse('Unauthorized', status=401)
response = self.get_response(request)
return response
2. JWT 토큰 변환
jwt가 암호화 되었다고 방심하면 안된다.
jwt는 아주쉽게 복호화 할 수 있다. 그렇기 떄문에 jwt에 민감한 정보를 넣는 것은 최대한 지양해야 한다.
자칫 잘못하면 개인정보가 아주 쉽게 해커에게 넘어간다.
3. Secret key
위의 Json의 구조를 다시보면 Verify signiture라는 부분이 있을 것이다. 이 부분의 secret key를 개발자가 직접 만들수 있도록 되어있다.
이 부분을 너무 쉽게 만들면 해커가 간단한 해킹방법으로 다 뚫을수 있을것이다.
반드시, 어렵고 복잡하게 만들어야 한다.
4. 이미 해킹당한 jwt를 해커가 사용
위에 언급했듯이 이미 해킹당한 jwt를 해커가 사용한다 해도 서버는 해커와 유저를 구분할 수 없다.
이를 막기위해 토큰은 access token와 refresh token을 이용한다.
from datetime import timedelta
...
SIMPLE_JWT = {
"ACCESS_TOKEN_LIFETIME": timedelta(minutes=5),
"REFRESH_TOKEN_LIFETIME": timedelta(days=1),
"ROTATE_REFRESH_TOKENS": False,
"BLACKLIST_AFTER_ROTATION": False,
"UPDATE_LAST_LOGIN": False,
access 토큰이 우리가 언급했던 자기를 증명하는 토큰이라 한다면
refresh토큰은 1회성의 access 토큰 재발급용 토큰이다.
이 방식을 통해 토큰이 해커에게 넘어 갔어도 access 토큰의 lifetime이 지나기만 하면 더 이상 해커의 접속을 막을 수 있다.
정상적인 유저라면 refresh토큰을 통해 만료시간마다 새로운 access 토큰을 부여받기에 사용에 문제가 없다.
다만 이 refresh 토큰 마저 해킹당했다면 어떻게 할것인가? 하는 의문이 생긴다.
그렇기 때문에 refresh 토큰에 rotate기능을 넣어 refresh 토큰이 한번사용되면 refresh토큰을 바꾸는 방법을 사용한다.
또한 black list 를 만들어 이미 사용된 토큰들을 보관하여 해커가 다시 접속 못하도록 하는 방법도 있다.
다만 이 black list는 서버에 보관되기에 session 방식의 단점이 jwt의 방식에 추가된다.
'CS' 카테고리의 다른 글
| 계산 시간 추정하기 (0) | 2024.06.02 |
|---|