웹 개발을 공부하면서 로그인/회원가입 페이지는 한번쯤 만들어 보았을 것이다. 필자는 뭐가 어렵겠나 싶어서 크게 비중을 두고 만들어보진 않았었다. 그러다, 이번에 Python Flask와 Javascript React로 웹 페이지를 만들면서 로그인/회원가입 페이지를 한땀한땀 만들어보았는데 생각보다 많은 것들을 고려하면서 만들어야해서 힘들었다.
사용자가 로그인을 하고나서 상태를 유지하려면 세션에 사용자 정보를 저장하고 Request가 들어올 때마다 DB에서 사용자를 조회하여 세션에 저장된 데이터와 비교를 해야하므로 리소스의 낭비가 심했다. 그래서 다른 방법을 찾아보던 중 토큰을 이용한 인증방식인 JWT(Json Web Token)를 알게되었다.
그래서 포스트에서는 JWT에 대해서 알아보도록 하겠다.
1. JWT(JSON Web Token)란?
1-1. JWT는 웹표준(RFC7519)로 Server와 Client 사이에서 정보를 빠르고 안정적으로 교류할 수 있게 해줌.
1-2. Header, Payload, Signature로 구성되어 있으며, 이를 Secret Key와 결합하여 Base64로 인코딩함, 주로 로그인이나 보안 데이터 교류 등 사용자를 인증이 필요할 때 사용됨.
1-3. Header의 Claim
- alg: 해싱 알고리즘, HMACSHA256과 RSA가 주로 사용됨.
- typ: 토큰의 타입, JWT
1-4. Payload의 Claim
- sub: 토큰명
- iss: 발급자
- aud: 대상자
- iat: 토큰 발급시간
- jti: 토큰 만료시간
- nbf: 토큰 제한시간, 이 시간 이후에 토큰을 사용할 수 있음.
- 그 외에 이곳에 임의의 데이터를 적재할 수 있으나, 너무 많거나 큰 데이터는 적재하는 것을 권장하지않음.
1-5. Signature
- 인코딩된 Header와 Payload를 결합하고, SecretKey로 해싱하여 토큰을 생성.
1-6. JWT 사이트.
- 이 사이트에서 JWT에 대한 자세한 정보들을 확인할 수 있으며, JWT 디버깅도 지원함.
2. JWT을 통한 인증 방식.
2-1. Client에서 Server에 사용자 인증을 요청함.
2-2. Server에서 사용자를 인증하고 사용자 정보가 담긴 Token을 발행함.
2-3. Client는 Storage에 Token을 저장함.
2-4. Client는 Server에 데이터를 요청할 때, Token을 Request Header( Authorization )에 적재하여 요청함.
2-5. Server는 Client에서 받은 Token이 유효한지 검증하고 이벤트를 처리함.
3. JWT를 통한 인증 방식의 특징.
3-1. Stateless Server.
- 사용자가 인증을 받았을 때 발급되는 토큰에 사용자 정보를 담고 이를 통해 인증하는 방식으로, 사용자 정보를 Server내에 유지할 필요가 없음.
- Stateful Server는 사용자의 정보를 계속 유지해야 하므로 확장성이 떨어지는 반면, Stateless Server는 Client로부터 독립적이기 때문에 확장성이 뛰어남.
3-2. CSRF(Cross-Site Request Forgery, 사이트 간 요청 위조) 방지.
- CSRF는 사용자가 자신의 의지와는 무관하게 공격자가 의도한 행위를 트랩(목적지가 변조된 이미지, 버튼 등)을 통해 특정 웹사이트에 요청하게 하는 공격.
- CSRF는 사용자가 다른 웹 사이트에 로그인 한 상태이거나 로그인 정보가 담긴 쿠키를 가지고 있어야 함.
- Token을 이용하는 웹 사이트인 경우 트랩을 통해 원치않는 요청을 해도 Token이 없기 때문에 안전함.
3-3. 모바일 어플리케이션에서 사용하게 안성맞춤.
- 세션/쿠키/ 인증 방식을 사용한다면 쿠키 매니저를 관리해야 하지만, 토큰을 이용하면 간단하게 해결할 수 있음.
3-4. XSS(Cross-site Scripting)에 취약함.
- Server로 부터 받은 토큰은 주로 localStorage에 저장해두는데, 이는 XSS 공격을 받으면 쉽게 탈취당할 수 있음.
3-5. Token을 탈취당하면 만료시간이 될 때까지 Server에 자유롭게 접근할 수 있음.
- Token은 Server에서 한번 발급하고나면 만료시간이 될 때까지 제어를 할 수 없기 때문에 탈취당하지 않게 주의해야함.
- 만료시간을 짧게하여 탈취를 당하더라도 피해를 줄일 수 있지만, 사용자가 자주 인증해야하는 번거로움이 발생함.
- 그래서 만료시간이 짧은 access_token과 만료시간이 긴 refresh_token을 함께 발급하여 access_token이 만료되면 refresh_token을 통해 access_token을 새로 발급하도록하면 어느정도 해소할 수 있음.
4. JWT을 저장하는 방식.
4-1. localStorage, sessionStorage
- 가장 기본적으로 사용되는 저장 방식.
- XSS 공격으로 쉽게 탈취 당할 수 있음.
4-2. Cookie.
- Cookie에 저장하는 방식은 Server에서Token을 발급할 때 Cookie에 저장하고 HttpOnly 옵션을 설정하여 발급.
- Server와 통신을 할 때에만 Cookie가 전달되므로 Javascript로 접근하지 못하며 XSS를 방지할 수 있지만, CSRF 공격에 취약해지는 단점이 있음.
- Client에서는 Token을 다룰 필요가 없으므로 개발하기 편해짐.
- CORS로 인해 한정된 도메인에서만 사용할 수 있다는 단점이 있음.
5. 마치며.
- 이상으로 JWT에 대하여 알아보았다. localStorage에도 저장해보고 Cookie도 사용해보았는데, Cookie에 저장하는 방식이 가장 편했다. 다만 Token의 만료시간과 Cookie의 만료시간을 함께 고려해야되는 불편함이 있었다. 그래도 세션/쿠키 인증 방식보다는 Server를 구현하는게 훨씬 간편해졌다.
'ETC > Tech.' 카테고리의 다른 글
[Tech.] 작업표시줄에 있는 프로그램 단축키로 실행하기 (0) | 2020.01.15 |
---|---|
[Tech.] Message Broker란? (2) | 2020.01.08 |
[macOS] Catalina에서 Android USB테더링 하기 - HoRNDIS (11) | 2019.12.18 |
[BatchScript] 실행 파일의 인자값 파싱 (0) | 2019.11.28 |
[BatchScript] CLASSPATH 만들기 (0) | 2019.11.28 |
댓글