Session & Cookie/OAuth/JWT

콜트·2021년 1월 29일
0

라이징 프로그래머2

목록 보기
16/18
post-thumbnail
post-custom-banner

5주차 과제를 진행하면서, 클론 코딩 프로젝트에 JWT를 적용해보았다. 그 과정속에서 학습한 JWT를 비롯한 인증 방식에 대해 기록하고자 한다.

인증 방식

인증 방식이란 무엇일까? 간단하게 설명하자면, 놀이공원에 입장하고 놀이기구를 이용하기 위해서는 다양한 방법이 있다. 자유이용권, Big 5, 단일 발권 등등.. 여기서 각각의 방식에 대입해서 인증 방식을 간단하게 정리해보자.


앞서 말한 놀이기구를 이용하기 위한 여러 가지 방법 중에서 자유이용권은 어떤 속성을 갖고 있는지 생각해보자. 단순하게, 자유이용권은 놀이공원이 개장한 순간부터 폐장하는 순간까지 손목에 잘 차고만 있으면 모든 놀이기구를 이용할 수 있다. 하지만 만약 끊어져서 잃어버린다면? 그리고 끊어진 자유이용권을 다른 누군가가 주운 뒤, 본인의 손목에 이어서 붙여버린다면? 물론 그런 일이 있어서는 안되겠지만, 자유이용권을 주운 사람 또한 모든 놀이기구를 이용할 수 있게 될 것이다. 이와 같이, 자유이용권과 유사한 인증 방식이 Session & Cookie 방식이다. 단순히 Session ID를 가지고 있기만 하면 모든 권한을 갖게 되는 것이다. 그만큼 보안에 취약하기도 하다. 반대로 말하면 Session ID가 노출되는 순간 주인이 가진 모든 권한을 타인도 가질 수 있다는 뜻이다.

인증 과정

따라서, Session & Cookie 인증 방식의 흐름을 간략하게 설명하면 다음과 같다.

  1. 자유이용권 발권신청(로그인)
  2. 자유이용권 발권(서버에서 계정정보를 읽어 사용자를 확인한 후, 사용자의 고유한 ID값을 부여하여 세션 저장소에 저장한 후, 이와 연결되는 세션ID 발행)
  3. 자유이용권을 손목에 가지런히 채운다(사용자는 서버에서 해당 세션ID를 받아 쿠키에 저장을 한다).
  4. 놀이기구를 이용할 때마다 자유이용권을 보여준다(서버의 인증이 필요한 요청마다 쿠키를 헤더에 실어서 요청을 보낸다).
  5. 직원이 자유이용권을 확인한 뒤, 놀이기구를 신나게 이용한다(서버에서는 쿠키를 받아 세션 저장소에서 대조를 한 후 대응되는 정보를 가져오고, 인증이 완료되면 서버는 사용자에 맞는 데이터를 보내준다).

세션은 서버에서 가지고 있는 정보이며 쿠키는 사용자에게 발급된 세션을 열기 위한 열쇠(SESSION ID)를 의미한다. 만약 쿠키만으로 인증을 사용한다면 그건 서버의 자원을 사용하지 않는다는 것이며, 이는 클라이언트가 인증 정보를 책임진다는 말과 같다. 그렇게 되면 HTTP 요청을 탈취당할 경우 정보가 다 털리게 된다. 따라서 보안과는 상관이 없는 단순한 기능은 장바구니나 자동로그인과 같은 경우에는 유용하게 쓰일 수 있다.

장점

  • Session & Cookie 방식은 기본적으로 쿠키를 매개로 인증을 거치는데, 여기서 쿠키는 세션 저장소에 담긴 유저 정보를 얻기 위한 열쇠라고 보면 된다. 따라서 쿠키가 담긴 HTTP 요청이 도중에 노출되더라도 쿠키 자체(세션 ID)는 유의미한 값을 갖고있지 않습니다(중요 정보는 서버 세션에) 이는 계정정보를 요청에 담아 인증을 거치는 것보단 안전할 것이다(당연하게도).

  • 사용자 별로 고유의 ID값을 발급받게 된다. 그렇게 되면 서버에서는 쿠키 값을 받았을 때 일일이 회원정보를 확인할 필요 없이 바로 어떤 회원인지를 확인할 수 있기 때문에 서버의 자원에 접근하기 용이할 것이다.

단점

  • 만약 쿠키를 탈취당한다면, 실제 쿠키의 사용자가 누구인지와는 관계없이(놀이공원의 자유이용권과 마찬가지로) 사용할 수 있다. 즉, 타인의 정보로 요청을 보낼 수 있다는 뜻이다(다른 사람 명의로 결제를 한다던지 뭐.. 그런..).

  • 서버에서 세션 저장소를 사용해야하므로 서버에 추가적인 저장공간을 필요로 하게 되며, 자연스럽게 비용과 부하도 늘어나게 된다.


OAuth

Open Authorization, Open Authentication

OAuth는 인터넷 사용자들이 비밀번호를 제공하지 않고 다른 웹사이트 상의 자신들의 정보에 대해 웹사이트나 애플리케이션의 접근 권한을 부여할 수 있는 공통적인 수단으로 사용되는 접근 위임을 위한 개방형 표준이다.

OAuth - 위키백과

다음은 OAuth이다. 앞서 말한 놀이기구를 이용하기 위한 방법 중에 Big 5에 해당한다고 볼 수 있다. Big 5에 대해서 간단하게 설명하자면, 놀이기구 5개를 탈 수 있는 티켓이라고 보면 된다. 하지만 여기서는 조금 더 확장해서 허용된, 즉 정해진 놀이기구만 탈 수 있는 티켓이라고 보면 될 것 같다. 그런데 이때 티켓을 제 3자에게 부여받아서 사용하는 것이다. 네이버 로그인, 카카오 로그인등이 있다. 하지만 세션과는 다른 점이 있다. 예를 들어서, 처음에 Big 5 티켓을 발권받고 놀이기구를 이용하다보니 티켓을 모두 소진했다고 하자. 다시 놀이기구를 이용하기 위해서는 다시 티켓을 발급받아야 한다(....그럴거면 자유이용권을...). Session ID는 갖고만 있으면 계속해서 유효하지만 그와 달리 OAuth는 권한이 유효한 순간이 정해져있다. 이 기간은 짧은 편이므로 만료되기 전에 갱신해줘야 한다.

OAuth는 쉽게 말해서 다른 서비스의 회원 정보를 안전하게 사용하기 위한 방법이라고 생각하면 된다. 여기에서 안전하게의 주체는, 회원 정보를 가지고 있는 주체, 우리의 고객이다. 즉, 우리의 고객이 안전하게 다른 서비스의 정보를 우리 서비스에 건네주기 위한 방법이다. 고객이 자신의 소셜 서비스의 아이디/비밀번호를 우리 서비스에 알려주지 않아도, 소셜 서비스에 있는 고객의 정보를 우리 서비스에서 안전하게 사용하기 위한 방법이다.

인증 과정

그렇다면 OAuth의 인증 과정은 다음과 같이 간략하게 정리할 수 있다.

콜트월드(가명) 발권업무 담당 직원(이하 직원), 콜트(놀러온....)가 있다고 하자.

  1. 콜트는 직원에게 Big 5 티켓을 달라고 한다.
  2. 직원은 콜트가 콜트월드에 예약한 이력이 있는지 확인한다.
  3. 이때 콜트는 소셜 서비스로 예약을 했다고 답한다.
  4. 직원은 콜트의 예약여부를 확인하기 위해 네이버 또는 카카오 등등 소셜 서비스에서의 예약여부 증명을 요청한다.
  5. 콜트는 소셜 서비스에 로그인하고 예약화면을 보여줌으로써 예약여부를 증명한다.
  6. 그러면 직원은 해당 증명을 바탕으로 소셜 서비스에 존재하는 콜트의 정보를 얻어온다.
  7. 얻어온 정보를 바탕으로 직원은 콜트에게 티켓을 발권해준다.
  8. 콜트는 티켓을 이용해서(5개뿐인....) 신나게 놀이기구를 이용한다.

Redirect & URI

이는 결국 소셜 서비스에서 발급한 Access Token을 얻기 위한 절차이다. 소셜 서비스가 가진 유저의 정보를 요청하기위해선 해당 Access Token이 필요하기 때문이다.

이러한 토큰을 우리 서비스에서 전달받기 위해서 Redirect를 이용한다. 우리에게는 QueryString이 있기 때문이다. 그러니까, 소셜 서비스에서 로그인에 성공하면 우리 서비스에서 정의한 특정 URIredirect하면 된다는 것이다. QueryString에 토큰의 값을 묶어서!
그렇게 하면 우리 서비스에서 소셜 서비스에서 발급한 토큰을 받을 수 있게 된다.

그래서 우리 서비스에서 소셜 서비스로 로그인 요청을 보낼 때 redirect_uri를 지정해서 보내게 된다. 하지만 이 요청이 탈취되어 redirect_uri가 수정되어 악의적으로 사용되는 것(XSS, 피싱 사이트)을 방지하기 위해, OAuth를 사용하려면 우선 해당 서비스에 등록절차를 밟아야 한다. 즉, 소셜 로그인 기능을 사용하려고 한다면 사전에 해당 소셜 서비스에 등록을 하고 승인을 받아야 한다.

그리고 이러한 등록 과정에서 여러 가지 정보를 기입하는데, 이 때 redirect_uri도 사전에 미리 지정해주게 된다. 이렇게 함으로써 지정된 redirect_uri가 아닌 다른 값으로 redirect한다면 소셜 서비스는 이 요청을 받아들이지 않을 것이다.

이제 해당 Access Token을 이용해서 소셜 서비스에서 제공하는 APIURI로 요청하면 소셜 서비스에서 정보를 얻어올 수 있다.

Permission List

Access Token을 가지고 있더라도 허용된 권한만 사용할 수 있게 하기위해 토큰과 함께 보내는 Permission List라는 것도 있다.

정리

  1. 서비스를 등록하는 과정
    • 네이버에 자사 서비스 등록하기
    • 이 과정에서 redirect_uri 등을 합의하기
  2. 토큰을 받기 위한 과정
    • 사용자를 네이버 로그인 페이지로 이동시키기
    • 네이버가 사용자를 우리 서비스로 리다이렉트 시키기
  3. 토큰을 이용해 정보를 요청하는 과정

장점

  • 복잡한만큼 보안성이 좋다.

단점

  • 과정이 복잡한 만큼 리소스가 많이 든다. 완료 체크 등등.. 처리할 요소들이 많다.

JWT(Json Web Token)

다음은 JWT이다. JWT는 마치 손목에 도장을 찍어주는 것과 비슷하다고 볼 수 있다. 매번 놀이기구를 이용 할 때마다 손목에 찍힌 도장을 보여주는 것이다.

로그인에 성공하면 서버는 인코딩한 문자열을 토큰인것처럼 보내게 되는데, 클라이언트는 요청을 보낼 때마다 이를 헤더에 실어서 같이 보내어 권한을 검증하게 된다. 이를 JWT라고 하며, 인증에 필요한 정보들을 암호화시킨 토큰을 뜻한다. SSL 통신(HTTPS)을 통해 패킷 자체를 못 보게 할 수 있다(확률을 낮추는 것.. 뚫으려고 작정하면...). 그래서 JWT에는 SSL을 반드시 적용해주는 것이 좋다.

JWT의 3요소 - 'Header', 'Payload', 'Signature'

JWT에 들어가보면 암호화된 토큰을 볼 수 있다.

토큰을 만들기 위해서는 크게 3가지, Header, Payload, Verify Signature가 필요하다.

  • Header : 위 3가지 정보를 암호화할 방식(alg), 타입(type) 등이 들어간다.
  • Payload : 서버에서 보낼 데이터가 들어간다. 일반적으로 유저의 고유 ID값, 유효기간등이 들어간다.
  • Verify Signature : Base64 방식으로 인코딩한 Header, Payload 그리고 SECRET KEY를 더한 후 서명된다.

최종적인 결과 : Encoded Header + "." + Encoded Payload + "." + Verify Signature

Header, Payload는 인코딩될 뿐(16진수로 변경), 따로 암호화되지 않는다. 따라서 JWT 토큰에서 Header, Payload는 누구나 디코딩하여 확인할 수 있다. 그 말은 곧, Payload에 중요한 정보를 담으면 쉽게 노출될 수 있기 때문에 주의해야 한다는 뜻이다.

하지만 Verify SignatureSECRET KEY를 알지 못하면 복호화할 수 없다.

A 사용자가 토큰을 조작하여 B 사용자의 데이터를 훔쳐보고 싶다고 가정하자. 그래서 payload에 있던 A의 ID를 B의 ID로 바꿔서 다시 인코딩한 후 토큰을 서버로 보냈다고 하자. 그러면 서버는 처음에 암호화된 Verify Signature를 검사하게 된다. 여기서 Payload는 B사용자의 정보가 들어가 있으나 Verify Signature는 A의 Payload를 기반으로 암호화되었기 때문에 유효하지 않는 토큰으로 간주하게 된다. 여기서 A사용자는 SECRET KEY를 알지 못하는 이상 토큰을 조작할 수 없다는 걸 확인할 수 있다.

인증 과정

JWT의 인증 과정을 간략하게 정리하면 다음과 같다.

  1. 콜트월드의 회원인 콜트가 놀이공원에 입장하려고 한다.
  2. 직원은 콜트가 회원인지 확인한다.
  3. 회원으로 확인되면 간단한 정보들이 담긴 도장을 손목에 찍어준다.
  4. 콜트는 놀이기구를 이용할 때마다 손목에 찍힌 도장을 보여주게 된다.
  5. 도장에는 유효기간 및 기타등등의 정보들이 기재되어 있고, 놀이기구를 탈 때마다 해당 정보들이 유효한지 검증한다.
  6. 각각의 정보들이 올바르다면 콜트는 놀이기구를 이용할 수 있게 된다.

장점

  • 간편하다. Session & Cookie는 별도의 저장소 관리가 필요하다. 하지만 JWT는 발급한 후 검증만 하면 되기 때문에 추가 저장소가 필요 없다. 이는 상태를 저장하지 않는(Stateless) 서버를 만드는 입장에서는 큰 강점이다. 서버를 확장하거나 유지 또는 보수하는데 유리하기 때문이다.

  • 확장성이 뛰어나다. 토큰 기반으로 하는 다른 인증 시스템에 접근이 가능하다. 예를 들어 Facebook 로그인, Google 로그인 등은 모두 토큰을 기반으로 인증을 하는데, 이에 선택적으로 이름이나 이메일 등을 받을 수 있는 권한도 받을 수 있다.

단점

  • 이미 발급된 JWT에 대해서는 조작이 불가능하다. Session & Cookie의 경우 만일 쿠키가 악의적으로 이용된다면 해당하는 세션을 지워버리면 된다. 하지만 JWT는 한번 발급되면 유효기간이 만료되기 전까지는 계속 사용이 가능하다. 따라서 악의적인 사용자는 유효기간이 지나기 전까지 계속해서 정보를 탈취할 수 있다.
    - 기존의 Access Token의 유효기간을 짧게 하고 Refresh Token이라는 새로운 토큰을 발급함으로써 Access Token이 탈취당했을 때 발생할 수 있는 피해를 줄일 수 있다.

  • Payload 정보가 제한적이다. Payload는 따로 암호화되지 않기 때문에 디코딩하면 누구나 정보를 확인할 수 있다. 따라서 유저의 중요한 정보들은 Payload에 넣을 수 없다.

  • JWT의 길이이다. Session & Cookie에 비해 JWT의 길이는 길다. 따라서 인증이 필요한 요청이 많아질수록 서버의 자원낭비가 발생하게 된다.


참고자료


profile
개발 블로그이지만 꼭 개발 이야기만 쓰라는 법은 없으니, 그냥 쓰고 싶은 내용이면 뭐든 쓰려고 합니다. 코드는 깃허브에다 작성할 수도 있으니까요.
post-custom-banner

2개의 댓글

comment-user-thumbnail
2021년 2월 25일

우와 콜트님 ~ 깔끔 그 자체군요 ? 정말 도움되는 글입니다 !
저도 스프링부트 시작하고 싶네요 ㅎㅎ~

1개의 답글