로그인

이현섭·2023년 11월 11일
0

개인 프로젝트를 진행하다가 로그인을 구현 중 겪은 어려움 및 항상 까먹었던 로그인에 대해 기억하기 위해 작성합니다.

1. 로그인이란?

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

2. 토큰이란?

  • 토큰은 인증이나 정보교환에 사용되는 디지털 자격 증명.
  • 인증 토큰은 사용자가 시스템에 로그인할 때 생성되며, 사용자의 신원을 확인하고 권한을 부여하는데 사용됨.

토큰은 크게 3가지로 이루어짐

    1. header 암호화 규칙, 토큰의 타입
    1. payload 토큰 데이터
    1. signature 암호화를 위한 데이터

발생할 수 있는 보안사고

    1. 시크릿 키 노출
    1. 토큰 탈취

토큰은 어디에 저장해야 할까?

1. 로컬스토리지, XSS(Cross Site Scripting)

로컬스토리지와 세션스토리지

  • 로컬 스토리지에 저장된 데이터는 만료되지 않고 영구적. 데이터를 직접 삭제하거나 브라우저 캐시를 지우지 않는 이상 데이터가 유지됨.
  • 세션 스토리지에 저장된 데이터는 브라우저 탭이 닫히면 삭제됨.
  • 로컬 스토리지는 같은 출처(도메인)를 가진 모든 탭/윈도우 간에 공유됨.
  • 세션 스토리지는 각 탭/윈도우 마다 독립적. 같은 출처라도 서로 다른 탭/윈도우에서는 서로의 데이터를 볼 수 없음.

=> 둘 다 스크립트를 통해 접근할 수 있으므로 XSS 공격에 취약. 따라서 중요한 정보는 서버 측에서 관리하는 것이 편함.

XSS

  • XSS(Cross Site Scripting) 은 공격자가 웹 사이트에 악의적인 스크립트를 주입하는 보안 취약점.

  • 사용자의 브라우저가 악성 스크립트를 실행하게 되면, 공격자는 사용자의 세션 토큰이나 쿠키에 접근하거나, 사용자를 가장하여 행동을 취할 수 있음.

만약 토큰을 로컬스토리지에 저장하면 이러한 XSS에 특히 취약해짐.
로컬 스토리지는 JavaScript를 통해 쉽게 접근할 수 있기 때문에, XSS 공격을 통해 악성 스크립트가 주입되면 이 스크립트는 로컬 스토리지에 저장된 토큰을 읽고 이를 공격자에게 전송할 수 있음.

=> 이를 방지하기 위해 HTTP 쿠키에 HttpOnly 플래그를 설정하여 JavaScript가 쿠키에 접근하지 못하도록 하는 것이 권장됨.

2. 쿠키, CSRF(Cross-site Request Forgery)

쿠키란?

  • HTTP 쿠키는 서버가 사용자의 웹 브라우저에 전송하는 작은 데이터 조각.
  • 브라우저는 그 데이터 조각들을 저장해 놓았다가, 동일한 서버에 재 요청 시 저장된 데이터를 함께 전송함.

CSRF 란 ?

  • CSRF(Cross-site Request Forgery) 는 공격자가 사용자가 이미 인증된 웹사이트에 대해 악의적인 요청을 보낼 수 있게 하는 공격 방법.

  • 사용자가 로그인한 상태에서 악성 웹사이트를 방문하면, 이 웹사이트는 사용자가 의도하지 않은 요청을 실제 사이트에 대해 자동으로 수행할 수 있음.

쿠키에 자동으로 토큰이 포함되기 때문에 CSRF 공격에 취약함. 공격자는 사용자의 브라우저를 이용해 쿠키를 사용하여 인증된 사용자처럼 요청을 보낼 수 있음.

=> 이를 방지하기 위해 SameSite 쿠키 속성을 사용하거나 CSRF 토큰 과 같은 추가적인 검증 메커니즘을 사용

3. 세션 방식 로그인

  • 세션은 서버가 사용자의 상태를 기억하기 위해 사용하는 방법. 토큰 기반 인증은 무상태(stateless). 반면 세션 기반 인증은 상태 기반 (stateful) 방식.
  • 서버는 사용자의 상태 (로그인 정보, 사용자 설정 등) 을 서버에 저장하고, 클라이언트는 유일한 세션ID를 받음. 클라이언트의 요청마다 이 세션 ID를 전송하며, 서버는 이 ID를 사용하여 사용자의 상태를 조회함.

4. JWT vs 세션

JWT의 장점과 단점

  • 서버 / 백엔드 비용 감소
  • 프론트엔드 복잡도 높아짐
  • 보안상 세션보다 조금 더 위험

세션의 장점과 단점

  • 서버 / 백엔드 비용 대폭 증가
  • 프론트엔드 인증 쉬워짐
  • 보안상 약간의 향상

Next와 Nest로 로그인 구현 중 일단 토큰을 발급 후 로컬스토리지에 간단하게 저장해서 진행하려고했는데, 서버 컴포넌트는 로컬스토리지 접근이 되지 않기때문에 토큰을 쿠키에 저장 시도.

분명 postman에서 실행될때는 설정이 잘 되었지만 브라우저 탭에서 확인을 해보면 쿠키가 저장되어 있지 않음.

쿠키의 SameSite 속성

None : 동일 사이트, 크로스 사이트 모두 전송 가능. 이로인해 CSRF 공격에 취약.
SameSite를 None으로 한다면 Https 연결이 필요한 Secure 속성을 함께 넣어줘야함.
Strict : 크로스 사이트 요청에는 항상 전송되지 않음. 즉, SameSite에서만 쿠키의 전송을 허용
Lax : 기본적으로 크로스 사이트 차단. 하지만 예외사항이 있어 크로스사이트임에도 일부 요청 방식으로는 쿠키 전송 가능.

Chrome80 부터 SameSite 기본값이 None => Lax로 변경되었음.

현재 프론트는 localhost:3000 서버는 localhost:4000 인 상황.
따라서 쿠키를 설정해주기 위해서는 서버와 클라이언트에 둘 다 Credential 부분을 true 로 변경해줘야함!

credentials 속성을 true로 설정해준다면, nest는 자동으로 응답 헤더에
Access-Control-Allow-Credentials: true 를 포함시킴.
이 설정은 프론트가 다른 출처에서 온 요청에 대해 쿠키나 인증 헤더를 포함할 수 있게 해줌.

프론트의 fetch 에서도 credentials : "include" 적용.

credentials 속성은 브라우저의 fetch API나 XMLHTTPRequest 에서 쿠키와 인증 관련 헤더를 요청과 함께 보낼지 결정하는 옵션.

  • same-origin : 기본값. 같은 출처의 요청에만 쿠키와 인증 헤더를 포함시킴.
  • include : 모든 요청에 쿠키와 인증 헤더를 포함시킴. 이를 위해 서버에서도 Access-Control-Allow-Credentials : true 헤더를 설정해줘야 함. 이는 다른 출처(ex: 다른 도메인, 서브도메인, 포트) 의 요청에서도 사용자의 인증 상태를 유지하는 데 필요.
  • omit : 모든 요청에서 쿠키와 인증 헤더를 무시하고 보내지 않음.

정리

프론트엔드와 백엔드가 다른 포트나 도메인에서 실행될 때 CORS 정책에 의해 쿠키가 기본적으로 요청과 함께 전송되지 않음.
따라서 프론트엔드에서 credentials : include 를 설정하고
백엔드에서 Access-Control-Allow-Credentials : true 를 설정.

쿠키 저장 성공!

profile
안녕하세요. 프론트엔드 개발자 이현섭입니다.

0개의 댓글