FE 토큰 기반 로그인에 관하여

·2023년 10월 9일
0

CS

목록 보기
3/3

HTTP의 특성

HTTP는 인터넷 상에서 데이터를 주고 받기 위한 서버-클라이언트 모델을 따르는 프로토콜임.
클라이언트가 서버에게 요청을 보내면, 서버는 응답을 보내줌으로써 데이터를 교환합니다.
HTTP는 비연결성(Connectionless), 무상태성(Stateless)의 특징을 가지고 있습니다.
이 말은 곧 요청에 대한 응답을 처리 완료하게 되면, 연결을 끊어버림을 뜻합니다.
따라서 클라이언트에 대한 이전의 상태 정보 및 통신 상태가 남아있지 않게 됩니다.

쿠키의 장점

  • 자동 인증
    쿠키는 브라우저와 서버 간에 자동으로 전송되기 때문에 매 요청마다 사용자를 식별하는 데 편리하다.
    이는 유저 사용성에 영향을 미치며, 서버가 유저의 로그인 상태를 쉽게 확인할 수 있다.
  • 보안
    쿠키는 HttpOnly 속성을 사용하여 보안을 강화할 수 있습니다.
    HttpOnly 속성을 적용한 쿠키는 HTTPS 연결에서만 쿠키가 전송되고, HttpOnly가 적용된 쿠키는 자바스크립트가 접근할 수 없으므로 XSS공격을 방지할 수 있습니다.

로컬 스토리지의 장점

  • 클라이언트 측에서 데이터 보존
    스토리지는 브라우저에 데이터를 저장하므로 서버에 요청을 보내지 않고도 클라이언트 측에서 로그인 정보를 보존할 수 있다.
    이것은 유저 경험을 향상시키고 서버 부하를 줄일 수도 있다.
  • 더 많은 데이터 저장 가능
    로컬 스토리지는 쿠키보다 더 많은 데이터를 저장할 수 있다.
    쿠키는 주로 작은(적은) 양의 데이터(4KB 이하)를 저장하는 데 사용됩니다. 반면 웹 스토리지는 최대 5MB의 데이터를 저장할 수 있다.

쿠키랑 스토리지 둘 다 저장하게 된다면?

  • 유연성
    두 기술을 조합하면 로그인 및 사용자 정보를 쿠키로 안전하게 전송하면서, 로컬 스토리지를 사용하여 클라이언트 측에서 데이터를 보존할 수 있다.
  • 퍼포먼스 개선
    쿠키를 사용하여 서버와의 통신을 최소화하면 서버 부하를 줄일 수 있다.
    동시에 로컬 스토리지를 사용하여 사용자 경험을 향상시킬 수 있다.

로컬 스토리지는 사용자 경험과 어떤 상관관계를 가지는가?

성능, 신속성, 오프라인 기능, 사용자 로그인 상태 유지 등

  • 데이터의 지속성
    브라우저에 데이터를 저장함으로써 사용자가 웹 사이트를 다시 방문할 때 이전 상태나 사용자 지정 설정 등을 쉽게 복원할 수 있다.
    사용자가 일정을 유지하거나 선호하는 테마를 설정하는 등의 작업에서 유용하다.
  • 페이지 로딩 속도
    일부 데이터를 로컬 스토리지에 저장하면, 필요한 정보를 서버에서 다시 가져오는 것이 아닌 클라이언트 측에서 바로 사용할 수 있다.
    이는 페이지 로딩 속도를 향상시키고 사용자에게 더 신속한 경험을 제공할 수 있도록 해준다.
  • 오프라인 기능
    사용자가 오프라인 상태일 때도 일부 기능을 제공할 수 있다.
  • 자동 로그인 및 세션 관리
    사용자가 웹 사이트에 로그인한 후에 해당 정보를 로컬 스토리지에 저장하게 되면 사용자가 다시 로그인하는 번거로움을 줄일 수 있다.
    하지만 이것은 보안상 위험한 방법이므로 로컬 스토리지에 로그인 정보를 절대 저장해선 안된다.
  • 개인화 및 사용자 선호도
    사용자의 테마, 언어 설정 등을 저장하면 사용자 경험을 맞춤화 할 수 있다.
    선호하는 방식으로 웹 서비스를 제공함으로써 사용자 경험 향상을 기대할 수 있다.

쿠키와 로컬 스토리지

일반적으로 로컬 저장소를 웹에서 사용할 경우 가장 많이 사용되는 방법은 쿠키, 로컬 스토리지이다.
쿠키와 로컬 스토리지는 각각 다른 목적을 가지고 있기 때문에 적합한 방법을 채택해야한다.

쿠키는 서버측과 클라이언트 측 양쪽에서 쿠키 데이터를 사용하는 api가 존재한다.
로컬 스토리지는 로컬 환경에서만 컨트롤 할 수 있다.

예시로 쿠키 데이터의 쓰임이 웹과 서버 양쪽에서 다 쓰이고, 서버쪽에서 활용이 높다면 쿠키값을 사용하는 것이 효율적일 것이다.

광고 7일 동안 보지않기 같은 기능은 쿠키로 구현한다고 한다.
반면 로컬 스토리지에는 유효 기간과 관련된 메소드가 없기 때문에 별도로 코드를 작성해줘야 한다.

로컬/세션 스토리지, 쿠키 장점과 단점은?

LocalStorage

  • 로컬에 도메인 별로 지속되는 스토리지
  • 시간제한 없음. 브라우저가 꺼져도 남아있음.
  • 값을 지우려면 직접 지워줘야함.
  • XSS 공격에 취약. 따라서 보안의 위험성이 높다.

SesstionStorage

  • 세션(프로세스, 탭, 브라우저)이 종료될 때 까지 지속되는 스토리지
  • 로컬 스토리지와 차이점은 소멸 타이밍이다.
  • 로컬 스토리지는 브라우저가 꺼져도 남아있지만, 세션 스토리지는 스토리지가 사라집니다.

    보통 세션의 종료는 "브라우저의 종료"를 뜻합니다.
    하지만 세션 스토리지에서 의미하는 세션은 가장 작은 단위인 "탭"단위를 의미합니다.
    "탭"마다 세션 스토리지는 따로 배정되며 서로의 영역을 공유하지 않습니다. 서로 값을 침범할 수 없음.
    (독립적)
    따라서 쿠키는 도메인이 같으면 항상 쿠키를 보내는 툭징이 있는데, 세션 스토리지는 각자의 탭 안에서만 의미가 있기 때문에 보안적으로 더 좋다.

쿠키

  • 브라우저당 4KB의 용량 제한
  • 네트워크 트래픽에 영향을 줄 수 있다.
  • 도메인 별로 데이터가 분리된다
  • 같은 브라우저라면 값을 공유한다
  • HttpOnly 속성으로 XSS 공격을 방어할 수 있다.

쿠키와 웹 스토리지를 함께 사용할 경우 주의할 점

데이터의 일관성을 유지해야한다. 두 저장소에 동일한 정보가 일치하도록 조치해야한다.

토큰 기반 로그인 - 로그인을 유지하기 위해서 어떤 과정이 필요한가?

  1. 인증
    사용자가 로그인을 시도하면, 서버는 사용자의 신원을 확인
    유효한 경우 - 엑세스 토큰, 리프레시 토큰을 발급
    일반적으로 엑세스 토큰은 짧은 유효기간을 가지고, 리프레시 토큰은 더 긴 기간 유효하다.

    예시 ) 유효기간 : 엑세스 토큰 30분 || 리프레쉬 토큰 1달

  2. 엑세스 토큰 사용
    클라이언트는 엑세스 토큰을 사용하여 보호된 엔드포인트에 요청을 보낸다.
    이 토큰은 서버에 의해 검증. 사용자의 권한을 확인하고 허용된 작업을 가능하게 한다.

    보호된 엔드 포인트
    서버에서 보호된(인증이 필요한) API 또는 리소스에 액세스하려고 클라이언트가 서버에 요청을 보내는 것을 의미

  3. 엑세스 토큰 갱신
    엑세스 토큰이 만료되기 전에 클라이언트는 리프레시 토큰을 사용하여 새로운 엑세스 토큰을 받을 수 있다.
    이를 통해 사용자는 로그인 상태를 유지할 수 있다.

  4. 리프레시 토큰 사용
    리프레시 토큰을 사용하여 새로운 엑세스 토큰을 받는 동안, 서버는 클라이언트가 여전히 유효한 사용자인지 확인한다.
    만약 리프레시 토큰이 만료되었다면, 사용자는 다시 로그인해야 한다.

    보통은 액세스 토큰이 갱신될 때 리프레시 토큰도 함께 갱신하는 방식을 채택한다.

  5. 로그아웃
    사용자가 로그아웃 하거나 세션이 종료된 경우, 클라이언트는 로컬에서 저장된 토큰을 삭제한다.

모바일에서의 경우는 어떻게?

모바일 웹에서도 웹 스토리지와 쿠키를 사용할 수 있다.
웹 스토리지는 자바스크립트 API 중 하나이기 때문에 브라우저가 실행되는 모든 환경에서 사용할 수 있다.

클라이언트에서 토큰 검증을 처리해도 되는가?

클라이언트에서 토큰 검증이 이루어지면 절대 안된다. 검증은 무조건 서버측에서 이루어져야 한다.
클라이언트 측에서는 받은 정보를 서버로만 보내주고, 받는 행위만 이루어져야한다.
토큰에 유저정보를 같이 넣어서 보내면 안됩니다!

클라이언트는 보안에 관련된 그 어떠한 것들도 판단하거나 처리하면 안된다.
오로지 서버로 전달만 합니다.
즉, 서버에서만 토큰을 까봐야합니다. 즉, 클라이언트 측에서 토큰을 먼저 까서 서버로 보내면 안된다.

Axios - 인터셉터?

토큰 인증 및 에러 처리, 로딩 상태 관리, 요청/응답 로깅 하는 데에 인터셉터를 사용할 수 있다.
인터셉터
인터셉터를 적용하는 예시

JWT란 무엇인가

Json Web Token

웹기술 표준
rfc - request for comments

안에는 무엇이 들어있는가?

  • 빨강색 Header
    - 암호화 규칙, 토큰 타입
  • 보라색 Payload
    - Web에서 Payload의 어원은 지급(Pay)해야 하는 적화물(load)를 의미합니다.
    - 토큰 데이터
  • 파랑색 signature
    - 암호화를 위한 데이터
    • 시크릿 키가 포함됩니다.
    • 서버에서 해당 jwt 가 유효한지 확인
    • 서버에서는 암호화되지 않는 secret key가 있고, signature에서는 암호화된 secret key가 있다. 이것을 기준으로 유효성을 검증합니다.
    • 시그니쳐는 클라이언트에서 만들지 않습니다! 유저가 로그인을 시도하면 (올바른 유저 정보가 전달되었을 때) 서버에서 생성해서 내려줍니다.

헤더와 페이로드는 아무나 까서 볼 수 있음.

  • Hash(해싱이란)란?
    - 복호화 할 수 없는 암호화 기법 (단방향 암호화)

발생할 수 있는 보안 사고

  1. 시크릿 키 노출
    헤더와 페이로드는 이미 공개되어 있고, 시크릿 키는 암호화되어 있는데 이것이 노출된다면 무한하게 토큰을 찍어낼 수 있는 경우가 생김
    즉, 모든 정보가 노출될 수 있는 위험이 있음.

    헤더와 페이로드는 아무나 까서 볼 수 있음.

  2. 데이터 복호화로 인한 정보 유출

Statelsee token

  • 중요한 정보를 왜 넣어두는가?

    토큰 자체가 스스로의 유효성을 검증하는 완결성을 가진다.

  • 서버 입장에서 토큰 하나로 검증할 수 있는 장점
    1. 서버에서는 매번 확인하는 것이 아니라 요청이 들어올때만 유효성을 알려주면 되는 장점
  • 클라이언트에서는 큰 장점이 없음. 서버측 장점이 크다.
  • 서버에서는 토큰 내용만 확인.
    유저 정보가 올바른지, 시그니처가 올바른지 등

클라이언트에서는 토큰 탈취를 주의해야합니다.

토큰 방식의 대체제

  • 세션 방식

정리

Q. 페이로드 까서 보는건 어차피 누구나 할 수 있는 건데도 그 페이로드 까서 사용하는 코드를 프론트엔드에서 직접 수행하고 있으면 안좋다는 건가요?

A. 그렇다. 그 이유는 클라이언트에서 페이로드를 디코딩해서 사용하는 순간, 클라이언트 사이드의 자바스크립트 코드 내에 페이로드를 디코딩하는 방법과, 그 안에서 유의미한 정보를 추출하는 방법을 알려주는 셈이 되기 때문입니다. 가급적이면 보안관련 알고리즘은 숨기는 것이 좋다.

따라서 유의미한 정보를 추출하는 코드들은 서버에서 작동하는 것이 보안상 가장 좋다.

추가적으로 페이로드를 까서 클라이언트 기능에 이용하는 것은 백엔드의 암호화 로직에 프론트엔드 기능의 의존성이 걸린다는 이야기이기도 하다.

백엔드에서는 보안 방식을 변경하고자 하는 것인데, 클라이언트에서 갑자기 유저 이름을 보여주는 기능에 문제가 생기는 일이 발생할 수 있다.

토큰 뿐 아니라 어떤 기능들을 개발할 때, 가능하면 지금 있는 것으로 어떻게든 구현할 수 있는 것보다 그 기능들이 서로 얽히지 않도록 하는 것을 권장한다.

멘토님의 첨언

리프레시 토큰의 유효성 검증을 유저 정보 조회 API에 달아서 사용할 수 있다.
토큰이 유효하다면 / 로그인에 성공했다면 유저정보+토큰을 내려주는 식으로.
근데 이건 백오피스성 서비스고, 실제 서비스면 이마저도 분리하는게 좋을것 같습니다.

토큰을 스토리지에 저장한다면 리프레시토큰만 로컬스토리지에 저장하고, 액세스토큰은 메모리에서만 사용하는 방식을 많이 사용한다.

HttpOnly 쿠키에 리프레시 토큰, 메모리에 accessToken을 담는 경우도 많습니다.
메모리에서만 사용한다 === 변수나 상태에 저장하여 사용한다. (상태 = React useState)

로컬 스토리지에 토큰 저장의 단점?

자바스크립트로 접근 가능하다.
XSS 공격 취약 (Cross Site Scripting)

쿠키에 토큰 저장 단점?

CSRF 공격

Refresh token

로컬 스토리지, 쿠키의 단점을 시스템 설계로 해결할 수 있음.

Refresh Token

Access Token

Access token 을 메모리에 저장한다는게 변수에 저장 시킨다는건가요 ?
=> 상태 및 변수 다 가능

엑세스 토큰이 만료되면, 리프레시 토큰으로 매번 요청을 보냄

RT를 httpOnly로 발급하면 브라우저의 쿠키 스토리지에 저장
httpOnly가 설정된 쿠키에 setCookie를 하면 작동하지 않음. 방어
그리고 httpOnly 설정은 서버에서 하고 내려줌(?)

쿠키를 발급하는 주체는 서버다.

  • 그럼 자동 로그인은 어떻게 구현하는가?

중요내용

httpOnly : true로 토큰 탈취 공격 방어 가능 (쿠키의 속성. 유저가 자바스크립트를 이용하여 세팅할 수 없도록 해줌)
RT, AT 2중으로 나누고 httpOnly 속성 적용 및 AT를 변수 및 상태에 저장시켜 방어가능
액세스 토큰 : 메모리에 관리
리프레쉬 토큰 : 쿠키 + httpOnly,,

1.로그인 요청
2.리스폰스 값 : 액세스, 리프레쉬
3.메모리에 저장된 액세스 토큰으로 요청을 함 (요청해야한다면)
4.액세스 토큰이 만료가됨
5.리프레쉬 토큰으로 다시 액세스 토큰 재요청
6.메모리에 저장된 재요청한 액세스 토큰을 헤더에 담아 정보 요청

인증이 필요한 페이지에서, 새로고침 및 상태로 들고있던 accessToken 이 리셋되면
이때마다 리프레시토큰으로 매번 요청을 보내는 건가? 맞음 ✅

페이지 이동시에 계속 refreshToken 으로 정보를 받아오진 않을테니, 역시 받은 유저의 정보도 상태로 들고 있는건가? 맞음 ✅

유저정보 없음 -> accessToken 확인 -> 없으면 refreshToken으로 정보요청 -> accessToken과 유저정보를 state로 저장 순서 맞나요? 맞음 ✅

React에셔는 XSS 공격 당할 수 있는 루트가 하나있음. _dangerouslySetInnerHTML

profile
- 배움에는 끝이 없다.

0개의 댓글