인증과 권한 개요

인증(Authentication)이란 사이트를 사용할 수 있도록 허가해주는 것이다. 권한이란  인증된 사용자가 어떤 역할을 부여할지를 결정하는 것이다. 예를 들어, 만일 쇼핑몰이라면 쇼핑몰 전체를 관리하는 역할이 있을 수 있고 판매자 역할 혹은 구매자 역할의 권한이 존재할 수 있겠다.

세션과 쿠키 방식 – RFC6265

SSR(Server Side Rendering) 방식에서는 세션과 쿠키라는 인증 방식을 사용하였다.  관련된 프로토콜은 RFC6265 state Management  프로토콜이다.  따라서 쿠키는 클라이언트에 저장되고 세션은 서버에 저장된다는 단순한 암기 방식으로는 세션과 쿠키의 모든것을 설명할 수 없다. 반드시 RFC6265 상태관리 프로토콜에 대한 이해가 선행되어야 한다.

한 사이트를 예를 들면서 RFC6265에 대해서 설명해보겠다.

최초 접속

특정 사이트에 최초에 접속시 서버에서는 http 쿠키에 세션 정보가 있는 지를 체크한다. 세션 정보가 있다면 이전에 접속한 사용자로 판단하고 해당 세션을 서버에서 조회하여 세션에 저장된 상태 정보를 꺼내서 활용한다. 만일 세션 정보가 없다면 최초로 접속한 사용자로 판단하고 서버에서 세션을 생성한 다음에 response 헤더에 Set-Cookie를 보낸다. 이것은 RFC6265에 정의된 프로토콜이다.

그 이후 접속

Set-Cookie 가 오면 브라우저는 Set-Cookie에 있는 정보를 쿠키에 저장하게 된다. 그리고, 브라우저는 쿠키에 저장된 모든 값들을 http request 헤더에 Cookie에 넣어서 보내게 된다.

따라서 만일 쿠키 정보가 많으면 많을수록 http 헤더의 용량은 커지게 된다. 이 문제점을 해결하기 위해서 html5에서는 쿠키 대신 storage라는 개념이 등장하였다.

JWT – RFC7519

Json Web Token 방식은 claim 기반 토큰이다. claim 기반 토큰이랑 토큰을 파싱해서 내용을 볼 수 있다는 의미이다. 세션 방식은 서버에 저장되어있는 값이고 세션에 저장된 값은 서버만이 알고 있다. 만일 SPA 기반 클라이언트 사이드 렌더링을 구현하면서 세션방식을 사용할 수 있을까?  사용할 수 있다. 하지만 비효율적이다. 서버에서 사용되는 세션을 Set-Cookie로 브라우저에서는 Cookie로 갖고 있게 된다고 앞서 설명하였다. 그래서 클라이언트는 세션값을 알고 있다. 하지만 해당 세션에 무슨값이 담겨 있는지는 알 수가 없고 서버에 조회를 해야만 알수 있다. 그러므로 세션에 저장된 값을 매번 조회해야 하므로 비효율적이라는 것이다.

JWT 토큰 방식을 사용하면 사용자가 로그인을 성공하면 서버에서는 브라우저에서 사용할 정보를 JWT 토큰에 담아서 보낸다. 그러면 브라우저는 JWT 토큰을 storage에 저장하고 필요한 정보들 예를들어, 사용자 이름이라든가, roles와 같은 권한 정보들을 토큰에서 꺼내서 화면 처리를 하게 된다. 또한 api 호출시 http 헤더에 토큰 정보를 담아서 호출해야 한다. 그러면 서버에서는 토큰 정보를 꺼내서 유효한 토큰인지를 판단해서 유효하지 않으면 401을 유효하면 처리하도록 한다. 즉, 보안은 클라이언트와 서버 양쪽모두에서 처리해야 한다.

JWT 프로토콜은 아래를 참고하자.

jwt.io

JWT 토큰은 헤더.페이로드.서명 이 세가지로 이루어져 있고, 코딩과 관련된 부분은 페이로드 부분이다. 페이로드 부분은 registered 클레임, public 클레임, private 클레임 이 세가지가 있다는 것을 알아야 하고, registered 클레임에는 iss, sub, aud, exp, nbf, iat, jti 가 각각 무슨 의미인지를 파악해야 한다. 코딩시에 만일 roles과 같은 권한 정보를 넣고 싶다면 registered 클레임에는 정의가 안되어있으므로 private 클레임에 넣어야 한다는 것을 알아차려야 한다. 즉, 등록된 클레임에 정의되어있지 않다면 private 클레임에 정의해야 한다.

블랙 토큰이란?

로그인해서 jwt 토큰을 발급은 받은 상태에서 로그아웃을 하였다. 로그아웃을 한 후에 로그인시 발급받은 토큰을 가지고 REST api를 호출하였다. 호출이 정상적으로 될까?

된다. 왜? 이미 발급받은 토큰은 유효기간이 정해져 있기 때문에 로그아웃을 한다고 해서 토큰이 무효화가 되는것은 아니기 때문이다. 그러면 어떻게 이걸 해야 하나? 로그아웃을 하면 서버에서는 클라이언트에게 발급된 토큰을 서버에 블랙토큰으로 등록해야 한다. 그리고 api 처리전에 블랙토큰으로 등록된건지를 체크해주는 로직이 필요하다. 실제 규모있는 프로젝트 보안 이슈에서 종종 등장하는 이슈이다.