프론트엔드 로그인과 관련된 여러가지 개념과 기술

여경·2024년 4월 24일
1

작년 프리온보딩 챌린지 당시 강의 내용을 정리하고 요약해뒀던 글이다. 굉장히 유익했던 강의라 shoveling 레포에 기록해두었는데, 벨로그에 올리는 걸 까먹었어서 다시 정리해보았다.

  • 로그인과 관련된 여러 가지 개념과 기술
  • 프론트엔드에서 일반적으로 로그인을 구현하는 방법 - 백엔드에서 일어나는 일 맛보기
  • 인프라 관점에서 생각해 보기
  • 여러 가지 실습과 질문/답변

토큰이란?

로그인이란?

사용자가 시스템에 접근하거나 동작을 수행하는 것을 제어하고 기록하기위한 컴퓨터 보안절차

사용자를 식별하기 위해

로그인에 토큰을 사용하는 이유?

http 요청이라는 것은 단지 텍스트 요청이며 무상태성을 유지해야하기 때문에 알수 없음.

일단 이렇게만 해도 굴러가긴 한다.
실제 서비스에서의 구조 (*액세스 토큰만 사용한다는 가정)

검정 박스가 클라이언트 단에서 처리하는 부분

JWT Token

JSON web token

json 기반 웹에서 사용하기 위해 만든 토큰

내부 구조

  1. Header
  • 암호화 규칙
  • 토큰 타입
  1. Payload
  • 데이터 (클레임)
  1. Signature
  • 암호화를 위한 데이터

  • 특정 문자열 : 서버에서 해당 jwt 가 유효한지 확인 해보는 용도

  • 왜 이러한 문자열인지는 알 수가 없음. 해싱이기 때문

해싱이란?

  • 암호화 기법 중 하나로 단방향 연산 즉, 돌아갈 수 없는 방식

JWT 유효성 검증 방식

secret key는 서버가 만들어서 클라이언트는 알 방법이 없음.
헤더와 페이로드는 언제나 클라이언트에서 열어볼 수 있다. 하지만 이 두가지로는 만들 수 없는 조각을 주는 것(시그니처)
시그니처에 서버가 자신이 준것이 맞는지 확인해볼 수 있는 시크릿 키가 맞는지 해싱을 다시 돌려서 해시로 나온 값과 동일한지 확인 할 수 있다 (= 올바른 유저인지)
서버에서는 암호화되지 않은 secret key가 있고, 시그니처에서는 암호화된 secret key를 가지고 있다.

서비스 구조에 대입해보기

실제로 JWT 관련 동작이 일어나는 곳

발생할 수 있는 보안 사고

클라이언트 - 토큰 탈취
-> 토큰이 유효한 시간 동안 로그인이 모두 가능한 상태됨..

서버- 시크릿 키 노출
-> 토큰을 무한하게 찍어낼 수 있는 상황이 발생함
어떤 사용자의 이름, 이메일 등 사용자정보를 무한히 찍어낼 수 있게 되는 것
클남..

Stateless token

  • 중요한 정보를 왜 넣어두나요?
    토큰 자체가 스스로의 유효성을 검증하는 완결성을 가지게 됨.

서버입장에서는 문자열(토큰) 하나면 유저 확인을 언제든 가능함.
클라이언트 사이드에서는 사실 이득도 업다.. 해달라고 하면 되기에 딱히 단점도 없다..
서버에서는 매번 확인하는게 아니라 요청이 들어올때만 유효성을 알려주면댐

토큰 하나에 시크릿키 하나면 유효 여부, 유효에 대한 기간, 정보들을 모두 알 수 있다.

JWT 보관 방식과 보안

Refresh token & Access Token 사용하기

리프레시 토큰은 발급은 하는데, http only 쿠키로 발급

  • 제약 : https 로만 접근 가능
    액세스는 인증서버에 요청했을때 메모리에만 발급해줌 (메모리는 해커가 접근 불가능)
  • 요약
    액세스 토큰 : 메모리에 관리 (const에 선언하는 머 그런것들)
    리프레쉬 토큰 : httpOnly 속성 쿠키 로 발급

보통 그렇기에 인증 필요한 api 호출시 보통 2개의 api가 전송됨
(토큰 유효한지 체크 api + 해당 토큰으로 받아오는 정보 api)


<정리 ~! >
1. 로그인 요청
2. 리스폰스 값 : 액세스와 리프레쉬
3. 메모리에 저장된 액세스토큰으로 요청
4. 액세스 토큰이 만료가 됨
5. 리프레쉬 토큰으로 다시 액세스 토큰 재요청
6. 메모리에 저장된 재요청한 액세스 토큰을 헤더에 담아 정보 요청

  • 보안을 위해 조치할 수있는 것이 늘어나고 매번 로그인 하지 않고도 탈취 사고 위험도 줄일 수 있다.

세션

스토리지 ? 저장소

로그인 행위 되돌아보기
사용자가 누군가인지 식별하기 위해 로그인을 사용, 그 수단으로 토큰을 사용함.
세션은 연결 자체의 이름, 사용자의 로그인해서 로그아웃, 혹은 만료까지의 기간(커넥션)
세션 방식 로그인 : 사용자 로그인이 유효한 시간동안 서버에 세션 아이디를 기록하고 인증에 사용하는 방식

  • 세션에서는 세션 아이디를 서비스가 기록을 해두고 사용자가 누군지 알아보고 로그인하는 방법

어떻게 하는데?

쿠키 방식

쿠키란?

서버에서 보내주는 작은 데이터 조각, 클라이언트에게 setCookie 와 같은 리스폰스 헤더에 담아 전달,,

같은 도메인에 보낼때 그 쿠키를 자동으로 붙여서 보낸다.

실제로 브라우저에서 어떻게 동작?

  1. 서버에게 로그인 요청을 보낸다.
  2. set-cookie 에 붙여 보냄
  3. 세팅이 잘 되면, 쿠키가 개발자 도구에서 볼수 있듯 표시됨
    만약 잘 못되었다면... ~ 정책적으로 쿠키가 꼬이거나 문제가 있어도 에러도 안 내고 조용히 실패,,, 그게 단점
    인증쿠키는 Get 요청으로 하면 안됨 ..

쿠키는 직접 넣어주는 값이 아니다. 프론트에서 직접 할 일은 없다.

쿠키 관련 정책 지정하기

SamSite

  • None : 아무도메인이나 상관없고, getCookie 와 같은 것 다 가능, ㄹㅇ 사랑의 쿠키 나눔행사,, 최근에 크롬에서 막음
  • Lax : 안전한 몇개의 operation에 대해서만 cross site 허용(https, httpOnly 속성 설정과 같은것 )
  • Strict : 도메인이 같은 경우 허용

httpOnly

  • 통신 전용 -> 클라이언트에서 값 가져가서 알 필요 없다고 자바스크립트 접근 불가

Secure

https : 인증서 기반 암호화 - 패킷의 암호화가 올바른 경우에만 sameSite lax가 동작

로컬호스트는 보통 http -> CORS 오류 자주 발생, 403 밴 당하는 경우도 종종 발생

CORS

CORS란 오리진이 다른 두경우(도메인이 다른 두개) 서로 api를 찔러서 가져가는 경우를 차단 해둔당..

에러 해결방법

  • 브라우저에서 할 수 있는 일? 업따..

  • 로컬 호스트를 https 로 띄우는 걸 통해 http 라 발생하는 오류들을 막는 방법이니 해보면 좋음

세션 아이디를 쿠키에 담아 credential true로 주면, 자동으로 왔다갔다 ~

지난 번 도메인 호출과 인프라 구성 비교하기

  • 로컬호스트에서 도메인으로 전송하도록 했었고

세션 방식 로그인은

: 4000에 서버, :5173에 클라 띄워서 같은 로컬 pc에서 구성함

세션 로그인 동작 살펴보기

  • 세션이 유효한지는 토큰방식과 동일하게 서버에 물어봄

실제 서비스가 되기위해 필요한 것

  • 로그아웃
    • 세션을 어떻게 expired 시킬것인가, cookie 를 지우는지..
  • 회원가입
  • 권한 관리

세션 vs JWT

JWT의 장단점

  • 서버/백엔드 비용 감소, 인프라 구성등에 사용되는 비용이 줄어들 수 있음, state가 없기에 (stateless 유지)
  • 프론트엔드 복잡도 높아짐 - 토큰 로테이션, 액세스 토큰 어디에 저장할지 등등 구성해야함
  • 보안상 세션보다 조금 더 위험하다 - 탈취될 위험이 남아있기에 쪼오끔.. 위험

세션의 장단점

  • 서버/백엔드 비용 대폭 증가 - 인프라 비용이 많이 오름, 세션을 유지해야하기 때문에 ..(ex: 전화통화를 100명이랑 유지해야한다고 생각하면? 모두 다 기록 관리 ... state 존재)
  • 프론트엔드 인증 쉬워짐
  • 보안상 약간의 향상...

동시 접속자 수, 서비스 규모, 앱/웹 동시운용 여부, 팀내 인력 구성 등등... 을 이유로 선택은 서비스 상황에 따라 결정
앱/웹... 동시 사용시에는 토큰 많이 사용,, 뭐 프론트가 굉장히 많은 경우 토큰 사용하거나 ~ 백이 많으면 세션을 쓰는게 유리하다고 생각 둘다 없으면 뭐 화이팅 ㅋㅋㅋ..이러네

HTTP Request

프로토콜

하이퍼 텍스트 -> 누르면 이동하는 문서

Bearer

  • 이게 토큰이라는 것을 표현하기 위한 prefix 같은 존재, 그저 약속이라고 생각하면 댐

cURL

  • 커맨드라인에서 url을 호출할 수 있는 도구

  • 백 이슈인지 브라우저 이슈인지 등을 확인하는 용도,,
  • 포스트맨 같은 도구

서버와의 역할 분담에서 항상 지켜져야 하는 것

프론트의 코드는 브라우저에 노출되기 때문에 보안 관련된 역할 분담은 서버에게 확실히 이야기 할 필요가 있다 (서버 벨리데이션은 필수적이다)

권한에 따라 동작 제어하기

그 다음 프론트에서 할 일 -> 권한에 따라 적절한 자원에 접근하도록 하기
ex) 유저에게 role이 주어져있는게 없다면 로그인 으로 routing , 뭐 빈 컴포넌트 리턴



http 401 에러 ( 누구세요) 에 대한 문제 해결 - > 리프레시 토큰으로 엑세스 토큰 재발급 시도 (무한루프 가능성 있는 코드임 - 리프레시 토큰에 의해 401이 해소되지 않는경우에 발생가능함 , retry 카운트 만드는걸루 해결해볼 수 있음(윈도우 객체에다가 Number해도 되고, axios 인스턴스 안에다가 만들어두됨))
요청을 시도하다가 요청이 실패한 경우에 임시신분증,,,(리프레시 토큰)으로 액세스 토큰 재발급 시도
재발급 실패 -> 로그인 페이지로 보냄

내부적 구성


(**수정사항 2번째꺼는 마지막 구문 삭제)
1.로컬스토리지에 저장하는 경우
2. 세션에 쿠키에다 저장하는 경우

리프레시 토큰은 항상 1회용이고 액세스 할때마다 새로운 엑세스, 리프레시 토큰이 매번 세팅이 되는 방식으로 구현

취약점 복습

refresh token

  • access token이 죽은 시점에 csrf 공격이 들어오면?
  • 살아잇는 시점에 탈취, 사용 되면?
  • refresh token이 탈취된다면?
    => 굿베이 ㅜㅜ ..

OAuth와 소셜 로그인

Open Authorization
허가된 다른 서비스를 통해 기존 서비스(구글, 네이버 등) 의 권한을 "위임"하는 것

기본적으로 개별 서비스(배민..이라구 하고~)가 있고, 원본 서비스가 존재한다.
1. 구글로 로그인 클릭 -> 개별 서비스가 링크를 하나로 주고, 구글한테 확인받고 오라고 리디렉션
2. 구글페이지에서 배민에서 구글게정으로 이런저런 동작하고 싶어요, => 이런저런 동작은? : 링크에 쿼리파라미터로 확인
3. 구글: 시크릿값을 주고, 주소 A로 이동하세요 , 구글 또한 보관
4. 구글 다녀옴, 시크릿값도 있고, 주소 A 도착 : 배민이 구글에게 시크릿값과 주소 A로 접근했다는 걸 확인 받음

  • 구글 입장에서는 이게 배민인지아닌지도 확인함 서비스(배민) 자체의 시크릿키도 포함해서 보냄

권한에 따라 오어스 원본 서버의 유저정보를 가져와 사용하거나 권한을 위임받은 동작도 할 수있으며, 인증 자체만으로 사용할수도 있다!

클라이언트가 구현해야할 동작
1. 리디렉션
2. 요청이 승인 되었을때 : 로그인을 기록해둘 방법이 필요, 세션이든 토큰이든 ~

서버입장 : 시크릿키도 챙기기, 배민-구글 간의 시크릿키도 갖고있기


~ 추가 공부

싱글톤 패턴
객체를 다루지 않는 프엔 트렌드 특성상 생소할 수있음 프론트에 없는 컨셉일지두..

하지만 우리가 구현한 것중에 비스무리한게 하나 있담.
하나의 데이터 오리진을 가지고 필요한 동작들을 수행하는 것

ex - 라우터 객체
사이드바에도 쓰이고, 페이지 라우터에도 쓰였음. 핵심은 이 데이터가 한가지라는 것.

데이터의 원천 생각하기
하나의 데이터가 하나의 맥락에서 관리되고 있는가?

백엔드도 처음이라면 모를 수 있어요



FormData < Json
멀 사용해도 상관 ㄴㄴ

0개의 댓글