인증과 인가

김동헌·2023년 12월 7일
0

CS

목록 보기
2/9
post-thumbnail

인증과 인가

인증(authentication)은 주로 사용자의 신원을 확인하고 확인된 신원을 기반으로 서비스 또는 시스템에 접근을 허용하는 과정을 말합니다.

  • 사용자가 서비스에 로그인할 때 누구인지 확인하는 과정 인증

인가(Authorization)는 인증된 사용자에 대한 자원(데이터, 서비스, 시스템 등)에 대한 접근 권한을 확인하는 과정

  • 관리자는 관리자 페이지에 접근할 수 있지만, 일반 사용자는 관리자 페이지에 접근할 수 없습니다.

간단하게

  • 인증은 사용자를 식별,
  • 인가는 식별된 사용자의 부여 권환을 확인하는 것 입니다.

자 그러면 다양한 인증 과정들에 대해서 알아보겠습니다.

  1. 기본적인 인증 → Request Header
  2. 인증 유지 → Browser(Cookie)
  3. 안전하게 인증 → Server(Session)
  4. 효율적으로 인증 → Token
  5. 다른 채널을 통해 인증 → OAuth

1. Request Header - 활용

Request Header를 사용하는 인증 방식은 사용자의 아이디와 비밀번호를 직접 서버에 전달하여 인증하는 방식입니다.
이 정보는 주로 HTTP 요청의 헤더에 넣어서 전송됩니다.

(API 구축되어 있다는 전제)

사용자가 아래와 같이 요청을 보냅니다.
http://user:qwe12@www.inklink.com/login

protocol(http://)host(www.inklink.com) 사이에 user:qwe12@를 넣어주고 POST를 서버에게 전송

이때 URL에 사용자 정보를 포함하는 경우, 브라우저는 이 정보를 서버에 전송하기 전에 Base64 인코딩을 진행합니다.

http://user:qwe12@www.inklink.com/login

base64

Base 인코딩 값 = 6G9uZXk6cGFzc3dvcmQ
↓ ↓ ↓ ↓ ↓
요청 헤더 Authorization: Basic 6G9uZXk6cGFzc3dvcmQ 넣어서 전송

이렇게 전송된 정보는 서버에서 디코딩되어 사용자의 인증 정보로 활용됩니다.


Request Header - 문제점

HTTP 프로토콜의 특징 중 하나인 무상태성(stateless)을 알고 계신가요 ? 무상태성은 각각의 Client의 요청이 서로 독립적이며, 이전 요청이나 응답에 대한 정보를 기억하지 않는 것 입니다.

즉, 각 요청은 서버에게 독립적으로 처리되고, 서버는 각 요청에 대한 처리를 완료한 후에 상태를 유지하지 않습니다.

이 말은 어떤걸 의미할까요 ?

상황을 가정하는게 저는 이해가 쉽더라구요.
아래 상황을 가정해보겠습니다.

  1. 어떤 글을 작성하기 위해 Request Header로 로그인을 했습니다.
  2. 글을 작성하고 바로 이후에 수정을 하려고 합니다.
    • 저라는 사용자를 서버가 기억하고 있을까요 ?
      무상태성의 특징을 가진 HTTP 프로토콜은 저를 기억하지 못합니다. 그렇기에 저는 또 다시 로그인을 해야하죠.

저라는 사용자를 서버가 기억하고 있으면 좋겠네요.
즉 내 상태가 유지되었으면 좋겠습니다 !

이러한 목적을 가진 것이 Cookie입니다👏


2. Cookie

브라우저 활용하기

사용자가 로그인하면
Server는 Client에게 고유한 식별자(세션 ID 등)를 담은 쿠키를 전송합니다.

이후 Client가 다시 서버에 요청을 보낼 때 해당 쿠키를 함께 전송하면, 서버는 그 쿠키를 기반으로 사용자를 식별하고 세션을 유지할 수 있습니다.

Cookie에 간단하게 사용자의 정보(ID,PW)를 저장한다.. 너무 편합니다.


그런데 Client가 쿠키를 관리한다라,,,
만약 아래와 같은 상황이 벌어진다면요 ?

  • 사용자가 자신의 등급을 VIP로 수정
  • 구매한 적도 없는 구매했다고 수정

이런 상황은 일어나면 안되겠죠 ?


또한 Client의 웹 브라우저는 Server보다 상대적으로 보안에 취약합니다. 즉, Cookie는 보안에 취약하다는 의미죠.

그런데 만약 쿠키에 ID, PW를 저장하면요 ?
사용자가 편한만큼 해커도 편하게 브라우저 Storage에서 사용자의 정보를 빼갈 수 있겠네요 !

그렇기 때문에 쿠키에는 중요한 정보를 저장하지 않는 것이 좋습니다.


그러면 중요한 정보는 어떡하죠 ?
자, 이제 Session으로 갑니다 🚗


3. Session

Cookie는 사용자의 정보를 클라이언트 측에서 관리하죠 ?

Session은 사용자의 정보를 서버 측에서 관리합니다.

동작방식입니다.

  1. 사용자가 로그인 요청을 보냅니다.

  2. 서버는 사용자의 인증 정보를 확인하고,
    검증이 완료되면 세션 ID를 생성합니다.

  3. 이 세션 ID를 클라이언트에게 전송하고
    동시에 서버 측에도 세션 정보를 저장합니다.

  4. 클라이언트는 세션 ID를 저장해두고,
    이후의 요청에서는 세션 ID를 서버에 전송하여 자신을 식별합니다.

  5. 서버는 세션 ID를 기반으로 클라이언트를 식별하고, 해당 세션에 저장된 정보를 사용하여 사용자의 상태를 유지합니다.

쉽게 말해서
Cookie 방식에서 Cookie 안에 사용자의 정보가 저장되어 있다면
Session 방식은 Cookie 안에 세션 ID가 저장되어 있습니다.

서버 측는 Cookie의 정보로 사용자를 식별하게 되는데,
만약 세션 ID가 있다면 서버 측에서는 이를 사용하여 사용자를 식별하고 해당 세션에 저장된 정보를 활용합니다.

Cookie에 사용자의 정보가 있으면,, 쿠키를 탈취당할 때 위험하겠죠 ?

그런데 만약 탈취한 Cookie에 사용자 정보는 없고 세션 ID가 있다면요 ? 그나마 덜 위험하지 않을까요 ?

그런데 저는 이런 생각도 들었어요. 세션 ID로 해커가 서버에 접근하면 되는거 아니야 ?

네 맞습니다 ! 세션 ID를 획득한 해커는 해당 세션에 저장된 사용자의 권한과 정보를 이용해 사용자인 척 접근할 수 있습니다. 아래 방식으로 세션의 보안을 더할 수 있겠네요.
HTTPS 사용, Secure 속성 사용,
HttpOnly 속성 사용, 세션 유효 시간 제한


요약해보겠습니다

쿠키 : 편의성 ↑ 보안↓
세션 : 편의성 ↓ 보안↑(쿠키보다 상대적으로 좋다.)

자. 그래도 문제점은 언제나 존재합니다.

Session - 문제점

만약 서버가 여러 개가 있다고 가정합시다.

클라이언트가 글을 작성하기 위해 로그인을 합니다.
이때, Server3과 인증을 해서 Session 값을 받았죠.

이제 글을 수정하기 위해 인증을 하기 위해
Session 값을 서버로 보냈는데
Load Balancer로 인해서
Server3이 아닌 Server1 또는 Server2가 요청을 받게 됩니다.

당연히 Server1,2 는 해당 세션 ID를 갖고 있지 않으므로 인증을 거부하게 된다.

즉, 클라이언트가 한 서버에서 발급받은 세션 ID를 다른 서버에게 보내면 해당 서버는 해당 세션에 대한 정보를 알지 못하여 인증 오류가 발생할 수 있다는 말이죠.


자 그렇다면 서버에 Session Storage 라는 것을 만들어보면 어떨까요 ?
세션을 한 곳에서 관리해보죠 !

이렇게 되면 문제는 해결되겠네요 !

서비스가 잘 되고 있어요 ! 그런데 점점 사용자가 많아지네요..?

이렇게 되면,, DB가 버틸 수 없습니다 😥

다른 방법도 알아보죠 🤔

만약 정보의 요청과 응답 안에 사용자의 정보가 아닌, 사용자의 상태를 담는다면 어떨까요 ?

이걸로만 인증과 인가를 처리한다면요 ?
그렇게 등장합니다. Token


4. Token

일반적으로 Token에는 사용자의 식별 정보(ex_사용자 아이디), 권한 정보, 그리고 토큰의 유효 기간 등이 포함될 수 있습니다.

이렇게 토큰에 필요한 정보를 담아 전송함으로써,
서버는 클라이언트의 요청을 검증하고 인가를 수행할 수 있습니다.

주로 JSON Web Token (JWT)과 같은 토큰을 사용하여 인증 및 인가를 수행하고,
이 방식은

  • 서버 측에 상태를 저장하지 않고
  • 클라이언트가 토큰을 사용하여 상태를 관리하는 무상태(Stateless) 아키텍처를 지향합니다.

JWT(Token)

JWT: JSON WEB TOKEN

사용자의 인증 및 권한 정보를
토큰에 담아 클라이언트에서 저장합니다.

각 요청에서 클라이언트는 이 토큰을 서버에 전송하고,
서버는 해당 토큰을 검증하여 사용자를 식별하고 사용자에게 부여된 권한을 확인합니다.

이를 통해 서버는 사용자의 로그인 상태와 권한을 클라이언트에서 관리할 필요 없이, 효율적으로 처리할 수 있습니다.

동작 과정을 살펴볼까요 ?

  1. 로그인 요청:
    사용자가 로그인을 시도하면, 서버는 사용자를 인증하고 JWT를 생성합니다.

  2. JWT 발급:
    서버는 JWT를 생성하고, 해당 JWT에 사용자의 식별 정보와 권한 등을 포함시켜 반환합니다.

  3. 클라이언트에게 전달:
    클라이언트는 받은 JWT를 안전한 곳(예: 웹 스토리지)에 저장합니다.

  4. 요청 시 사용:
    클라이언트가 서버에 요청을 보낼 때마다, 저장된 JWT를 요청 헤더에 포함시켜 전송합니다.

  5. 서버 검증:
    서버는 받은 JWT를 검증하여 유효한지 확인하고, 필요한 인증 및 인가를 수행합니다.


JWT 생성

일반적으로 JWT는 시큐리티 기술을 이용하여 생성됩니다. JWT의 핵심은 안전하고 변조가 어려운 토큰을 생성하는 것이기 때문에, 이를 위해 다양한 시큐리티 알고리즘이 사용됩니다.

JWT는 기본적으로는 Base64로 인코딩된 형태로,
암호화가 아닌 단순한 인코딩을 사용하므로 해독이 쉽습니다.
그렇기 때문에 JWT에는 민감한 정보를 담지 않는 것이 좋습니다.

또한, Security가 중요한 만큼,
Security가 외부로 노출되면 JWT 자체도 끝이 납니다.
Security는 서버 내부에서만 접근 가능한 환경에서 보관합니다.

JWT의 구성 요소는 따로 포스팅을 하나 더 하겠습니다 !

지금은 간단하게 설명하겠습니다

JWT 토큰 생성
1. 클라이언트가 요청을 서버로 전송
2. 서버는 요청을 받아 DB에서 사용자 정보를 가져온다.
3. 시큐리티를 사용자 정보를 바탕으로 JWT 토큰 생성
4. JWT 토큰을 클라이언트에게 전송한다.

JWT 토큰 사용
1. 클라언트는 JWT 토큰을 헤더에 포함시켜 서버로 전송한다.

  1. 서버는 전송받은 JWT 토큰을 검증한다
    • 검증이 성공하면 토큰에 포함된 정보를 활용해서
      사용자를 인증하고 권한을 부여
      이를 통해 클라이언트의 요청을 처리한다.

간단하게 !

  • Security를 사용해서 JWT를 만들어 내고,
  • Security를 이용해서 JWT의 인증 과정을 거친다.

AccessToken, RefreshToken 인증 방식

클라이언트는 처음 로그인할 때
AccessToken과 RefreshToken을 받습니다.

AccessToken은 만료기한이 30분으로, 30분이 지나게 되면 해당 토큰을 가지고 클라이언트는 인증을 받을 수 없게 되죠.

자 30분이 지났다고 가정해보겠습니다.
클라이언트는 서버에게 AccessToken을 보냅니다.

첫번째 시도
클라이언트의 AccessToken은 만료되었고,
인증이 거부되었습니다.

두번째 시도

이때 클라이언트는 다시 요청을 보내는데
AccessToken과 RefreshToken을 함께 보내게 됩니다.

서버는 RefreshToken을 DB에 조회하고,
유효하다면 클라이언트에게 재발급된 Access Token을 전송해준다.

이를 통해 AccessToken이 노출되거나 만료될 때마다 사용자는 계속해서 인증 및 권한을 갱신할 수 있습니다.

아래 사진으로 동작 과정을 한번 더 이해해보신다면 좋겠네요 : >

Session 문제점 극복

기존의 Session의 문제점은 확장성이였죠 ?

JWT는 각 서버가 요청 받은 토큰의 유효성 검사를 서버가 가진 시크릿 키로 진행을 합니다. 이때, 서버가 공통의 시크릿 키를 사용한다면 모든 서버가 사용자를 인증할 수 있겠죠 ? 즉, 확장성에 대한 문제가 해결되게 됩니다.

Token 핵심

토큰의 핵심을 읽어보시면 좋겠습니다.

  1. 토큰은 상태 관리를 통해 세션을 따로 관리하지 않아도 됩니다.

  2. AccessToken이나 RefreshToken의 발급 및 검증 시
    DB에 접근하지 않고도 속도를 향상시킬 수 있습니다.
    토큰의 검증을 서버의 메모리 내에서 처리할 수 있기 때문입니다.

  3. 토큰도 탈취당할 수 있기 때문에 토큰 관리가 중요하며, 이에 대한 보안 조치가 필요합니다.

  4. 토큰은 무결성을 보장합니다. HMAC 기법

    • 토큰을 발급한 이후는 토큰 정보를 수정할 수 없습니다. 누군가 토큰을 한 글자라도 변경하면 서버에서는 유효하지 않은 토큰이라고 판간하기 때문이죠.

아래 보안 조치를 나열해보겠습니다.
HTTPS 사용 토큰 만료 기간 설정 RefreshToken 안전하게 저장
시크릿 키 관리 JWT 내 중요 정보 제한 다중 인증 요소(MFA) 사용
토큰 리프레시 정책 설정 로그 및 감사 세션 관리 및 토큰 리프레시 정책

보안 조치에서 가장 접근하기 좋고 가성비 좋은 방법은 SSL/TLS1.3 즉, HTTPS를 적용하는 것입니다.


다른 채널을 통해 인증 → OAuth은
KakaoLogin을 포스팅할 때 다루겠습니다.

profile
백엔드 기록 공간😁

0개의 댓글