이번주차 프로젝트에서 JWT 인증방식과 해시함수 SHA256을 꼭 사용해서 로그인 기능을 구현하라는 과제를 진행했다.
JWT 인증에 대한 설명글은 많은데, 구체적으로 어떻게 구현해야 하는지에 대해 내가 구현해야 하는 Flask 관련 자료는 잘 찾지 못했다. 나중에 그 이유도 알게되었지만.
우선 JWT에 대해서 공부했다. JWT에 대해서 잘 정리된 글은 많이 있으니 간단하게 정리하면, JSON 형식으로 ".".join([Header,Payload,Signatrue]) Header.Payload.Signature로 구성되어 있는 토큰으로 웹페이지에서 인증과 권한을 부여하고, 확인하는 용도로 사용한다고 한다.
토큰을 서버에서 만들어 클라이언트에 보내주고, 보내준 토큰으로 사용자 확인, 인증, 권한 확인에 사용한다. 그건 알겠는데... 해맨 지점은,
1. 클라이언트에서 토큰을 받아서 어떻게 하는지?
2. 그걸 서버와 어떻게 주고 받는지?
우선 어떻게 구현하는지에 대한 공부 전에 어떤걸 다루는지를 알아야 하기 때문에 조금 더 검색하며 글을 읽어나갔다.
1. 서버에서 발행한 토큰을 저장하는 방법은, ①쿠키(cookie), ②로컬 스토리지(local storage), ③세션 스토리지(session storage), ④메모리 저장 방법을 검색할 수 있었다. (좀 더 찾아보니 indexedDB도 있는데 그것 까진...)
우선 ④메모리에 저장하는 방법은 그래도 되냐는 질문이 대부분이고, 권장하지 않는 경우가 많았다. 우선, 해당 페이지에서 벗어나는 경우 토큰을 잃어버리고, 글로벌 변수로 저장하는 경우 다른 JS코드 인젝션을 당했을 때 노출될 수 있는 문제가 있다는 점 등이 검색되는 이유고 그 외에는 사실 명확한 답을 찾진 못했다. 아마 질문이 잘못되었기 때문이 아닐까? 하는 생각이 들었고, 보안상의 특별한 이유가 있다면 쓸 수 도 있지 않겠냐는 답은 있긴 했다. 만약 꼭 그렇게 하고싶다면, 캡슐화를 사용하라는 의견.
쿠키나 로컬 스토리지, 세션 스토리지에 저장하는 방법은 상황에 따라 선택하는데 그걸 선택하는 기준은 CSRF, XSS 공격에 대한 보안, 클라이언트-서버 사이 통신에 대한 부담 등이 있다. 개별적으로 CSRF나 XSS 공격에 대해서 취약점이 있는 것으로 나오고, 개별적으로 방어하는 방법이 다 있었다. 🎈 검색 키워드는 쿠키: SameSite 옵션, CSRF 토큰 사용, HTTP Referer 검증, httponly 옵션 등...
저장하는 방법에 따라 장단점은 꽤 많은 글이 검색되고 읽었을 때 잘 정리되어 있었으니, 따로 정리하진 않고 잘 정리된 글만 링크(쿠키, 세션, 로컬/세션스토리지). 링크(로컬/세션 스토리지). 링크(JWT 저장 위치별 장단점).
2. 서버와 어떻게 주고 받는지는 HTTP request header에 Authorization 를 써서 보내는 것이 일반적이라고 한다. 물론, 꼭 헤더에 보내야 하는 것은 아니라고 하나, GET 요청 시 body 없이 요청하는 경우가 일반적이기도 하고(찾아보니 대부분 GET요청 시 body를 달아도 통신이 잘 이뤄진다. 어떤 라이브러리나 프레임워크에서는 안 되도록 한 경우도 있다고...).
브라우저가 쿠키를 다루는 방법을 검색해보니 사용자가 따로 요청하지 않아도 브라우저가 Request할 때, 헤더에 넣어서 서버에 전송한다고 한다.
그럼 쿠키에 저장하는 경우 JWT를 Authorization bearer로 담아 보낼 필요가 없다는 건데... 지금까지 검색한 결과로 간단히 생각했을 때, cookie에 SameSite옵션을 사용하는데, 프론트엔드 서버와 백엔드 서버를 다른 도메인이나 주소로 운영하면 쿠키가 자동 전송되지 않을테니, 프론트엔드에서 쿠키에 있는 토큰을 찾아 request에 담아서 보내야 하는 상황 정도? 그 외에도 다양한 상황이 있을 것 같다. 웹브라우저가 쿠키를 자동으로 request에 담아준다고 하는데, 그런 기능을 해주지 않는 브라우저나 앱의 경우라던가...?
이번엔 Flask로 서버를 만들었고, JWT를 클라이언트로 보내서 쿠키에 저장하게 했고, 단순히 request.cookies.get()으로 사용자의 쿠키를 얻을 수 있었다. Flask에서는 request 헤더에 들어있는 JWT를 request.cookies.get()으로 얻을 수 있었다.
정리하면,
- JWT를 서버에서 받아 클라이언트 쿠키에 저장하거나 웹 스토리지에 저장한다.
- 서버는 Request에 저장되어 있는 토큰을 읽고, 사용자를 확인한다.
아직 기초가 없다보니, HTTP 통신, 쿠키, 웹 스토리지... 등 모르는 용어가 많다. 찾아보고 공부하면서 하나씩 알아가다 보면 언젠가 다 연결 될 것 같다. 또, 적절한 보안 방법까지 찾아가며 공부해봐야 하겠다. JWT를 구태여 쓰는 이유는 뭘까? 다른 방법은 없을까? 부분도 찾아봐야겠다.
(부록) 하도 검색을 많이 했더니, 유투브에 관련 영상으로 노마드 코더 영상이 떠서 봤는데, 개략을 잘 잡을 수 있는 영상이라 도움이 많이 되었다. 링크.
'Protocol, Standard, ...' 카테고리의 다른 글
REST... (0) | 2023.05.15 |
---|