티스토리 뷰
JWT 에 대한 간단한 정리
기본 지식
세션과 토큰 그리고 JWT
자동 로그인?
- 자동 로그인은 기본적으로 세션 혹은 토큰에 의해 이루어진다
- 브라우저의 Cookie 혹은 localStorage 에 session, token 등이 저장, 로그인 여부 확인에 사용
- Cookie 의 경우 HTTP Request 에서 Header에 포함되니깐 서버에서 Header 값으로 확인한다
- 쿠키니깐 key, value, 유효기간 등이 존재하며, httpOnly를 하지 않았을` 경우 js 로 접근 가능함
- 따라서, 인증 관련된 쿠키들의 경우 반드시 httpOnly 등을 처리해주어야 함
- localStorage 나 cookie 중 뭐가 더 낫냐에 대해서는 확실히 모르겠다. 일단 난 쿠키 사용함
- httpOnly 이런거로 막기도 쉽고 HTTP Header 에 들어가기 때문
세션
- 세션은 서버의 DB에서 저장한다
- 사용자 로그인에 대해 세션을 발급하고 HTTP Header 등으로 돌아올 때 이를 DB에서 대조
- DB에서 유효할 시 로그인 처리를 해주고, 만료되었거나 유효한 값이 아니면 로그인 다시 하게 함
토큰
- 세션은 서버의 DB에 저장된다는 문제점이 있다
- 서버가 여러개 있는 경우에는 상당히 귀찮다(서버 여러 개 운영 시 세션 관리 구글링ㄱ)
- token 은 DB에 부하를 거는 대신 SECRET_KEY를 사용해서 유효를 판단
- 즉 DB에 세션을 저장하지 않고, 마구 발급하며, 이게 정해진 SECRET_KEY로 풀리는지만 판단
- 추상적인 개념상 토큰은 위와 같고 구체적인 것은 JWT이다. JWT를 알아보자.
JWT : Json Web Token
위에서 말한 "토큰" 의 좀 더 구체적인 개념이라고 생각하면 된다
[header].[payload].[signature] 로 구성됨
Header
header에서는 암호화 알고리즘이 정의됨(json 형태)
암호화 알고리즘은 SHA256 등 Hash 기반→ SECRET_KEY가 있어야 decode 가능!
참고로 RS256 도 있으니 추가 공부하면 좋다
Payload
구성
- json 형태의 key, value 들
역할
- 인증에 사용할 사용자의 정보(이름, id 등)
Signature
구성
- header, payload를 암호화 알고리즘(Header에서 정의된) + SECRET_KEY로 암호화
- 암호화 완료 후 base64 encode
역할
- header, payload에 담긴 값이 변조를 거쳤는지 아닌지 verify 하는 역할
- base64로 encode 되어 있어서 바로 decode 가능하지만 decode 된 내용도 암호화 된 결과임
- header, payload를 변조해도 signature 에서 걸릴 수 있음. (Secret Key 가 털리지 않았다면)
특징
header, payload, signature 모두 base64URL 로 encode 된 상태.
따라서, header, payload는 바로 base64에서 decode해 내용 확인 가능.
→ 바로 값을 확인할 수 있으므로 민감한 정보는 안담아둠
→ 변조의 위험성이 있음(alg: "none")
→ 변조 여부 파악 위해 header,payload(암호화 알고리즘 + SECRET_KEY) 로 암호화⇒ signature.
Q. Token이 탈취당한 경우?
토큰이 탈취당한 경우 세션과 동일하게 자격 증명을 속이고 들어올 수 있다.
따라서, 토큰의 유효기간을 짧게 설정한다.(iat)
대신 이 경우, 로그인을 아주 자주 해줘야 하는 번거로움이 존재한다.
이로 인해, access_token과 refresh_token으로 분리하여 처리한다.
- access_token : 인증 정보 보관 목적. 유효 기간 짧음
- refresh_token : 토큰 재발급 목적. 유효 기간 긺.
Q. access_token 과 refresh_token은 어떻게 작동하는가?
- access_token으로 접근.
- 만료시 access_token과 refresh_token을 동시에 서버에 제출.
- access_token을 통해 사용자 정보를 확인하고 refresh_token을 verify 해서 재발급 여부를 결정.
- 조건을 만족하면 재발급.
문제 해결
WebGoat 으로 가보자
#4. JWT Signing
header의 알고리즘을 none으로 바꾸고 payload의 값을 원하는 대로 변경 signature를 공백으로 남겨두면 공격 가능
#5. JWT Cracking
SECRET_KEY를 취약하게 설정할 경우 hashcat과 같은 도구들로 crack 가능
해시캣에 사용할 워드리스트는 이걸 사용하면 됨
payload의 값을 원하는 대로 변조한 후 hashcat으로 SECRET_KEY를 crack.
SECRET_KEY 파악 후 jwt.io 에서 해당 값 대입해서 JWT 생성 후 request.
해당 문제를 통해 알 수 있는건 유추 가능한 SECRET_KEY를 사용 자제.
#7. Refreshing a token
- access_token과 refresh_token의 목적은 서로 다름.
- access_token은 사용자 정보 확인, 실제 인증에 사용됨
- refresh_token은 access_token 재발급
그래서 access_token은 다음과 같이 재발급함
- 만료된 access_token 에서 사용자 정보를 파악 (user id 등)
- refresh token을 검증해 사용자 정보에 대응하는 access_token을 재발급
이때 refresh_token에 대한 검증이 확실하지 않은 경우 다음과 같은 문제 발생 가능.
- 만료된 다른 사용자의 access_token이 노출됨
- 공격자의 refresh_token이 존재함.
- 새 토큰을 발급받는 엔드포인트 등에 1, 2를 각각 보냄.
- 공격자는 다른 사용자의 자격 증명을 획득가능
#8. Final Challenges
SECRET_KEY를 하나만 사용하는 경우 노출시 매우 위험해짐. 이를 위해서 여러가지를 DB에 저장 후 사용하면서 위험도를 줄일 수 있다.
본 문제의 경우 header의 kid를 통해서 SECRET_KEY에 접근. encdoe-decode에서 그 SECRET_KEY를 사용하고 있다.
이때 kid의 값으로 SQL Injection이 발생할 수 있다.
소스 코드를 확인해본 결과 kid 부분에서 SQL Injection 발생함.
원래 값인 webgoat_key 뒤에 SQL Injection.
원래 webgoat_key에 해당하는 SECRET_KEY를 DB에서 조회하는 방식이므로 이를 변조.
변조 목적으로 기존 결과 UNION으로 원하는 SECRET_KEY 값인 'mykey'를 base64 인코딩
이제 SECRET_KEY는 'mykey'로 접근 가능함
'연습' 카테고리의 다른 글
프로그래머스 등굣길 (0) | 2024.04.17 |
---|---|
토익스피킹 빠르게 고득점 하는 방법 (0) | 2024.03.29 |
docker-compsoe 업그레이드하기 (1) | 2022.09.16 |
[Django] testcase 사용하기 (0) | 2022.08.16 |
vscode remote ssh 막힐때 (0) | 2022.08.08 |
- Total
- Today
- Yesterday
- blind_based
- 그리디
- django testcase
- factory_pattern
- selenium-wire
- seleniumwire
- 코딩테스트
- private repo
- 도커 로그
- 삽질
- Til
- Spread Parameter
- SQL
- 백준
- BOJ
- Python
- 위상정렬
- 파이썬
- Javascript
- 로그 용량
- django test
- vscode
- 힙
- 스택
- jwt
- 프로그래머스
- Remote
- req.user
- 우선순위큐
- docker-compose update
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |