🔗 [Knowledge/🌐 Web 지식] - 인증 / 인가
* 위 글에 이어 작성하는 글입니다.
인증과 인가에 대해 공부하였다.
이전 글에 이어 , '인증방식'에는 무엇이 있는지, '인증 상태를 어떻게 유지하는지'에 대해 공부해 보자
그전에 앞서, HTTP에 대한 개념부터 알아야 된다.
HTTP란?
위 그림처럼 클라이언트와 서버는 'HTTP라고 하는 통신 규약'에 의해 요청과 응답을 주고받는다.
HTTP의 규약에 대해 간략하게 정리해 보자.
- 주요 메서드:
- GET: 정보 요청
- POST: 정보 전송
- PUT: 정보 업데이트
- DELETE: 정보 삭제 등
- 상태 코드:
- 200: 성공
- 404: 페이지 찾을 수 없음
- 500: 서버 오류 등
- 헤더 정보:
- 요청/응답에 대한 추가 정보 제공 (예: 콘텐츠 타입, 쿠키 등)
이처럼 다양한 규약에 의해 요청과 응답을 주고받는다.
여기서 중요한 건 바로 Stateless(무상태성)이라는 HTTP의 특징이다.
- Stateless(무상태성)
HTTP로 통신되는 클라이언트의 요청이 서버에 독립적으로 처리되며, 서버가 클라이언트에 대한 정보를 유지하거나 기억하지 않는다는 것이다.
이러한 특징으로 인하여, 인증을 하더라도 Statelss 함으로 인하여 인증상태가 유지되지 않는 이슈가 발생한다.
즉, 이전 글에서 말했던 서비스를 이용할 때마다 인증을 해야 되는 불편함이 있을 것이다.
그렇다면 우리는 이 인증상태를 유지시켜야, 사용자의 불편함을 해소시킬 수 있다.
🤔 어떤 방식으로 인증 상태를 유지할 수 있을까?
세션(Session)
- 서버가 클라이언트의 상태 정보를 유지하기 위해 사용하는 메커니즘으로,
고유한 세션 ID를 통해 각 사용자를 식별하고 관련 데이터를 일정 시간 동안 서버에 저장하는 방식
이전 글에, 편의점에서의 상황을 예시로 들어보자.
처음에 주민등록증을 통해 신분 확인 이후(인증) 술을 샀다. 이후, 다시 술을 사러 왔을 때 점원은 그 고객의 민증을 기억(인증 상태 유지)하고 있기 때문에 다시 인증을 하지 않아도 된다. 세션방식과 유사한 메커니즘의 예시다.
-세션의 동작 방식

⬇️⬇️
- 클라이언트가 서버에 로그인을 요청. 사용자 ID "hyunsoo"와 비밀번호 "soo123!"을 전송.
- 서버는 데이터베이스에서 해당 사용자 정보를 확인.
- 데이터베이스에서 ID와 비밀번호가 일치하는지 확인.
- 인증이 성공하면, 서버는 세션 ID "x9 fK2 P7 q"를 생성.
- 서버는 생성된 세션 ID를 자체 세션 저장소에 저장하고, 해당 세션 ID와 사용자 "hyunsoo"를 연결.
- 서버는 클라이언트에게 세션 ID "x9fK2P7q"를 응답으로 전송.
- 클라이언트는 받은 세션 ID를 저장합니다(Key-Value 형태로 SessionId: x9 fK2 P7 q).
- 이후 클라이언트의 요청에는 항상 이 세션 ID를 포함.
- 서버는 이전처럼 데이터베이스 조회 없이 요청에 포함된 세션 ID를 확인하여 사용자를 식별하고 인증된 상태를 유지.
- 이로써 사용자는 Session 방식을 통해 , 매번 로그인할 필요 없이 효율적으로 사용자 인증 상태를 유지할 수 있고,
이미 인증이 완료된 사용자라는 것을 기억하여, 그 뒤 인가 절차를 진행한다.
토큰(JWT)
-사용자 인증에 대한 정보가 담긴 징표
위와 같이 편의점 예시를 들어보자.
처음에 주민등록증을 통해 신분 확인 이후(인증) 술을 샀다. 그 이후, 점원은 고객에게'특별한 동전'을 준다.
🔑특별한 동전
-이 동전에는 고객의 이름, 주민등록번호, 발급일 등 고객의 정보와 유효기간 등의 정보가 암호화되어 있다.
또한, 편의점 브랜드만의 특별한 서명이 포함되어 있어, 해당 편의점 브랜드에서 발급된 것인지 확인할 수 있다.
이후 점원은 고객이 다시 술을 사러 왔을 때, 다시 인증을 하지 않고 이 동전을 보여주면, 동전의 정보와 유효기간을 확인한다.
여기서의 동전이 바로 JWT이다.
- JWT (Json Web Token)
-Json형식으로 Web에서 사용되는 Token
*JSON은 데이터를 키-값 쌍으로 표현하는 경량화된 데이터 교환 형식
실제 JWT가 어떻게 생겼는지.
eyJhbGciOiJIUzI*****.(Header)
eyJ1 c2 VySWQiOiJuYXZlc*****ZUJBRkdIYUpXWWdVX0 p2 c0 EySWkxaUw5 NUJ6 bkpXZWI1 NzlGajF5 a1 lRIiwicm9 sZSI6 IlJPTE****VNFUiIsImlhdCI6 MTcyNDIyMzA5 MywiZXhwIjoxNzI0*******.(Payload)
u7 CcAuYU8 nxnDVWEoJD8-BHkWtz5 rgPDl_*********(Signature)
우리 프로젝트에서 내가 네이버 소셜로그인을 했을 때 생성된 실제 JWT토큰의 모습이다. (보안을 위해 **처리)
보이는 것처럼 Header, Payload, Signature 이렇게 총 3개의 구조로 구성되어 있다.
Header
{
"alg" : "HS256",
"Type" : "JWT"
}
- 서명에 사용된 암호화 알고리즘과, 토큰의 유형에 대한 정보를 포함.
-Base64 Url로 인코딩.
Paload
{
"username": "naver JeBAFGHaJWYgU_Jvs******",
"role": "ROLE_USER",
"iat": 1724223093,
"exp": 1724*******
}
-사용자 정보 혹은, 토큰 정보 등을 나타내는 클레임(정보)을 포함.
- 아이디(username), 발행시간(iat), 만료시간(exp) 등 기재 가능.
-Base64 Url로 인코딩.
Signature
HMACSHA256(
base64 Url Encode(header) + "." +
base64 Url Encode(payload),
"secret key"
)
-Header와 Payload를 합친 후, 비밀 키를 사용하여 생성된 서명.
-HMAC-SHA256 알고리즘을 사용하여 생성.
-토큰의 무결성을 검증하고 변조 여부를 확인하는 데 사용.
-서버만이 알고 있는 비밀 키(secret key)를 사용하여 생성되므로, 토큰의 신뢰성을 보장.
-Base64 Url로 인코딩.
- JWT의 동작 방식

⬇️⬇️

- 클라이언트가 서버에 로그인을 요청. 사용자 ID "hyunsoo"와 비밀번호 "soo123!"을 전송.
- 서버는 데이터베이스에서 해당 사용자 정보를 확인
- 데이터베이스에서 ID와 비밀번호가 일치하는지 확인.
- 인증이 성공하면, 서버는 JWT "eyJhb.eyJ1c2 Vy.u7 CcAuY"를 생성.
- 서버는 생성된 JWT를 클라이언트에게 응답으로 전송.
- 클라이언트는 받은 JWT를 저장(Key-Value 형태로 token: "eyJhb.eyJ1c2 Vy.u7 CcAuY").
- 클라이언트는 이후 요청 시 저장된 JWT를 헤더에 포함하여 서버로 전송.
- 서버는 받은 JWT의 유효성을 검증. JWT의 서명을 확인하고 만료 여부를 체크.
- JWT가 유효하면, 서버는 요청을 처리하고 응답을 클라이언트에게 전송.
이로써 사용자는 JWT 방식을 통해, 매번 로그인할 필요 없이 효율적으로 사용자 인증 상태를 유지할 수 있다. 서버는 토큰의 서명을 확인하여 이미 인증이 완료된 사용자라는 것을 검증하고, 토큰에 포함된 정보를 바탕으로 인가 절차를 진행한다.
Session VS JWT
그렇다면 세션과 JWT 둘의 차이점은 무엇일까? 하나의 공통된 키워드를 통해 차이점을 알면 각자의 장단점을 더 알기 쉬울 것이다.
상태 관리(저장 위치 및 확장성)라는 키워드를 통해 알아보자.
상태 관리
-세션(Session) (서버에 저장)
- 세션 방식을 사용하는 웹사이트의 사용자가 늘어 서버를 3개로 늘림.
- 클라이언트는 로그인 요청을 보냈고, 로드 밸런서를 통해 요청이 처리.
- 서버 중 하나가 요청을 처리하고 세션 ID(x9 fK2 P7 q)를 생성.
- 세션 정보(SessionId: x9 fK2 P7 q, User: hyunsoo)가 해당 서버에 저장.
- 클라이언트가 동일한 세션 ID(x9 fK2 P7 q)로 후속 요청을 보냄.
- 로드 밸런서가 요청을 다른 서버로 라우팅 한다.
- 새 서버에는 해당 세션 정보가 없어 인증에 실패한다.
- 세션 정보가 특정 서버에만 저장되어 있어 다른 서버로 요청이 갈 경우 인증 실패가 발생한다.
*로드 밸런서 : 네트워크 트래픽을 여러 서버에 효율적으로 분산하는 장치 ( easy - 교통정리 시스템)
라우팅 : 네트워크에서 데이터의 경로를 결정하고 전달하는 과정 ( easy - 내비게이션)
이처럼 다른 서버에 세션 정보가 없는 경우 인증에 실패하는 단점이 생긴다.
이는 마치 편의점에 갔을 때 나의 정보를 기억했던 점원(인증 상태 유지)이 아니고 , 다른 점원이 있다면 나는 인증에 실패하는 것이다.
그렇다면 이 문제점에 가능한 해결책은 무엇이 있을까?
여러 해결책이 존재하지만, Sticky Session이라는 해결책을 알아보자.
Sticky Session
-클라이언트의 모든 요청을 항상 같은 서버로 보내는 방식
이 방식은 사용자의 세션 정보를 특정 서버에 유지하면서, 해당 사용자의 모든 후속 요청이 동일한 서버로 전달되도록 한다.
이는 마치 편의점에 가면 항상 나의 정보를 기억하는 점원에게만 응대를 받는 것과 유사하다.
이를 통해 세션 데이터의 일관성을 유지하고, 다중 서버 환경에서 발생할 수 있는 세션 관련 문제를 해결할 수 있다.
하지만, 이렇게 같은 서버로만 요청을 전달하면 몇 가지 문제가 발생할 수 있다.
- 특정 서버에 사용자가 집중되면 과부하가 발생할 수 있다
- 해당 서버에 장애가 생기면 연결된 모든 사용자의 서비스가 중단될 수 있다.
- 또한 새로운 서버를 추가하거나 제거할 때 세션 관리가 복잡해질 수 있다.
이러한 한계로 인해 스티키 세션은 완벽한 해결책이 아니며, 이에 대한 대안으로 JWT(JSON Web Token)가 등장하게 되었다
-토큰(JWT) (클라이언트 측에 저장)


- 사용자가 늘어나 서버를 3개로 확장함.
- 클라이언트가 로그인 요청을 보내고, 로드 밸런서를 통해 요청이 처리됨.
- 서버 중 하나가 요청을 처리하고 JWT 토큰(eyJhb.eyJ1c2 Vy.u7 CcAuY)을 생성.
- 토큰에 사용자 정보가 포함되어 있어 서버에 별도 저장이 불필요함.
- 클라이언트가 동일한 JWT 토큰(eyJhb.eyJ1c2 Vy.u7 CcAuY)으로 후속 요청을 보냄.
- 로드 밸런서가 요청을 다른 서버로 라우팅함.
- 새 서버가 JWT 토큰을 검증하고 사용자 정보를 추출하여 인증에 성공함.
- JWT는 stateless 하여 어느 서버에서도 동일하게 처리 가능함.
- 서버 간 세션 공유 없이도 인증 성공이 가능하여 확장성이 향상됨.
이처럼 JWT를 사용하면 서버 확장 시에도 인증 정보를 쉽게 공유할 수 있어 확장성이 개선된다.
이렇게 두 가지의 인증 방식을 다뤄 보았는데 인증에 항상 붙어오는 키워드가 있다. 바로 '보안'이다.
아무리 깔끔한 인증방식이라도 보안이 철저하지 않다면, 아무 소용이 없다.
상태관리의 키워드로만 보면 세션 방식이 JWT보다 나은 점이 하나도 없는 것처럼 느껴진다.
하지만 보안이란 키워드를 접목시켜 보면 다를 수도 있다. '보안'은 좀 더 중요한 부분이므로 다음번에 따로 알아보고 공부해 봐야겠다!
또한, 로그인을 할 때 요즘은 거의 '소셜 로그인'을 통해 한다.
소셜로그인을 구현하기 이전에 OAuth 2.0이라는 키워드가 있는데 대해서도 그 키워드에 대해서도 따로 다뤄봐야겠다.
To Do List
- 인증에 필요한 보안
- 소셜 로그인(OAuth 2.0)
🙇♂️결론
내가 손쉽게 하던 로그인이 이처럼 많은 단계를 통해 수행되는지 몰랐다.
그래도 기본 중의 기본인 인증 / 인가 방식에 대하여 블로그를 하루동안 정리하면서 많이 깨달았다.
확실히 강의만 그냥 많이 보는 것보다 직접 정리하면서 공부하는 것이 엄청 나한텐 도움이 되는 거 같다.
비록 이미지도 직접 만들고, 내용도 자세히 적는 과정에서 시간이 꽤나 걸렸지만, 팀원들에게 제대로 공유하고 싶은 마음이 컸기에
전혀 시간이 아깝지 않았다!
끝으로, 이 영상을 들으면서 자료 정리도 참고하고 정말 많은 도움이 됐다!
샤라웃 투 후추..(삼겹살에 후추 뿌려 먹고 싶다)
'Knowledge > 🌐 Web 지식' 카테고리의 다른 글
| OAuth란? (0) | 2024.09.07 |
|---|---|
| 테스트 코드 (Test Code)란? (2) | 2024.09.04 |
| RESTful API란? (2) | 2024.09.03 |
| API란 ? (0) | 2024.08.29 |
| 인증 / 인가 (2) | 2024.08.21 |