회원 인증 개념
클라이언트가 서버에 요청을 보낼 때는 HTTP라는 프로토콜로 통신하게 되는데, 우리 서버는 HTTP 통신으로 들어오는 수많은 요청에 대해 누가 누군지 알아야 한다.
이때 클라이언트는 서버로 요청을 보낼 때 HTTP 에 자신이 누구인지를 함께 적어서 보내는데, 이렇게 서버에게 내가 유저라는 사실을 확인 받는 과정을 인증이라고 한다.
HTTP 메세지의 어느 부분에 어떻게 적느냐에 따라 인증 방식이 나뉘는데 보통 3가지 방식이 있다.
1. ID와 PW를 그대로 담아 보내기
서버에게 인증 받기 위해 본인의 ID와 PW를 그대로 적어서 보낸다. 상당히 보안에 취약한 방법이며 누군가 중간에 이 요청을 가로챈다면 클라이언트가 적어놓은 회원의 ID와 PW를 그대로 볼 수 있다.
2. Session & Cookie
일단 Session은 서버 쪽에서 저장하는 정보, Cookie는 클라이언트의 자체적인 저장소로 이해해보자.
앞서 살펴 봤던 방식과 다른 점은 로그인을 하고 난 후 매 요청마다 ID와 PW를 보내지 않고, 로그인 후 발급되는 세션 ID를 보냄으로 인증을 대체 한다는 점이다.
세션 쿠키 방식은 처음 로그인을 하면 서버 측에서 해당 로그인 정보로 세션을 생성하고 클라이언트에게 세션의 ID를 응답으로 보낸다. 그럼 클라이언트는 응답으로 받은 세션 ID를 쿠키 저장소에 보관하고 요청을 보낼 때 마다 쿠키에서 세션 ID를 꺼내와 HTTP 헤더에 넣어 보낸다.
서버는 세션 ID를 바탕으로 저장된 세션을 탐색해 요청을 보낸 유저가 맞는지 확인하고 인증하는 방식이다.
하지만 이 세션 ID도 누군가 가로채어 HTTP 헤더에 넣어 요청하게 된다면 서버는 인증을 해 줄 수 밖에 없기 때문에 보안적으로 완벽하지 않다.
3. Token
토큰 방식 또한 Session & Cookie 방식과 비슷하다.
기본적인 토큰 방식은 회원가입시 유저에 매칭되는 토큰을 생성하여 저장한다. 로그인 요청이 들어오면 해당 토큰을 응답으로 보내주고, 클라이언트는 이 토큰을 잘 가지고 있다가 요청을 보낼 때 HTTP 헤더에 토큰을 넣어 보낸다.
서버는 요청으로 들어온 토큰이 유효한지 확인하여 인증하는 방식이다.
세션 & 쿠키 방식과 다른점은 토큰 자체에 사용자에 대한 정보가 있어서 서버는 이 토큰만을 가지고 어떤 유저인지 구분해 낼 수 있다는 것이다.
어 그렇다면 누군가 토큰을 탈취하면 유저에 대한 정보를 알아 낼 수 있는것이 아닐까?
토큰은 기본적으로 암호화 방식을 채택하여 사용한다. 그리고 이 암호화에 필요한 키는 바로 settings.py에 있는 SECRET_KEY이다. 따라서 이 키가 노출되지 않는다면 토큰 자체로는 어떤 정보도 알아낼 수 없다.
JWT (Json Web Token)
JWT는 (.)을 통해 3가지로 구분되어 있다.
Header
- type: "JWT" 토큰 유형
- alg: "HS256" 어떤 해싱 함수를 사용할 것인가
(이 알고리즘은 토큰을 검증할 시 사용되는 signature 부분에서 사용됨) - 해싱 함수: 임의의 길이의 데이터를 고정된 길이의 데이터로 매핑하여 암호화하는 함수
Payload
- iss: 토큰 발급자 (issuer)
- sub: 토큰 제목 (subject)
- aud: 토큰 대상자 (audience)
- exp: 토큰의 만료시간 (expiraton)
- iat: 토큰이 발급된 시간 (issued at)
Signature
- JSON Web Token 의 마지막 부분은 바로 서명(signature) 이다. 이 서명은 헤더의 인코딩값과, 정보의 인코딩값을 합친후 주어진 비밀키로 해쉬를 하여 생성한다.
JWT 토큰은 누구나 내용을 확인할 수 있기 때문에 비밀번호와 같은 개인정보를 담아선 안된다.
Access Token & Refresh Token
클라이언트가 서버에 접근할 때 본인을 인증할 수 있는 방법으로 Access Token을 활용한다.
Access Token과 Refresh Token의 기본 사용 로직은 다음과 같다.
- Access Token은 그 유효기간을 짧게 설정한다.
- Refresh Token의 유효기간을 길게 설정한다.
- 정상적인 클라이언트의 Access Token의 유효 기간이 만료되더라도 가지고 있던 Refresh Token을 통해 새로운 Access Token을 생성해 사용할 수 있게 한다. (즉 Access Token은 짧은 시간 동안에만 사용할 수 있게 하고 Refresh Token을 통해 주기적으로 재발급 받도록 하여 Access Token이 유출 되더라도 피해를 최소화 할 수 있다.)
- 정상적인 사용자가 Access Token 이 만료되었다면 서버측에 Refresh Token을 전송하여 다시 로그인 할 필요 없이 Access Token 을 발급 받을 수 있다.
만약 Refresh Token이 탈취되었을때는 어떡할까
토큰의 유효기간은 임의로 만료시킬 수 없다.
다음에 알아보자..
기본 JWT 세팅
1. 가상환경 myvenv에 djangorestframework 와 djangorestframework-simplejwt를 설치
pip install djangorestframework djangorestframework-simplejwt
2. settings.py 코드 추가
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLAWWES' : (
'rest_framework_simplejwt.authentication.JWTAuthentication',
)
}
3. settings.py에 Access token에 Refresh token 유효기간등 설정. (따로 지정해주지 않으면 default 값으로 설정됨)
SIMPLE_JWT = {
'ACCESS_TOKEN_LIFETIME': timedelta(minutes=20),
'REFRESH_TOKEN_LIFETIME': timedelta(days=7),
'ROTATE_REFRESH_TOKENS': False,
'BLACKLIST_AFTER_ROTATION': False,
'UPDATE_LAST_LOGIN': False,
'ALGORITHM': 'HS256',
'SIGNING_KEY': SECRET_KEY,
'VERIFYING_KEY': None,
'AUDIENCE': None,
'ISSUER': None,
'JWK_URL': None,
'LEEWAY': 0,
'AUTH_HEADER_TYPES': ('Bearer','JWT'),
'AUTH_HEADER_NAME': 'HTTP_AUTHORIZATION',
'USER_ID_FIELD': 'id',
'USER_ID_CLAIM': 'user_id',
'USER_AUTHENTICATION_RULE': 'rest_framework_simplejwt.authentication.default_user_authentication_rule',
'AUTH_TOKEN_CLASSES': ('rest_framework_simplejwt.tokens.AccessToken',),
'TOKEN_TYPE_CLAIM': 'token_type',
'TOKEN_USER_CLASS': 'rest_framework_simplejwt.models.TokenUser',
'JTI_CLAIM': 'jti',
'SLIDING_TOKEN_REFRESH_EXP_CLAIM': 'refresh_exp',
'SLIDING_TOKEN_LIFETIME': timedelta(minutes=5),
'SLIDING_TOKEN_REFRESH_LIFETIME': timedelta(days=1),
}
참고
'Django | DRF' 카테고리의 다른 글
[DRF] Project : WeaTo(3) - 회원가입 로그인 로그아웃 (0) | 2022.08.10 |
---|---|
[DRF] Project : WeaTo(1) - Custom User Model (0) | 2022.08.08 |