jwt 토큰방식 인증

김범수·2022년 1월 19일
0

node를 이용해서 jwt인증을 구현해보고있다.
frontend는 nextjs, backend는 nestjs를 사용하려한다.
그동안 인증시스템 구현을 위해 몇번 시도했었는데, 개념을 잘 인지하지 못해서 구현에 실패했던것같다. 그래서 jwt 인증방식의 개념을 먼저 정리하려고 한다.

JWT의 구조

JWT는 Header, Payload, Signature의 3 부분으로 이루어지며, JSON 형태인 각 부분은 Base64로 인코딩 되어 표현된다. 또한 각각의 부분을 이어 주기 위해 . 구분자를 사용하여 구분한다. 추가로 Base64는 암호화된 문자열이 아니고, 같은 문자열에 대해 항상 같은 인코딩 문자열을 반환한다.

이부분이 이해가 안됐었는데, 그럼 서버에서 사용하는 인증키를 정보에 다 담는가? 분명 위험한 방식일거라 생각되는데.. 하는 의문점이 있었다.

1) 헤더 (Header)

Header 는 두가지의 정보를 지니고 있습니다.
typ: 토큰의 타입을 지정합니다. 바로 JWT를 말하는 것입니다.
alg: Signature 해싱 알고리즘을 지정합니다. 해싱 알고리즘으로는 보통 HMAC-SHA256 혹은 RSA 가 사용되며, 이 알고리즘은 토큰을 검증 할 때 사용되는 signature 부분에서 사용됩니다.

{ 
 "typ": "JWT",
 "alg": "HS256"
}

2) 정보 (Payload)

Payload 부분에는 토큰에 담을 정보가 들어있습니다. 여기에 담는 정보의 한 ‘조각’ 을 클레임(Claim) 이라고 부르고, 이는 Json(Key/Value) 형태의 한 쌍으로 이뤄져있습니다. 토큰에는 여러개의 클레임들을 넣을 수 있습니다.

클레임 의 종류는 다음과 같이 크게 세 분류로 나뉘어져있습니다:

등록된 (registered) 클레임
공개 (public) 클레임
비공개 (private) 클레임

헤더에는 우선 토큰타입이나 해싱 알고리즘의 방식등의 정보가 들어간다.

등록된 클레임은 이미 정해진 클레임들, 공개 클레임은 충돌이 방지된 이름으로 클레임 이름을 URI형식으로 짓는다. 마지막 비공개 클레임은 클라이언트 - 서버 합의하에 지어진 클레임 이름들이다.

3) 서명 (Signature)

서명(Signature)은 토큰을 인코딩하거나 유효성 검증을 할 때 사용하는 고유한 암호화 코드입니다. 서명은 위에서 만든 헤더(Header)와 페이로드(Payload)의 값을 각각 BASE64로 인코딩하고, 인코딩한 값을 비밀 키를 이용해 헤더(Header)에서 정의한 알고리즘으로 해싱을 하고, 이 값을 다시 BASE64로 인코딩하여 생성합니다.

이 서명부분이 전혀 이해가 되지 않았었다.
그래서 다른 자료를 참고해서 더 알아봤다.

우선 찾아본 내용에 따르면,

이런식으로 header, payload, 그리고 secret key를 이용해서 서명을 만들고 클라이언트에서 jwt를 보냈을때 인증을 하는 방식이다. 그런데 헷갈렸던 이유가 다른 자료에 보면 공개 키와 비밀 키를 이용해서 인증을 하는 방식이있다.

https://velog.io/@junghyeonsu/%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%90%EC%84%9C-%EB%A1%9C%EA%B7%B8%EC%9D%B8%EC%9D%84-%EC%B2%98%EB%A6%AC%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95
위의 벨로그 개시물에 들어가보면

공개 키(public key)와 비밀 키(secret key)
JWT에서는 기본적으로 공개 키 암호 방식(PKC, Public Key Cryptograpyh)를 사용하는데,
비대칭 암호 방식을 이용해 공개 키와 비밀 키를 생성하고 이 키들을 상황에 따라 나누어 가지고 통신한다.

서명은 비밀 키가 있는 곳에서만 할 수 있고 공개 키를 가진 어느 곳에서나 이 데이터의 서명을 검증할 수 있다.

공개 키를 가진 누구나 데이터를 암호화해서 데이터를 보낼 수 있지만,
비밀 키를 가진 곳에서만 데이터를 복호화해서 내용을 확인할 수 있다.

요기서 짚고 넘어가야 하는 것은 비대칭 암호 방식이기 때문에
❌ 비밀 키로 암호화한 데이터는 다시 비밀 키로 풀 수 없고,
❌ 공개 키로 암호화 한 데이터는 다시 공개 키로 풀 수 없다.

🟢 서명: 비밀 키를 가진 극소수(주로 한명)만 데이터에 서명할 수 있다. 공개 키를 가진 아무나 데이터의 서명을 검증할 수 있다.
🟢 암호화: 공개 키를 가진 아무나 데이터를 암호화할 수 있다. 비밀 키를 가진 극소수만 데이터를 복호화해 확인할 수 있다.

이런식으로 나와있는데, 이부분이 이해가 안돼서 한참을 찾아봤다. 그런데 내가 생각했던 jwt인증방식 말고도(생각했던 방법은 HS256을 이용한 인코딩 방식이다.) RS256을 이용한 방식이 있었다. https://jwt.io에서 답을 찾을 수 있었는데


이런식으로 jwt내부에 공개키와 개인키를 함께 넣어주는 방식이다.

그리고 rsa256에 관한 부분도 찾아봤는데, jwt rsa256 인증방식 해당 글을 참조하자면, 서명을 private key로 하고 public key로 verify를 한다고한다. 그렇다면 서버에서 처음 키를 서명할때는 private key로 한 뒤 데이터 요청이 있을때 수신받은 jwt를 public key로 verify 한다는것 같은데, 이부분은 아직 정확하지않아 추후에 더 추가하겠다.

우선 개념정리는 이정도로 했고, 현재 구현중이긴 한데 다 구현되면 jwt 인증방식 구현을 올려볼 예정이다. type script 타입 명시나 백엔드 개발 부분도 이제 시간이 좀 생겨서 쭉 업로드 할 예정이다.

----추가----

access_token
refresh_token

access_token 10분
refresh_token 2주

access_token return data

refresh token 달라

refresh token받음

cpu 연산만으로 정보 접근 가능

세션은 요청을날릴때마다 db에접근
whitelist는 10분에 한번씩
blacklist 만료기간이 지나진않았지만 사용 금지된 토큰은 넣어놓는다 (한 계정에서 여러 토큰 사용가능)

세션의 문제점 두가지
파일입출력이 계속 일어난다.
추가정보(권한 등)까지 체크할때 추가 쿼리가 많이 발생한다.

세션스토리지가 많아져버리면 동기화가안돼서 db를 사용하거나 redis를 씀

10년짜리 유효기간 whitelist랑 대조

#참고 자료
https://velog.io/@dnjscksdn98/JWT-JSON-Web-Token-%EC%86%8C%EA%B0%9C-%EB%B0%8F-%EA%B5%AC%EC%A1%B0
https://velog.io/@junghyeonsu/%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%90%EC%84%9C-%EB%A1%9C%EA%B7%B8%EC%9D%B8%EC%9D%84-%EC%B2%98%EB%A6%AC%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95

profile
즐기는 개발자

0개의 댓글