인증 인가 정보는 어디에 담아야할까? (cookie? authentication header?)

인증 인가를 구현하면 늘 고민이다. 쿠키에 넣어야하는가 헤더에 넣어야하는가?

인증 인가 정보는 어디에 담아야할까? (cookie? authentication header?)
Photo by Shreyak Singh / Unsplash

인증 인가 정보 전달 방법의 결정

요구사항

  • HTTP 표준에 부합해야한다.
  • 보안 이슈를 최소화해야한다.
  • 클라이언트에서도 처리가 간편해야한다.
  • 모든 HTTP request 에서 처리 가능해야한다.
  • JWT, Session 모두 고려해야한다.

고려대상

Request Body

  • Request Body 에 auth 정보를 싣어 보내는 방법의 경우 GET HEAD DELETE TRACE 와 같은 HTTP Method 에서 사용할 수 없다. 따라서 제외한다.

URL Query Parameter

  • ?auth=1d14dfebcea334a9d8c 와 같은 형식으로 전송하는 방법이다.
  • 다양한 클라이언트에서 제한 없이 query parameter 를 붙여 보내는 방식으로 구현이 가능하다.
  • URL 의 경우 길이 제한을 고려해야하며(2,083 자라 괜찮을 것 같지만), 노출되기 쉬운 URL에 인가 정보를 담는 것이 보안적으로 위험할 수 있다.
    • 물론 HTTPS를 통해서 통신할 경우 Query param, Path 는 암호화 대상이다. 그러나 단순한 노출에 있어 취약하다.
  • 의미적으로도 다른 좋은 대안들이 많으며 보안적인 이슈에서도 해결 방안이 없고 개인적으로 처리에 있어서 선호하는 방식이 아니다. 따라서 제외한다.

Authentication Header

  • 이는 몇 가지로 나눠볼 수 있다. HTTP 표준에서는 Authentication header 를 통한 인증을 기본으로 하고 있다. 이 중에서 JWT 기반의 인증 방식의 경우 Authentication header + Bearer Token 방식을 일반적으로 활용한다.
    • "Whenever the user wants to access a protected route or resource, the user agent should send the JWT, typically in the Authorization header using the Bearer schema. The content of the header should look like the following:"
    • https://jwt.io/introduction
  • Authentication: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c 과 같은 형태로 HTTP Header 에 설정하여 요청한다.
    • Bearer
      • Basic 인증과 Bearer 인증의 모든 것
        • 해당 서비스에서는 Basic 인증에 API 의 secret key를 담아 전송한다. 권한을 나누지 않으며 사용자를 특정하지 않는 경우이기에 적합하다. 반면, 우리 서비스에서의 인증 인가의 경우 특정 사용자를 구분하고 권한을 확인해야하는 경우가 많다. 따라서, Basic + Secret key 기반의 인증은 적합하지 않다.
  • 보안
    • Authentication Header 를 통해서 전송하기 위해서는 Local storage 혹은 Session storage 에서 관리되어야한다. Javascript 코드를 통해 접근이 가능하기에, XSS 공격에 대해서 취약하다. (cookie 의 경우 httpOnly 를 사용한다면 접근이 불가능하다.)
    • 하지만 CSRF 공격에 대해서는 유리하다. CSRF 공격의 경우 해당 사이트에 대해서 쿠키를 자동으로 전송하는 기능을 활용하지만, Authentication Header 의 경우 cookie 를 사용하지 않으며 해당되지 않는 웹에서는 직접 주입하지 못하기에 해당 공격에 대해 면역이다.
    • https://stackoverflow.com/questions/17000835/token-authentication-vs-cookies
  • Cookie header 를 통해서 필요한 정보를 cookie 에 담아 교환하는 방식이다. 서버에서는 set-cookie 를 통해서 클라이언트의 브라우저에게 cookie 를 설정하도록 할 수 있으며, 웹 브라우저 기반의 클라이언트는 브라우저에서 자동으로 이를 관리 / 전송한다.
  • Cookie는 웹 브라우저를 통한 클라이언트와의 통신에서 큰 강점이 있다.
    • httpOnly 옵션을 활성화 할 경우, document.cookie 와 같은 구문으로 js 에서 가져올 수 없다.
      • 이는 XSS 공격을 막는데 큰 도움을 준다.
    • 웹 브라우저에서 통신할 경우 cookie는 클라이언트 입장에서 out of box 영역이다. 완전히 browser 에 의해 자동으로 관리되도록 할 수 있으며, 이는 보안, 클라이언트 개발 편의성 모두 증대 시키는 방향이다.
      • 되도록이면 보안적인 요소를 클라이언트가 다루지 않도록 한다는 점에서 긍정적이다.
      • Authorization header, query parameter 등 다른 방법의 경우 어쩔 수 없이, client 에서 storage 에 저장을 해야하며, 이를 제어하는 코드가 필요한 것에 비하면 상당히 편리하다.
    • 반면, Cookie 의 경우 Browser 에서는 자동으로 관리할 수 있으나 Mobile application 제작 시에는 자동으로 관리가 되지 않는다 (별도로 라이브러리를 쓰거나 해야하며, 관리 되더라도 처리가 불편하다.) 일반적인 Web browser 에서 사용하는 것과 달리, 개발자가 직접 넣어주는 코드를 따로 작성해야한다. 이로 인해 Mobile Application 개발자 입장에서는 불편함이 존재한다
  • Authorization header 와 비교했을 때, Cookie 에는 다양한 값을 첨부할 수 있다는 것도 강점이다. 다양한 인증 정보를 동시에 전송할 수 있다.
  • Web proxy 를 거치는 경우에서도 cookie 가 유리하다. cookie 의 경우 web proxy를 거치는 과정에서도 그대로 유지되곤하나, authorization header 의 경우 web proxy 를 거치며 보안적인 이유나 캐시의 사용으로 변경될 가능성이 있다.
  • Cookie 의 경우 single domain 에 대해서만 묶인다는 것도 유의해야한다.
  • 웹 브라우저에 의해 Cookie 가 자동으로 전송되기에 CSRF 공격의 문제가 있다.
    • 이에 대한 해결책으로, Custom-Header 를 체크하는 방법을 사용할 수 있다.

의사결정

  • Cookie 기반으로 인증 정보를 전송한다.
    • 현재 우리가 개발해야하는 API 서버는 웹 브라우저 기반의 통신을 하는 클라이언트가 대상이다. Cookie 를 사용할 경우 클라이언트는 더 이상 해당 부분의 처리에 대해서 생각하지 않아도 되며, 서버에서 관련 작업을 모두 수행할 수 있다. 보안적인 측면에서나, 클라이언트 편의성 입장에서 유리하다.
    • Authentication Header 는 단일 정보만 싣어 나를 수 있는 것과 달리, Cookie 는 여러 개의 인증 정보를 한 번에 전송할 수 있다.
      • Authentication Header / Cookie 에 나눠 전송하는 것보다, 일관되게 모든 Authentication 정보를 cookie 에 담는 것으로 획일화하는 것이 적합하다고 판단했다.
      • 만약, 단일 Authentication 정보를 사용한다고 보장하며, 브라우저와 상관없는 API Server를 개발한다면 Authentication header를 사용했을 것 같다.
    • Authentication Header / Cookie 는 각각 보안 이슈, 일반적인 사용 사례에서 비슷하다. 즉, 어디에 두던간에 BE/FE 의 핸들링의 문제이지 큰 차이는 발생하지 않는다. 실제 상용 서비스 사례에서는 대부분 Authentication header 보다는 cookie 를 통해 정보를 전달한다.
      • 서비스 성격에 따라 달라짐을 유의하자. 다양한 클라이언트를 대상으로 하는 API 서버의 경우 Authentication header 를 활용하는 경우도 많다. 반면, web broswer를 통해 접속하는 웹 사이트에서는 authentication header 보다는 cookie 를 통해서 싣어나른다.
    • JWT 의 refresh_token 의 경우 refresh 경로에 대해서만 path를 지정하여 특정 요청에서만 전송하고, 매 요청에서 전송하지 않도록 해야한다.
      • ex) path = /api/auth/refresh
    • CSRF 공격에 대비하기 위해서 Custom Header 를 설정하는 방법 등을 고민해봐야한다.

필요한 배경 지식 및 참고자료

  • CSRF
  • XSS
  • HTTP 인증
  • Cookie
  • HTTP header