티스토리 뷰

🪙  Token

세션 인증 방식을 보완한 토큰 인증 방식

1. Hashing

가장 많이 쓰이는 암호화 방식 중 하나
📌 다른 암호화 방식들은 복호화가 가능하지만, 해싱은 암호화만 가능하다.

해시 함수(Hash Function)을 사용하여 암호화를 진행한다.

  • 특징
    • 항상 같은 길이의 문자열을 리턴
    • 서로 다른 문자열에 동일한 해시 함수를 사용하면 반드시 다른 결과값이 나옴
    • 동일한 문자열에 동일한 해시 함수를 사용하면 항상 같은 결과값이 나옴

🌈 레인보우 테이블과 🧂 솔트(Salt)

🌈 레인보우 테이블

항상 같은 결과값이 나온다는 특성을 이용해 해시 함수를 거치기 이전의 값을 기록 해놓은 표

레인보우 테이블에 기록된 값의 경우, 유출이 되었을 때 해싱을 했더라도 해싱 이전의 값을 알아낼 수 있다.

보안상 위협이 될 수 있음

이 때 솔트를 활용해 해결할 수 있다.

🧂 솔트 (Salt)

소금이라는 뜻 그대로 소금을 치듯 해싱 이전의 값에 임의의 값을 더해 데이터가 유출되더라도 해싱 이전의 값을 알아내기 더욱 어렵게 만드는 방법
비밀번호 + 솔트  해시 함수(SHA1) 리턴 값
‘password’ + ‘salt’ ‘C88E9C67041A74E0357BEFDFF93F87DDE0904214’
‘Password’ + ‘salt’ ‘38A8FDE622C0CF723934BA7138A72BEACCFC69D4’
‘kimcoding’ + ‘salt’ ‘8607976121653D418DDA5F6379EB0324CA8618E6’
  • 솔트를 사용하게 되면 해싱 값이 유출 되더라도, 솔트가 함께 유출된 것이 아니라면 암호화 이전의 값을 알아내는 것은 불가능에 가깝다.

🔐 해싱의 목적

동일한 값의 데이터를 사용하고 있는지 여부만 확인하는 것이 목적
  • 해싱은 민감한 데이터를 다뤄야하는 상황에서 데이터 유출의 위험성은 줄이면서 데이터의 유효성을 검증하기 위해 사용된다.
더보기

🎈 사이트 관리자는 사용자의 비밀번호를 알고 있어야 할까?

Nope!

알고 있다면 이를 악용할 가능성이 있어 심각한 문제가 생길 수 있다.

때문에 보통 비밀번호를 데이터베이스에 저장할 때, 복호화가 불가능하도록 해싱하여 저장한다. → 사이트 관리자도 정확한 비밀번호를 알 수 없음

그렇다면 서버는 비밀번호를 모르는 상태에서 어떻게 로그인 요청을 할까?

  • 해싱한 값끼리 비교해서 일치하는지 확인하기

동일한 문자열에 동일한 해시 함수를 사용하면 같은 결과값이 나오기때문에 이를 이용해 같은 비밀번호인지 확인할 수 있다.


2. Token

사용자의 정보를 암호화하여 토큰의 형태로 클라이언트에 저장하는 토큰 인증 방식
  • 최근 웹 애플리케이션에서 많이 사용 되는 인증 방식 중 하나이다.

➰ 웹 보안에서 토큰이란?

인증과 권한 정보를 담고 있는 암호화된 문자열

 

🪙 토큰 인증 방식의 등장 배경

세션 기반 인증이 가지고 있던 한계를 극복하기 위해 등장
  • 세션 기반 인증
    • 서버에서 유저의 상태를 관리 → 서버의 부담이 너무 큼

서버의 부담을 줄이기 위해 클라이언트에 사용자의 인증 상태를 저장하는 방법을 생각해냈다.

➡︎ 토큰 기반 인증

  • 토큰 기반 인증
    • 유저의 인증 상태를 클라이언트에 저장 → 메모리 부족 문제를 줄임

🪙 토큰 인증 방식의 흐름

  1. 사용자가 인증 정보를 담아 서버에 로그인 요청을 보냄
  2. 서버는 데이터베이스에 저장된 사용자의 인증 정보를 확인
  3. 인증에 성공했다면 해당 사용자의 인증 및 권한 정보를 서버의 비밀 키와 함께 토큰으로 암호화
  4. 생성된 토큰을 클라이언트로 전달
    • HTTP 상에서 인증 토큰을 보내기 위해 사용하는 헤더인 Authorization 헤더를 사용하거나
    • 쿠키로 전달하는 등의 방법을 사용
  5. 클라이언트는 전달받은 토큰을 저장
    • 저장하는 위치는 Local Storage, Session Storage, Cookie 등 다양함
  6. 클라이언트가 서버로 리소스를 요청할 때 토큰을 함께 전달
    • 토큰을 보낼 때에도 Authorization 헤더를 사용하거나 쿠키로 전달
  7. 서버는 전달받은 토큰을 서버의 비밀 키를 통해 검증한다.
    • 토큰이 위조 되었는지
    • 토큰의 유효 기간이 지나지 않았는지
    등을 확인할 수 있음
  8. 토큰이 유효하다면 클라이언트의 요청에 대한 응답 데이터를 전송한다.

🪙 토큰 인증 방식의 장점

  • 무상태성
    • 서버가 유저의 인증 상태를 관리하지 않는다.
    • 서버는 비밀 키를 통해 클라이언트에서 보낸 토큰의 유효성만 검증하면 됨
    • → 무상태적인 아키텍처를 구축할 수 있다.
  • 확장성
    • 다수의 서버가 공통된 세션 데이터를 가질 필요가 없다.
    • → 서버를 확장하기 더 용이하다.
  • 어디서나 토큰 생성 가능
    • 토큰의 생성과 검증이 하나의 서버에서 이루어지지 않아도 된다.이를 활용해 여러 서비스 간의 공통된 인증 서버를 구현할 수 있음
    • → 토큰 생성만을 담당하는 서버를 구축할 수 있다.
  • 권한 부여에 용이
    • 인증 상태, 접근 권한 등 다양한 정보를 담을 수 있다.이를 활용해 어드민 권한 부여 및 정보에 접근할 수 있는 범위도 설정할 수 있음
    • → 사용자 권한 부여에 용이하다.

🪙 JWT (JSON Web Token)

데이터 전송에 사용하는 토큰 기반 인증 기술

JSON 형식으로 저장한 정보(Payload)를 암호화(서명)하여 전송한다.

  • 클라이언트가 서버에 요청을 보낼때
    • 인증정보를 암호화된 JWT 토큰으로 제공
  • 서버는 이 토큰을 검증하여 인증정보를 확인

📍 JWT 구성

1. Header

HTTP의 헤더처럼 해당 토큰 자체를 설명하는 데이터가 담겨 있다.

토큰의 종류, 시그니처를 만들때 사용할 알고리즘을 JSON 형태로 작성

{
    "alg": "HS256",
    "typ": "JWT" 
}

이 JSON 객체를 base64 방식으로 인코딩하면 JWT의 첫 번째 부분인 Header가 완성된다.

더보기

base64 방식

원한다면 얼마든지 디코딩할 수 있는 인코딩 방식

비밀번호와 같이 노출되면 안되는 민감한 정보를 담지 않도록 해야함

 

 

2. Payload

HTTP의 페이로드와 마찬가지로 전달하려는 내용물을 담고 있는 부분

어떤 정보에 접근 가능한지에 대한 권한, 유저의 이름과 같은 개인정보, 토큰의 발급 시간 및 만료 시간 등의 정보들을 JSON 형태로 담는다.

{
	"sub": "someInformation", 
    "name": "phillip", 
    "iat": 151623391 
}

이 JSON 객체를 base64로 인코딩하면 JWT의 Payload가 완성

 

 

3. Signature

토큰의 무결성을 확인할 수 있는 부분

Header와 Payload가 완성되면, Signature가 이를 서버의 비밀 키(암호화에 추가할 salt)와 Header에서 지정한 알고리즘을 사용하여 해싱한다.

// HMAC SHA256 알고리즘을 사용한 경우 생성된 Signature
HMACSHA256(base64UrlEncode(header) + '.' + base64UrlEncode(payload), secret);

서버는 Signature를 검증하는 단계에서 올바르지 않은 토큰임을 구분한다.

-> 토큰을 발급할 때 사용한 Secret을 정확하게 알고 있지 않다면 유효한 Signature를 만들어 낼 수 없기 때문

 

 

토큰 인증 방식의 한계

토큰 자체가 탈취된다면 토큰 인증 방식의 한계가 드러난다.

📍 무상태성

토큰 기반 방식의 장점인 무상태성은 때로는 단점으로 작용을 한다.

서버가 인증 상태를 관리하고 있지 않기 때문에

제 3자가 토큰을 탈취하는 경우 서버가 해당 토큰을 강제로 만료시킬 수 없다.

➡︎ 토큰이 만료될 때까지 사용자로 가장해 계속해서 요청을 보낼 수 있음

 

📍 유효 기간

토큰이 탈취되는 상황을 대비해 유효 기간을 짧게 설정하면

사용자는 토큰이 만료될 때마다 다시 로그인을 진행해야한다.

➡︎ 좋지 않은 사용자 경험을 제공

여기서 유효 기간을 길게 설정하면

토큰이 탈취될 경우 더 치명적으로 작용할 수 있다.

 

📍 토큰의 크기

토큰에 여러 정보를 담을 수 있는 만큼, 많은 데이터를 담으면

  • 그만큼 암호화하는 과정이 길어짐
  • 토큰의 크기도 커짐

➡︎ 네트워크 비용 문제가 생길 수 있음

 

 

액세스 토큰(Access Token)과 리프레시 토큰(Refresh Token)

토큰 인증의 한계를 극복하기 위한 방법

토큰 인증의 한계를 극복하기 위한 대표적인 구현 방법은 액세스 토큰과 리프레시 토큰을 함께 사용하는 것

  • Access Token : 서버에 접근하기 위한 토큰
    • 토큰과 비슷한 역할을 하며 보안을 위해 보통 24시간 정도의 짧은 유효기간이 설정되어 있다.

 

  • Refresh Token : 액세스 토큰이 만료되었을 때 새로운 액세스 토큰을 발급받기 위해 사용되는 토큰
    • 액세스 토큰보다 긴 유효 기간을 설정한다.

 

이 두 토큰을 사용하면 액세스 토큰이 만료 되더라도 리프레시 토큰의 유효기간이 남아있다면 사용자가 다시 로그인을 하지 않아도 지속해서 인증 상태를 유지할 수 있다.

 

하지만 리프레시 토큰의 도입이 모든 문제를 해결해 주지 않는다.

리프레시 토큰은 긴 유효 기간을 가지기 때문에 해당 토큰마저 탈취된다면 긴 유효 기간동안 악의적인 유저가 계속해서 액세스 토큰을 생성하고 사용자의 정보를 해킹할 수 있다.

→ 이를 대비하기 위해 리프레시 토큰을 세션처럼 서버에 저장하고 이에 대한 상태를 관리한다.

 

728x90

'코딩 > 코드스테이츠' 카테고리의 다른 글

[자료구조] - Stack , Queue  (0) 2023.03.15
[인증 / 보안] - OAuth  (0) 2023.03.09
[인증 / 보안] - Cookie/Session  (0) 2023.03.07
[네트워크] - TCP/IP  (0) 2023.03.06
[사용자 친화 웹] - 접근성  (0) 2023.03.02