Hashing
암호화 방식 중 하나인 해싱
복호화가 가능한 다른 암호화 방식들과 달리, 해싱은 암호화만 가능
해싱은 해시 함수(Hash Function)를 사용하여 암호화를 진행
해시 함수의 특징
- 항상 같은 길이의 문자열을 리턴
- 서로 다른 문자열에 동일한 해시 함수를 사용하면 반드시 다른 결과값이 나온다
- 동일한 문자열에 동일한 해시 함수를 사용하면 항상 같은 결과값이 나온다
레인보우 테이블과 솔트(Salt)
해시 함수의 특징 중 하나 → '항상 같은 결과값이 나온다'
이 말의 의미는 해시 함수를 거치기 이전의 값을 알아낼 수 있다.
레인보우 테이블 : 해시 함수를 거치기 이전의 값을 알아낼 수 있도록 기록해 놓은 표
→ 기록된 값의 경우, 유출이 되었을 때 해싱을 했더라도 해싱 이전의 값을 알아낼 수 있으므로 보안상 위험 큼
Salt(솔트) : 해싱 이전 값에 임의의 값을 더해 데이터가 유출되더라도 해싱 이전의 값을 알아내기 더욱 어렵게 만드는 방법
→ 해싱 값이 유출되더라도, 솔트가 함께 유출된 것이 아니라면 암호화 이전의 값을 알아내는 것은 불가능
해싱의 목적
- 동일한 값의 데이터를 사용하고 있는지 여부만 확인하는 것
→ 데이터 그 자체를 사용하려는 목적이 아니다 - 예시
- 사이트 관리자는 사용자의 비밀번호를 알 필요 없음
→ 악용할 위험이 있음 - 비밀번호를 DB에 저장할 때, 복호화가 불가능하도록 해싱하여 저장
→ 해싱은 복호화가 불가능하므로 사이트 관리자도 비밀번호를 알 수 없다 - 그럼 서버 측에서 비밀번호를 모르는 상태에서 어떻게 로그인 요청을 처리할 수 있는 걸까?
- 해싱한 값끼리 비교해서 일치하는지 확인
→ 정확한 값을 몰라도, 해싱한 값이 일치한다면 정확한 비밀번호를 입력했다는 의미
- 해싱한 값끼리 비교해서 일치하는지 확인
- 사이트 관리자는 사용자의 비밀번호를 알 필요 없음
- 민감한 데이터를 다루어야 하는 상황에서
- 데이터 유출의 위험성↓
- 데이터의 유효성을 검증하기 위해서 사용되는 단방향 암호화 방식
Token 인증 방식
토큰을 사용하면 사용자의 인증 정보를 서버가 아닌 클라이언트 측에 저장할 수 있다.
토큰 인증 방식의 등장 배경
기존의 세션 기반 인증이 가지고 있던 한계를 극복하고자 고안됨
→ 세션 기반 인증 : 서버에서 유저의 상태를 관리
서버의 부담을 줄이기 위해 서버가 사용자의 인증 상태를 저장하는 것이 아닌 클라이언트에 이를 저장하는 방법을 고민
→ 토큰 기반 인증 방식이 등장!
토큰은 유저의 인증 상태를 클라이언트에 저장할 수 있어서
→ 세션 인증 방식의 비교해 서버의 부하나 메모리 부족 문제를 줄일 수 있음
토큰은 교통 승차권과 같이 무언가를 이용할 수 있는 권한이나 자격을 나타내는, 일종의 증표
ex) 지하철 승차권, 사무실 출입 카드
웹 보안에서의 토큰
→ 인증과 권한 정보를 담고 있는 암호화된 문자열
→ 이를 이용해 특정 애플리케이션에 대한 사용자의 접근 권한을 부여할 수 있음
토큰 인증 방식의 흐름
- 사용자가 인증 정보를 담아 서버에 로그인 요청을 보냄
- 서버는 데이터베이스에 저장된 사용자의 인증 정보를 확인
- 인증에 성공했다면 해당 사용자의 인증 및 권한 정보를 서버의 비밀 키와 함께 토큰으로 암호화
- 생성된 토큰을 클라이언트로 전달
- HTTP 상에서 인증 토큰을 보내기 위해 사용하는 헤더인 Authorization 헤더를 사용하거나, 쿠키로 전달하는 등의 방법을 사용
- 클라이언트는 전달받은 토큰을 저장
- 저장하는 위치는 Local Storage, Session Storage, Cookie 등
- 클라이언트가 서버로 리소스를 요청할 때 토큰을 함께 전달
- 토큰을 보낼 때에도 Authorization 헤더를 사용하거나 쿠키로 전달할 수 있음
- 서버는 전달받은 토큰을 서버의 비밀 키를 통해 검증
이를 통해 토큰이 위조되었는지 혹은 토큰의 유효 기간이 지나지 않았는지 등을 확인 가능 - 토큰이 유효하다면 클라이언트의 요청에 대한 응답 데이터를 전송
토큰 인증 방식의 장점
- 무상태성
- 서버가 유저의 인증 상태를 관리하지 않는다
- 서버는 비밀 키를 통해 클라이언트에서 보낸 토큰의 유효성만 검증하면 되기 때문에 무상태적인 아키텍처를 구축 가능
- 확장성
- 다수의 서버가 공통된 세션 데이터를 가질 필요가 없다
- 서버 확장에 용이
- 어디서나 토큰 생성 가능
- 토큰의 생성과 검증이 하나의 서버에서 이루어지지 않아도 되기 때문에 토큰 생성만을 담당하는 서버 구축 가능
- 여러 서비스 간의 공통된 인증 서버를 구현 가능
- 권한 부여에 용이
- 토큰은 인증 상태, 접근 권한 등 다양한 정보를 담을 수 있기 때문에 사용자 권한 부여에 용이
- 어드민 권한 부여 및 정보에 접근할 수 있는 범위도 설정 가능
JWT (JSON Web Token)
JSON 객체에 정보를 담고 이를 토큰으로 암호화하여 전송할 수 있는 기술
클라이언트가 서버에 요청을 보낼 때, 인증정보를 암호화된 JWT 토큰으로 제공하고,
서버는 이 토큰을 검증하여 인증정보를 확인 가능
JWT의 구성
JWT는 .으로 나누어진 세 부분이 존재하며 각각을 Header, Payload, Signature라고 부른다
- Header
- 헤더에는 마치 HTTP의 헤더처럼 해당 토큰 자체를 설명하는 데이터가 담겨있다.
토큰의 종류, 그리고 시그니처를 만들 때 사용할 알고리즘을 JSON 형태로 작성 - {
"alg": "HS256",
"typ": "JWT"
}
이 JSON 객체를 base64 방식으로 인코딩하면 JWT의 첫 번째 부분인 Header가 완성- 참고로, base64 방식은 원한다면 얼마든지 디코딩할 수 있는 인코딩 방식이다
따라서 비밀번호와 같이 노출되어서는 안 되는 민감한 정보를 담지 않도록 해야 한다.
- 참고로, base64 방식은 원한다면 얼마든지 디코딩할 수 있는 인코딩 방식이다
- 헤더에는 마치 HTTP의 헤더처럼 해당 토큰 자체를 설명하는 데이터가 담겨있다.
- Payload
- payload는 HTTP의 페이로드와 마찬가지로 전달하려는 내용물을 담고 있는 부분
어떤 정보에 접근 가능한지에 대한 권한, 유저의 이름과 같은 개인정보, 토큰의 발급 시간 및 만료 시간 등의 정보들을 JSON 형태로 담음 - {
"sub": "someInformation",
"name": "phillip",
"iat": 151623391
}
이 JSON 객체를 base64로 인코딩하면 JWT의 두 번째 부분인 Payload가 완성
- payload는 HTTP의 페이로드와 마찬가지로 전달하려는 내용물을 담고 있는 부분
- Signature
- signature는 토큰의 무결성을 확인할 수 있는 부분
Header와 Payload가 완성되었다면, Signature는 이를 서버의 비밀 키(암호화에 추가할 salt)와 Header에서 지정한 알고리즘을 사용하여 해싱 - 예시)만약 HMAC SHA256 알고리즘을 사용한다면 Signature는 아래와 같은 방식으로 생성
HMACSHA256(base64UrlEncode(header) + '.' + base64UrlEncode(payload), secret);
따라서 누군가 권한을 속이기 위해 토큰의 Payload를 변조하는 등의 시도를 하더라도 토큰을 발급할 때 사용한 Secret을 정확하게 알고 있지 못한다면 유효한 Signature를 만들어낼 수 없기 때문에 서버는 Signature를 검증하는 단계에서 올바르지 않은 토큰임을 알 수 있다
- signature는 토큰의 무결성을 확인할 수 있는 부분
토큰 인증 방식의 한계
Signature을 사용해서 위조된 토큰을 알아낼 수는 있지만, 토큰 자체가 탈취된다면 토큰 인증 방식의 한계가 드러남
- 무상태성
- 인증 상태를 관리하는 주체가 서버가 아니므로, 토큰이 탈취되어도 해당 토큰을 강제로 만료시킬 수 없음
- 토큰이 만료될 때까지 사용자로 가장해 계속해서 요청을 보낼 수 있음
- 유효 기간
- 토큰이 탈취되는 상황을 대비해서 유효 기간을 짧게 설정하면,
사용자는 토큰이 만료될 때마다 다시 로그인을 진행해야 하기 때문에 좋지 않은 사용자 경험을 제공 - 유효 기간을 길게 설정하면 토큰이 탈취될 경우 더 치명적으로 작용할 수 있음
- 토큰이 탈취되는 상황을 대비해서 유효 기간을 짧게 설정하면,
- 토큰의 크기
- 토큰에 여러 정보를 담을 수 있는 만큼, 많은 데이터를 담으면 그만큼 암호화하는 과정도 길어지고 토큰의 크기도 커지기 때문에 네트워크 비용 문제가 발생
액세스 토큰(Access Token)과 리프레시 토큰(Refresh Token)
- Access Token
- 서버에 접근하기 위한 토큰
- 보안을 위해 보통 24시간 정도의 짧은 유효기간이 설정되어 있음
- Refresh Token
- 액세스 토큰이 만료되었을 때 새로운 액세스 토큰을 발급받기 위해 사용되는 토큰
- 액세스 토큰보다 긴 유효기간을 설정
이렇게 두 가지의 각기 다른 토큰을 사용하는 경우, 액세스 토큰이 만료되더라도 리프레스 토큰의 유효기간이 남아있다면 사용자는 다시 로그인을 할 필요 없이 지속해서 인증 상태를 유지
리프레시 토큰의 도입이 모든 문제를 해결해주진 않는다.
→ 리프레시 토큰은 긴 유효 기간을 가지고 있어 해당 토큰마저 탈취된다면 토큰의 긴 유효 기간 동안 악의적인 유저가 계속해서 액세스 토큰을 생성하고 사용자의 정보를 해킹할 수도 있음
→ 이를 대비하기 위해 리프레시 토큰을 세션처럼 서버에 저장하고 이에 대한 상태를 관리하기도 함
'CodeStates > Backend' 카테고리의 다른 글
Section3 / Unit7 : [Backend]OAuth (0) | 2023.07.04 |
---|---|
Section3 / Unit7 : [Backend]쿠키/세션 (0) | 2023.07.03 |
Section2 / Unit10 : Web Server(req) (0) | 2023.06.05 |
Section2 / Unit10 : Web Server (express) (0) | 2023.06.02 |
Section2 / Unit10 : Web server(SOP, CORS) (0) | 2023.06.01 |