Notice
Recent Posts
Recent Comments
Link
«   2024/09   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30
Tags
more
Archives
Today
Total
관리 메뉴

꼬물꼬물 개발자

JWT 토큰 기반 사용자 인증 프로세스 본문

백엔드 개발

JWT 토큰 기반 사용자 인증 프로세스

한고운 2024. 1. 16. 12:57

 

<발표자 : 한고운>

1. 인증방식의 종류

 

1) Cookie 인증 방식

- Key-Value행식의 문자열 덩어리

- 서버를 통해 클라이언트의 브라우저에 설치되는 작은 기록 정보 파일

- 사용자마다의 브라우저에 정보를 저장하는 고유 정보 식별 방법 



1) 브라우저(클라이언트)가 서버에 요청(접속)을 보낸다. 
2) 서버는 클라이언트의 요청에 대한 응답 작성 시, 클라이언트 측에 저장하고 싶은 정보를 응답 헤더의 Set-Cookie에 담는다.
3) 이후 해당 클라이언트는 요청을 보낼 때마다, 매번 저장된 쿠키를 요청 헤더의 Cookie에 담아 보낸다. 
    서버는 쿠키에 담긴 정보를 바탕으로 해당 요청의 클라이언트가 누군지 식별한다.  

Cookie 구조 형태


 
Cookie 방식의 단점 

- 보안에 취약 : 요청 시 쿠키의 값을 그대로 보내기 때문에 유출 및 조작 당할 위험이 높음 
- 쿠키에는 용량 제한이 있어 많은 정보를 담을 수 없음 
- 웹 브라우저마다 쿠키에 대한 지원 형태가 다르기 때문에 브라우저간 공유 불가능
- 쿠키의 사이즈가 커질수록 네트워크 부하 심함 

 

2) Session 인증 방식

- 쿠키의 보안적 이슈 때문에 세션은 비밀번호 등 클라이언트의 민감한 인증 정보를 브라우저가 아닌 서버측에 저장(서버의 메모리, 로컬 파일, 데이터베이스 등)하고 관리함. 

- 즉, 민감한 정보는 클라이언트에 보내지말고 서버에서 모두 관리한다는 것 




1) 유저가 웹사이트에서 로그인하면 세션이 서버 메모리(혹은 데이터베이스) 상에 저장된다. 
     이때, 세션을 식별하기 위한 Session Id를 기준으로 정보를 저장
2) 서버에서는 Session Id가 저장된 쿠키를 브라우저에 저장한다.
3) 브라우저는 해당 사이트에 대한 모든 Request(요청)에 Session Id를 쿠키에 담아 전송한다. 
4) 서버는 클라이언트가 보낸 Session Id와 서버 메모리로 관리하고 있는 Session Id를 비교하여 인증을 수행한다. 
Session 형태

Session 방식의 단점

- 쿠키를 포함한 요청이 외부에 노출되더라도 세션 ID 자체는 유의미한 개인정보를 담고 있지 않다. 그러나 해커가 세션 ID 자체를 탈취하여 개인정보를 취득할수 있다는 위험이 존재함.
- 서버에서 세션 저장소를 사용하므로 요청이 많아지면 서버에 부하가 심해짐 

 

3) Token 인증 방식

- 토큰 기반 인증 시스템은 세션 인증 방식을 극복하기 위해 출현한 것

- 클라이언트가 서버에 접속을 하면 서버에서 해당 클라이언트에게 인증되었다는 의미로 '토큰'을 발급

- 토큰은 세션과는 달리 서버가 아닌 클라이언트에 저장되기 때문에 메모리나 스토리지 등을 통해 세션을 관리했던 서버의 부담을 덜어줌 

- 서버 기반 인증 시스템과는 달리 상태를 유지하지 않으므로 Stateless한 특징을 가짐 



1) 사용자가 아이디와 비밀번호로 로그인을 한다.
2) 서버 측에서 사용자(클라이언트)에게 유일한 토큰을 발급한다.
3) 클라이언트는 서버 측에서 전달받은 토큰을 쿠키나 스토리지에 저장해 두고, 서버에 요청을 할 때마다 해당 토큰을 HTTP 요청 헤더에 포함시켜 전달한다. 
4) 서버는 전달받은 토큰을 검증하고 요청에 응답한다. 
    토큰에는 요청한 사람의 정보가 담겨있기에 서버는 DB를 조회하지 않고 누가 요청했는지 알수 있다. 
Token 방식의 단점 

- 쿠키/세션과 다르게 토큰 자체의 데이터 길이가 길어, 인증 요청이 많아질수록 네트워크 부하가 심해질 수 있다. 
- Payload 자체는 암호화되지 않기 때문에 유저의 중요한 정보는 담을 수 없다. 
- 토큰을 탈취당하면 대처하기 어렵다. ( 사용 기간 제한 설정 필요) 

 

 

서버기반 인증 시스템  & 토큰기반 인증 시스템의 차이

구분 서버기반 인증시스템 토큰기반 인증시스템  
정의 - 세션 기반의 인증 시스템
- 서버측에서 사용자들의 정보를 기억하기 위해 세션을 유지하며, 이는 메모리, 디스크, 데이터베이스 등을 통해 관리한다. 
- 클라이언트로부터 요청을 받으면 클라이언트의 상태 정보를 저장하여 유지해야 함으로 Stateful(상태유지)한 구조를 가진다.
- 서버 기반 인증 시스템의 단점을 보완
- 인증받은 사용자에게 토큰을 발급해주고, 서버에 요청을 할 때 HTTP 헤더에 토큰을 함께 보내어 인증받은 사용자(유효성 검사) 인지 확인
- 사용자의 인증 정보를 서버에 저장하지 않고 클라이언트의 요청으로만 인가를 처리하므로 Stateless(무상태)한 구조를 가진다. 
 
장점 - 중요한 정보는 서버에 있기 때문에 쿠키 자체(세션ID)에는 유의미한 값을 가지고 있지 않다. - 토큰 기반은 Access Token을 발급해준 후 요청이 들어오면 검증만 해주면 되기 때문에 추가 저장소가 필요 없음
- 확장성이 뛰어남. 토큰 기반으로 하는 다른 인증 시스템에 접근이 가능하다. 
 
단점 - 해커가 훔친 쿠키를 이용해 HTTP 요청을 보내면 서버에서는 올바른 사용자가 보낸 요청인지 알 수 없음 
- 서버에 세션을 저장하므로 사용자가 증가함에 따라 과부하를 줄 수 있어 확장성이 용이하지 모한다. 
- 시스템 확장이 어렵다. 
- 이미 발급된 JWT를 돌이킬 수 없음 
- 서버기반 인증시스템을 사용하는 경우에는 해당 세션이 악의적으로 사용될 경우 지워버리면 되나, JWT는 한번 발급되면 유효기간이 완료될 때까지는 계속 사용이 가능다는 위험이 있음 
- JWT 길이가 길다. 인증이 필요한 요청이 많아질수록 서버의 자원 낭비 발생
 

 

용어 정의

- Stateful (상태유지) : 상태유지라 함은 클라이언트와 서버 관계에서 서버가 클라이언트의 상태를 보존함을 의미함. 클라이언트와 서버 간에 송수신을 하는데 있어 서버는 클라이언트가 제공한 값을 단계별로 계속 저장하여 정보를 기억함. 이러한 정보들은 일반적으로 브라우저의 쿠키(Cookie)에 저장되거나, 서버의 세션(Session) 메모리에 저장되어 상태를 유지함.   

- Stateless (무상태) : 무상태란 반대로 클라이언트와 서버 관계에서 서버가 클라이언트의 상태를 보존하지 않음을 의미함.  즉,  Stateless 구조에서는 클라이언트와 서버간의 통신에 필요한 모든 상태 정보들은 클라이언트에서 가지고 있다가 서버와 통신할 때 데이터를 실어 보내는 것이 무상태 구조이다. 

 

정리 )  쿠키- 세션 방식의 서버기반 인증시스템의 경우 세션을 서버에 저장해야 하므로 비효율적이며, 서버 확장 시 서버간에 세션을 공유하기 어려운 단점을 가지고 있음. 이러한 단점을 해결하기 위한 방법으로 토큰 기반의 사용자 인증시스템을 사용함 

 

<발표자 : 이환영>

2. JWT(Json Web Token) 개념

- JWT(Json Web Token)란 인증에 필요한 정보들을 암호화시킨 JSON토큰을 의미함 

- JWT기반 인증은 JWT토큰( Access Token)을 HTTP 헤더에 실어 서버가 클라이언트를 식별하는 방식

- JWT는 JSON 데이터를 Base64 URL-safe Encode를 통해 인코딩하여 직렬화한 것 

  * Base64 URL-safe Encode는 Base64 Encode에서 URL 에서 오류없이 사용하도록 '+'.'/'를 각각 '-','_'로 표현한 것

- 토큰 내부는 위변조 방지를 위해 개인키를 통한 전자서명도 들어 있음 

- 따라서 사용자가 JWT를 서버로 전송하면 서버는 서명을 검증하는 과정을 거쳐 검증이 완료되면 요청한 응답을 돌려줌

 

1) JWT 구조

- JWT는 .을 구분자로 나누어지는 세가지 문자열의 조합 

- . 을 기준으로  Header, Payload, Signature 순으로 정렬

- Header에는 JWT에서 사용할 타입과 해시 알고리즘의 종류가 담겨짐 

    alg :  서명 암호화 알고리즘

    typ : 토큰유형

 

- Payload에는 서버에서 첨부한 사용자 권한 정보와 데이터가 담겨짐 

  페이로드는 정해진 데이터 타입은 없지만 대표적으로 Registered claims, Public claims, Private claims 세가지로 나눠짐 

  Registered claims :  미리정의된 클레임 

    iss(issuer: 발행자)

    iat(issued At: 발행 시간)

    exp(expireation time: 만료 시간)

    sub(subject: 제목)

    jti(JWI ID)

  Public claims : 사용자가 정의할 수 있는 클레임. 공개용 정보 전달을 위해 사용.

  Private claims : 해당하는 당사자들 간에 정보를 공유하기 위해 만들어진 사용자 지정 클레임. 외부에 공개되도 상관없지만 해당 유저를 특정할 수 있는 정보들을 담는다. 

 

- Signature 구조는 (헤더+페이로드)와 서버가 갖고 있는 유일한 Key값이 합처져 헤더에서 정의한 알고리즘으로 암호화 됨

  헤더와 페이로드는 단순히 인코딩된 값이기 때문에 제 3자가 복호화 및 조작이 가능하지만, 시그니처는 서버 측에서 관리하는 비밀키이기 때문에 비밀키가 유출되지 않는 이상 복호화 할 수 없다. 즉, 시그니처는 토큰의 위변조 여부를 확인하는데 사용됨 

 

2) JWT 인증 과정

1) 사용자가 ID, PW를 입력하여 서버에 로그인 인증을 요청한다. 
2) 서버에서 클라이언트로부터 인증요청을 받으면, Header, Payload, Signature를 정의한다. 
    Header, Payload Signature를 각각 Base64로 한번 더 암호화하여 JWT를 생성하고 이를 쿠키에 담아 클라이언트에게 발급
3) 클라이언트는 서버로부터 받은 JWT를 로컬 스토리지에 저장한다. (쿠키 등 다른곳에 저장할 수 있음) 
    API를 서버에 요청할 때 Authorization header(승인 헤더)에 Access Token을 담아서 보낸다. 
4) 서버에서는 클라이언트가 Header에 담아서 보낸 JWT가 내 서버에서 발행한 토큰인지 일치 여부를 확인하여 일치한다면 인증을 통과시켜주고, 아니라면 통과시키지 않는다. 
    인증이 통과되면 페이로드에 들어있는 유저의 정보들을 select해서 클라이언트에 돌려준다. 
5) 클라이언트가 서버에 요청 시, 만일 액세스 토큰의 시간이 만료되면 클라이언트는 리프래시 토큰을 이용재서 재발급 요청
6) 서버로 부터 새로운 엑세스 토큰을 발급 받는다. 

 

 

<발표자 : 추원혁>

JWT 토큰의 암호화 그리고 무결성

JSON으로 담은 "헤더"와 "페이로드" 데이터를 Base64 암호화 기법으로 암호화 하고, SHA256이나 RSA 암호화 기법을 이용하여 "서명"부분을 단방향 암호화함으로써 그 무결성을 검증하게 됨.

 

이 포스트는 JWT를 통한 사용자 인증 프로세스에 초점을 맞추고 있음.

사용자 인증과 그 무결성 검증은 웹 애플리케이션의 보안에서 필수적인 부분임.


JWT 인증 프로세스의 구현

JWT 인증 프로세스를 구현하는 방법을 설명해 보겠음.

const jwt = require('jsonwebtoken');
const secretKey = 'your_secret_key';

const sql = `SELECT * FROM users WHERE username = '${uname}'`;

// .. MySQL Query Process ...
let user = await db.query(sql);

if (!user) {
	// 사용자 로그인 실패. 사유: 존재하는 username 없음
	res.json({"error":true, "msg": "해당하는 유저가 없음."});
} else {
	// 로그인 프로세스 1차 성공. username 존재
    const hashedPassword = md5(password);
    const rowPassword = user.password;
    
    if (hashedPassword != rowPassword) {
    	// 사용자 로그인 실패. 사유: username은 존재하지만 비밀번호 불일치
		res.json({"error":true, "msg": "해당하는 유저가 없음."});
    } else {
    	// 로그인 최종 성공. JWT에 정보를 저장한다
		const userRow = {
        	id: user.id,
            username: user.username,
            permission: user.permission
        };
		const token = jwt.sign(userRow, secretKey, { expiresIn: '1h' });
        
        // Return
        res.json({"error":false, "msg": "로그인 성공함.", "token": token});
    }
}
  1. 사용자가 로그인을 시도하면, 서버는 사용자 정보를 검증함.
  2. 정보가 정확하면 서버에서 JWT를 생성하고 이를 사용자에게 전송함.
  3. 사용자는 이후의 요청에 이 JWT를 포함시켜 보냄.
    예를 들면 헤더에 Authorization: Bearer ${token} 을 포함한채로 전송하게 됨.
  4. 서버는 요청을 받을 때마다 미들웨어를 통해 JWT를 검증하여 사용자가 유효한지 확인함.
    JWT 생성시에는 jwt.sign() 함수를 사용하였지만,
    복호화하여 데이터의 무결성을 검사할시에는 jwt.verify() 를 이용하여 검사함.

장단점 정리

JWT를 사용하며 오는 장점

  • JWT의 장점은 상태를 서버가 아닌 클라이언트에 저장함.
    따라서 세션이 저장소나 메모리를 차지하지 않아 대규모 접속 발생시에도 퍼포먼스에 문제가 없음
  • 복호화가 가능한 데이터와 단방향암호화 서명을 가지고 있어 데이터 무결성 검증에 유리함,
    손쉽게 데이터를 복호화해서 꺼내 쓸 수 있음

JWT를 사용하며 오는 단점

  • 유저 (클라이언트) 측에 토큰이 직접 노출(보관) 되기때문에,
    위 코드블럭에서 작성한 secretKey와 같은 부분이 유출될 경우 권한 탈취 및 해킹의 위험이 있음.
  • 유저를 통해 인증된 토큰이 탈취되면, 탈취자는 토큰이 만료될 때까지 사용자로서 시스템에 접근할 수 있음. (XSS 공격)
  • 일단 발행된 토큰은 서버에서 만료를 강제할 수 없어 (iat과 expiresat이 지정되어있음), 블랙리스팅 시스템을 따로 구현해야 함.

JWT가 사용되는 대표적인 사례

모든 사례를 일일히 정리할 수는 없지만, 가장 대표적으로 오는 사례들을 간단히 정리해본다.

  • 단일 페이지 애플리케이션(SPA): 클라이언트 사이드에서 사용자 세션을 관리하는 데 사용됨.
  • 모바일 애플리케이션: 서버와 모바일 앱 간의 안전한 통신을 위해 사용됨.
  • 마이크로서비스 아키텍처: 서비스 간의 사용자 인증 정보 전달에 사용됨.
  • 사용자 인증 및 권한 부여: 사용자의 인증 정보와 권한을 포함하여 API 서버에 전달하는 데 사용됨.
  • 소셜 로그인 구현: 소셜 미디어 계정을 통한 로그인 시 사용자 정보 교환에 사용됨.

 

마치며

기존에 JWT는 내가 주로 사용해오던 인증 토큰 시스템이다.

이번 포스트를 통해 JWT를 사용하면서 발생할 수 있는 약점과 그 외 단점들을 알게되어 더욱 신중하게 이를 피해 코딩할 수 있을것 같다.

 

 

 

 

참고 

https://inpa.tistory.com/entry/WEB-%F0%9F%93%9A-JWTjson-web-token-%EB%9E%80-%F0%9F%92%AF-%EC%A0%95%EB%A6%AC

 

🌐 JWT 토큰 인증 이란? (쿠키 vs 세션 vs 토큰)

Cookie / Session / Token 인증 방식 종류 보통 서버가 클라이언트 인증을 확인하는 방식은 대표적으로 쿠키, 세션, 토큰 3가지 방식이 있다. JWT를 배우기 앞서 우선 쿠키와 세션의 통신 방식을 복습해

inpa.tistory.com

https://hoime.tistory.com/94

 

토큰 기반의 로그인 인증 방법 이해하기 (JWT)

프로젝트를 진행하며 로그인 / 회원가입 부분을 담당하여 개발하게 되었습니다. 로그인을 구현하기 위해 공부한 내용을 정리하고 공유하고자 하는 목적으로 글을 작성합니다. 우선 사용자 로그

hoime.tistory.com

https://evansdev.tistory.com/entry/JWT-%ED%86%A0%ED%81%B0-%EA%B8%B0%EB%B0%98-%EC%82%AC%EC%9A%A9%EC%9E%90-%EC%9D%B8%EC%A6%9D-%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4-%EA%B7%B8%EB%A6%AC%EA%B3%A0-Nodejs%EC%97%90%EC%84%9C%EC%9D%98-%EC%98%88%EC%A0%9C

 

JWT 토큰 기반 사용자 인증 프로세스 그리고 Node.js에서의 예제

시작하며 JWT 토큰이란? JWT 토큰은 Json Web Token의 약자임. 웹 인증 토큰이나 세션, REST API에서 많이 활용되는 토큰의 방식임. 사용자 인증에 필요한 정보를 암호화된 형태로 클라이언트에 저장함. J

evansdev.tistory.com

 

'백엔드 개발' 카테고리의 다른 글

레이아웃 구성  (0) 2024.01.18
주요 C/R/U/D ORM DB프로그래밍  (0) 2023.12.29
ORM Framework  (0) 2023.12.28
EJS 주요 문법 정리  (1) 2023.12.22
라우팅 구현 - 회원가입, 로그인  (0) 2023.12.17