Refresh Token을 어디에 저장해야 할까?(Feat. XSS, CSRF, CORS)

taehee kim·2023년 1월 7일
2
post-custom-banner

0. 글 작성 배경

  • Refresh Token을 어디에 저장하는 것이 좋은지 찾다보니 관련된 보안 관련된 내용이 많아서 정리하게 되었습니다.
  • XSS, CSRF공격이 어떤 공격인지 와 방어책, CORS정책에 대해서 알 필요가 있기 때문에 이에 대해서 소개합니다.
  • Backend에서 어떻게 해당 공격들을 방지해야 할지 정리하였습니다.

JWT Token

JWT 인증방식에서 Refresh Token을 왜 사용할까?

  • JWT의 장점은 Session과 다리 인증 기능을 위해 서버에 정보를 유지하지 않고 Stateless 하게 구성 할 수 있다는 점입니다.
  • 하지만 이 때문에 Token을 일단 발급하고 나면 원하는 때에 만료시키는 등의의 인증 상태에 대한 조작이 Session에 비해서 힘들다는 단점이 있습니다.
  • Refresh Token발급을 통해 이러한 단점을 보완하면서도 보안성을 유지할 수 있습니다.

Refresh Token은 어떻게 구현될까?

  • 로그인 시 Access Token과 함께 Refresh Token을 발급하고 Access Token의 경우 만료시간을 분단위로 짧게 유지시킵니다.
  • Refresh Token의 경우 만료시간을 비교적 길게 두어 Access Token만료 시 Refresh Token으로 재 발급 하는 방식으로 구현합니다..
  • 혹시나 Access Token이 탈취당하더라도 만료 시간이 적기 때문에 토큰을 탈취 당했을 때 위험이 감소합니다.
  • 특정 유저를 로그아웃 시키고 싶을 경우 즉시 로그아웃 시킬 수는 없지만, 만료시간 이후 Refresh Token으로 Access Token을 재발급 할 때에 User정보를 조회하고 재발급이 가능한 유저인지 확인하는 로직을 두는 식으로 구현할 수 있습니다.

Refresh Token 저장 위치?

  • Backend DB, Redis 등의 Storage에 저장하거나 Client측에 저장할 수 있습니다.
  • Backend 측에 저장할 경우 JWT를 사용하는 이유인 서버를 Stateless하게 유지하려는 의도와 충돌하기 때문에 특별한 경우가 아니면 Client측에 저장하는 것이 일반적입니다.
    • Client측에서는 Local Storage 혹은 Cookie에 저장할 수 있습니다.

Local Storage에 저장하는 경우

  • 장점
    • 구현이 쉽습니다.
  • 단점
    • XSS 공격에 취약합니다.

Cookie에 저장하는 경우

  • 장점
    • HttpOnly Flag로 XSS 공격을 방지할 수 있습니다.
  • 단점
    • CSRF공격에 대비해야합니다.

1. XSS, CSRF 공격.

1.1 XSS 공격이란

1.2 CSRF(**Cross-Site Request Forgery)** 공격이란

  • 사이트간 요청 위조, 사용자가 자신의 의지와 무관한 요청을 만들게 만드는 공격.

1.2.1 전제 조건과 공격 과정

CSRF 공격을 위한 조건과 과정에 대해 알아보겠습니다. CSRF 공격을 시도하기 위해선 아래와 같은 몇 가지 조건이 필요합니다.

  • 사용자가 보안이 취약한 서버로부터 이미 인증을 받은 상태여야 합니다.
  • 쿠키 기반으로 서버 세션 정보를 획득할 수 있어야 합니다.
  • 공격자는 서버를 공격하기 위한 요청 방법에 대해 미리 파악하고 있어야 합니다. 예상치 못한 파라미터가 있으면 불가능합니다.

위와 같은 조건이 만족되면 다음과 같은 과정을 통해 CSRF 공격이 수행됩니다.

  1. 사용자는 보안이 취약한 서버에 로그인합니다.
  2. 로그인 이후 서버에 저장된 세션 정보를 사용할 수 있는 sessionID가 사용자 브라우저 쿠키에 저장됩니다.
  3. 공격자는 서버에 인증된 브라우저의 사용자가 악성 스크립트 페이지를 누르도록 유도합니다.
    • 해당 악성 스크립트가 담긴 페이지를 클릭하도록 유도하는 방법은 다양한 것 같으나 몇 가지 유형을 정리하자면 다음과 같습니다.
    • 게시판에 악성 스크립트를 게시글로 작성하여 관리자 혹은 다른 사용자들이 게시글을 클릭하도록 유도합니다.
    • 메일 등으로 악성 스크립트를 직접 전달하거나, 악성 스크립트가 적힌 페이지 링크를 전달합니다.
  4. 사용자가 악성 스크립트가 작성된 페이지 접근시 쿠키에 저장된 sessionID는 브라우저에 의해 자동적으로 함께 서버로 요청됩니다.
  5. 서버는 쿠키에 담긴 sessionID를 통해 해당 요청이 인증된 사용자로부터 온 것으로 판단하고 처리합니다.
  • 즉, 쿠키에 이미 sessionID가 담겨 있기 때문에 누군가 악성 스크립트로 요청을 강제하면 사용자의 요청과 무관한 요청이 이루어질 수 있음을 이용한 공격방법 입니다..

1.2.3 CSRF 방어 방법

  • **Referrer 검증**
    • Referer header는 Request에 포함된 요청을 하는 쪽의 웹페이지 urI를 나타낸다.
    • Origin과 유사하지만 Origin은 Scheme, domain, port만을 의미하는데 반해 request path도 포함한다.
    • Referer가 원하는 Referer가 아닌 경우 요청을 거부하는 방식으로 보안성을 강화할 수 있습니다.
  • **CSRF 토큰 검증**
    • 로그인 시 CSRF토큰을 생성하여 세션에 저장해두고 클라이언트 요청 시 이 값을 검증합니다.
    • 세션을 저장해야하는 단점이 있습니다.
  • 더 다양한 방법들

2. 위 내용들을 기반으로 Refresh Token을 어디에 저장하고 어떻게 구현할지 구체적으로 결정해 봅시다.

Refresh Token은 Cookie에 저장합니다.

2.1 XSS 공격을 방지.

  • Local Storage는 XSS공격에 취약할 수 밖에 없습니다.
    • Javascript코드로 탈취가 가능하기 때문입니다.
  • 하지만, Cookie는 httpOnly flag를 줄 경우 Javascript코드로 조작이 불가능하기 때문에 XSS공격으로 인해 refresh token을 탈취하거나 조작하는것을 방지할 수 있습니다.

2.2 Cookie의 경우 CSRF에 취약하지만 이를 방지할 수 있습니다.

  • 먼저 secure flag를 true로 설정하여 Https인 경우에만 브라우저에서 Cookie로 설정하여 활용하도록 합니다.
  • SameSite=strict로 설정하여 CSRF를 방지할 수 있습니다.
    • 이 경우 요청자와 Authorization Server가 같은 Site를 사용하는 경우에만 활용할 수 있습니다.
    • 필자는 그렇지 않기 때문에 이를 none으로 설정하고 다른 방법들을 활용합니다.
  • strict로 설정할 수 없는 경우 CORS Origin을 특정하여 다른 사이트에서의 요청이 불가능하도록 방지합니다.
    • CORS는 요청한 서버의 Origin이 요청자의 Origin과 같지 않은 경우 서버에서 설정하여 응답 헤더로 적용된 Access-Control-Allow-* 헤더를 브라우저가 보고 응답 허용 여부를 결정하는 정책이다.
    • 허용 Origin(프로토콜, 도메인, 포트의 종합), method, header등을 나누어서 설정할 수 있고 브라우저가 서버로 부터 응답을 받고 난 후 CORS 통과 여부를 결정한다.
    • cors에 대한 자세한 내용 링크
  • CORS로 방지하는 경우 한계점은 브라우저에서 응답을 받지 않는 것이지 요청 자체가 서버에서 처리되지 않는것은 아니기 때문에 좀 더 완벽한 CSRF방지를 위해서는 위에서 CSRF방지에 쓰인 여러 방법을 종합적으로 고려해야 합니다.

JWT인증 과정을 어떻게 구현해야할까요?

  1. 초기 로그인 시 Access token의 경우에는 클라이언트에 body, request param등으로 전달하여 Authorization header에 ‘Bearer {token}’으로 설정하도록 합니다.
  2. Refresh Token의 경우 응답의 Set-Cookie 헤더로 쿠키로 설정하도록 하고 httpOnly secure=true, sameSite 조건을 꼭 지정해줍니다.
  3. 매 요청시 JWT검증 과정 중 Access Token이 만료되었을 시에는 Refresh Token으로부터 Access Token을 재발급 받을 수 있는 API를 요청하도록 처리합니다.
    1. 이 API내에서 User를 조회하여 정지되지 않은 유저인지 확인하고 아닌 경우 Authority를 다시 확인하여 Access Token을 생성합니다.
  4. Refresh Token마저 만료되게 되면 재 로그인 요청을 시도하게 합니다.
  5. CSRF방지를 위해 Referer체크, CSRF토큰 검증등의 과정을 추가해야합니다.

3. 결론

  • Refresh Token을 어디에 저장하는지에 대한 정해진 정답은 없지만, Cookie에 Refresh Token을 저장하는것이 가장 유리하다고 할 수 있습니다.

4. 출처

profile
Fail Fast
post-custom-banner

0개의 댓글