로그인 방식.. 뭘로 하지...?

bloom74·2024년 6월 10일
post-thumbnail

로그인을 매번 구현하면서 확실하게 로그인의 종류에 대해 모른다는 생각을 했다. 사소한 쿠키에 저장할지 localStorage에 저장할지 그 모든것이 보안과 연결되어 있기 때문에 항상 조심스럽게 생각하게 됐다. 이 기회에 인증의 유형과 어떤 저장 방식등이 있는지를 알아볼 예정이다.

인증

인증을 하기 위한 방법으로는 아래와 같은 방법들이 있다.

  • 비밀번호 기반 인증 - Hash와 Salt 기법
  • 이중 인증(2FA) 및 다중 인증(MFA) - SMS, 이메일, 앱 기반 인증
  • 생체 기반 인증 - 지문, 얼굴 인식, 홍채 인식
  • 토큰 기반 인증 - JWT, OAuth, SAML

비밀번호 기반 인증

암호화에는 단방향 암호화(절대 해독 불가능), 비밀키 암호화(임호키로 암호문 해독 가능)등이 있다.
고전 암호의 한계는 암호화 알고리즘을 알아내면 암호 해독이 가능하다는 점이였다. 그래서 현대에는 암호화키를 사용해서 알고리즘이 노출되더라도 키 없이 해독할 수 없게 만든다.

하지만, Brute Force Attack을 통해 레인보우 테이블을 만들어둔 해커들은 단순한 암호키를 이용한 Hash만으로 막을 수 없다.

Hash
Hash는 임의의 길이의 데이터를 고정된 길이의 데이터로 매핑하는 함수로 주로 SHA 방식으로 사용된다. SHA(Secure Hash Algorithm)은 서로 관련된 암호학적 해시 함수들의 모음이다. 해쉬 함수는 같은 데이터를 암호화 했을때 항상 같은 결과값이 나오기 떄문에 많은 시간과 자원이 있다면 직접 대입해 보면서 결과물과 비교해 원래 비밀번호를 알아낼 수도 있다.

Salt
Hash의 보완전으로 등장한 방식. 비밀번호 뒤에 임의의 문자열을 덧붙여서 해싱하는 방법. 예를들어, sewon만 해싱했다고 하면, sewonkorea 이라는 추가적인 문자열을 덧붙여서 해싱하게 되면 다른 결과물이 나온다. -> 하지만 이도 자원과 시간만 있다면 충분히 알아낼 수 있다. 하지만, 유저에 따라 임의의 문자열을 다르게 설정한다면 한명의 비밀번호가 유출되더라도 다른 사람의 비밀번호는 안전하게 된다는 장점이 있다.

토큰 기반 인증

토큰 기반 인증은 주로 웹 애플리케이션과 API 인증에 많이 사용된다. 먼저 토큰이란 무엇일까??

토큰(Token)이란?
사용자 인증을 위해 서버에서 발급하는 임의의 문자열. 이 문자열은 사용자 정보와 인증 상태를 포함할 수 있다.
서버가 클라이언트 상태를 기억하지 않는 stateless 방식에서 쓰일 수 있다. 서버는 클라이언트의 상태를 기억하지 않고, 클라리언트가 요청 시마다 토큰과 함께 전송하여 자신의 상태를 증명한다.

토큰 기반 인증의 흐름

  1. 사용자 로그인 - id, pw를 서버에 전송한다.
  2. 서버 인증 - id, pw를 확인하고 유효하다면 토큰을 생성하여 클라이언트에게 반환한다.
  3. 토큰 저장 - 클라이언트는 이 토큰을 쿠키 또는 브라우저 저장소에 저장한다.
  4. 요청 시 토큰 전송 - 클라이언트는 이후의 모든 요청에 이 토큰을 헤더에 포함하여 서버에 전송한다.
  5. 서버의 토큰 전송 - 서버는 요청을 받을 때마다 토큰을 검증하고 사용자의 신원을 확인한다.

주요 토큰 유형

JWT
- 헤더, 페이로드, 서명 세 부분으로 구성
헤더 : 토큰의 유형과 알고리즘 정보 포함
페이로드: 클레임(claim)이라고 불리는 사용자 정보 및 기타 데이터
서명: 토콘의 무결성을 검증하기 위한 서명
- Bas64URL로 인코딩되어 전송된다.
- Http 헤더에 실어 서버가 클라이언트를 식별한다.
- 상태를 서버에 저장하지 않아도 된다. 마이크로서비스 아키텍처에 유리하다.

OAuth 토큰

- OAuth 2.0 프로토콜을 따르는 토큰
- access token과 refresh token으로 구분한다.

SAML 토큰
- XML 기반의 토큰
- 주로 SSO(Single sign-on)에 사용

토큰 기반 인증의 장점과 단점

장점
- Stateless로 확장성이 뛰어남
- 클라이언트와 서버 간의 상태 공유를 공유할 필요가 없음.
- 분산 시스템에서 유용함

단점
- 토큰 탈취 시 보안 위협
- 토큰 갱신 로직이 필요
- 토큰 크기 문제 (JWT의 경우 페이로드가 커질 수 있음.)

브라우저 저장소 종류와 보안 이슈

localStorage 저장 방식
- 브라우저 저장소에 저장하는 방식이다.
- 자바스크립트 내 글로벌 변수로 읽기/쓰기 접근이 가능하다.
- HTML5에서 도입되었다. HTML5 이전에는 애플리케이션 데이터가 쿠키에 저장되어 모든 서버 요청에 포함되어야 했다.
- 쿠키와 비교했을 때 저장 용량이 훨씬 크며, 정보가 서버로 전송되지 않는다.
- 만료 날짜 없이 데이터를 저장한다.

localStorage에서 token 탈취 가능한 시나리오

sessionStorage 저장 방식
- 한 세션동안 데이터를 저장한다. (탭을 닫으면 데이터가 제거된다.)
- sessionStorage는 현재 떠 있는 탭 내에서만 유지. 같은 페이지라도 다른 탭에 있으면 다른 곳에 저장되기 때문이다.

indexDB 저장 방식
- 파일이나 블롭 등 많은 양의 구조화된 데이터를 클라이언트에 저장하기 위한 로우 레벨 API이다.
- 데이터를 고성능으로 탐색할 수 있다.
- RDBMS의 고정컬럼 테이블인 대신 객체지향 데이터 베이스.

쿠키란?

  • 서버가 사용자의 웹 브라우저에 전송하는 작은 데이터 조각이다. 브라우저는 데이터 조각들을 기억해두고, 동일한 서버에 재요청 시 저장된 데이터를 주로 사용한다.

  • 이를 이용하여 로그인 상태를 유지할 수 있다. stateless HTTP 프로토콜에서 상태 정보를 기억시켜주기 때문이다.

  • HTTP 요청을 수신할 때, 서버는 응답과 함꼐 Set-Cookie 헤더를 전송할 수 있다.

    쿠키 라이프타임
    - 세션 쿠키: Expires, Max-age 속성이 없는 쿠키. 현재 세션이 끝날 때 삭제된다. 브라우저는 "현재 세션"이 끝나는 시점을 정의하며, 어떤 브라우들은 재시작할때 세션을 복원해 세션 쿠키가 무기한 존재할 수 있도록 한다. Discard라는 파라미터가 설정되어 있다.
    - 영속적 쿠키: Expires 속성에 명시된 날짜에 삭제되거나, Max-age 속성에 명시된 기간 이후에 삭제된다.

Secure 쿠키
- HTTPS 프로토콜 상에서 암호화된 요청일 경우에만 전송된다.
- 하지만, Secure에도 민감한 정보는 절대 쿠키에 저장하면 안된다.
- 크롬52, Firefox52 이상을 사용한다면, 안전하지 않은 HTTP 사이트는 쿠키에 Secure 설정을 지시할 수 없다.

HttpOnly 쿠키
- xss공격을 방지하기 위한 방법.
- JS의 Document.cookie API에 접근할 수 없다.
- 서버에게 전송되기만 한다.
- ex) 서버 쪽에서 지속되고 있는 쿠키는 JS를 사용할 필요가 없다. -> HttpOnly플래그가 설정될 것이다.

세션 쿠키 기반 인증

  • 세션-쿠키 인증은 서버 측 세션과 브라우저 쿠키 간의 통신 인증 모델이다.
  • 서버 측에서 중앙 집중적으로 세션을 관리하고 모니터링한다.
    %%쿠키는 중앙 집중적 서버에 유리, 토큰은 마이크로 서버에서 유리%%

서버 기반의 인증 흐름

  1. 사용자 로그인 요청
  2. 서버에서 인증 처리 -> 사용자명 비밀번호 검증
  3. 세션 생성 -> 서버에서 고유한 세션 ID를 생성. 서버의 세션 저장소에 저장한다.
  4. 쿠키에 세션 ID 저장 -> 브라우저로 전송. 보통 HTTPonly 쿠키로 접근하기 때문에 스크립트에서 접근 불가능
  5. 사용자 요청 처리 -> 사용자가 서버에 요청을 보낼 때마다, 브라우저는 자동으로 저장된 세션 ID 쿠키를 서버로 전송한다.
  6. 세션 검증 -> 서버는 세션 ID를 세션 저장소에서 일치하는지 조회 및 확인한다.
  7. 응답 반환 -> 검증된 세션에 따라 요청에 따른 적절한 응답을 반환한다.

XSS공격, CSRF공격

XSS공격
공격자가 클라리언트 브라우저에 JS를 삽입해 실행하는 공격이다. 공격자가 input을 통해 JS를 서버로 전송해 서버에서 스트립트를 실행하거나, url에 JS를 넣어 클라이언트에서 스크립트 실행이 가능하다면 공격자가 사이트에 스크립트를 삽입해 XSS 공격을 할 수 있다.
이때 공격자는 JS를 통해 사이트의 글로벌 변수값을 가져오거니 그 값을 이용해 사이트인척, API콜을 요청할 수도 있다.
즉, 공격자가 코드가 내 사이트의 로직인 척 행동할 수 있다는 뜻이다.

CSRF 공격
공격자가 다른 사이트에서 우리 사이트의 APi콜을 요청해 실행하는 공격이다. API 콜을 요청할 수 있는 클랑이언트 도메인이 누구인지 서버에서 통제하고 있지 않다면 CSRF가 가능한데, 이때 공격자가 클라이언트에 저장된 유저 인증 정보를 서버에 보낼 수 있다면, 제대로 로그인한 것처럼 유저의 정보를 변경하거나 유저만 접근 가능한 액션들을 수행할 수 있다. 예를 들어 CSRF에 취약한 은행 사이트가 있다면 로그인한 척 계좌 비밀번호를 바꾸거나 송금을 보낼 수 있다는 것이다.

위 프로세스에 따라 세션id나 accessToken 같은 인증정보를 저장할떄 이용하는 저장소는 보통 localstorage나 쿠키다. 페이지를 리프레시하거나 창을 닫고 다시 접속할 떄도 로그인 정보가 이어지도록 둘 다 브라우저에 저장하는 방식이다. 하지만 두 방식은 XSS와 CSRF 공격에 취약할 수 있다.

정리

  • 세션 쿠키 방식은 중앙 집중형 서버에 유리 | 토큰은 마이크로서비스 아키텍처에 유리
  • JWT는 쿠키 혹은 브라우저 저장소에 저장 가능
  • XSS: JS를 삽입해 실행하는 공격
  • CSRF 공격: 다른 사이트에서 우리 사이트인척 API 콜을 요청해 실행하는 공격

인증에 대한 전반적인 정리를 해서 속이 시원하다. 가장 헷갈렸던 세션 쿠키 기반 인증에 대한 정리와 JWT 기반 인증에 대한 내용을 이해했다. 무엇보다 현재 리팩토링 중인 팀프로젝트에서 svg 파일을 업로든하는 부분이 있는데 XSS 공격에 대해 찾아보던 중, 파일 업로드를 통해 스트립트를 심어서 토큰을 탈취하는 방식에 대한 블로그를 보았다. 보안에 대해 경각심을 가지고 코드를 짜야겠다는 다짐을 하게 된다.

참고 자료

0개의 댓글