[개념정리] 웹에서의 인증

flaxinger·2022년 1월 1일
0

개념정리

목록 보기
1/3

Cookie란?

쿠키는 클라이언트가 웹사이트를 방문할 때 서버에게 HTTP header(Set-Cookie)를 통해 받는 Key-Value 형식의 문자열이다. 이후 클라이언트는 모든 요청의 header에 쿠키를 넣어서 요청하게 된다. 쿠키는 클라이언트를 식별할 수 있는 정보를 담고 있는데, 별도 암호화없이 보내지기 때문에 유출 및 조작의 위험이 있다. 더불어 쿠키의 크기가 크면 용량(최대 4KB) 및 overhead의 문제가 발생하며, 브라우저별로 쿠키 지원 형태가 달라 브라우저간 공유가 불가능하다.

Session Cookie는 앞선 쿠키의 취약점을 보완하기 위해 기존 쿠키에 담았던 민감 정보를 서버에 보관하고 이와 매칭되는 키(JSESSIONID)를 생성하여 클라이언트한테 주는 방식이다. 이후 클라이언트는 JSESSIONID를 요청 header에 담아서 보내고, 서버는 해당 JSESSIONID에 매칭되는 쿠키를 찾아서 사용자를 식별한다. 이때 JSESSIONID는 브라우저를 닫거나, (일정 시간이 지나) 서버에서 세션을 삭제하면 삭제된다. 즉 동일 유저가 다음에 연결할 때는 새로운 랜덤 JSESSIONID가 생성되어 전송된다.

Cookie와 Session의 차이

1. 보안

우선 명확히 해야하는 점은 쿠키든 JSESSIONID든 중간자 공격(Man In The Middle Attack)에 취약하다. 즉 쿠키든 JSESSIONID든 중간에서 누군가가 이를 확인한다면, 해당 정보의 주인을 사칭할 수 있다. 그럼 쿠키와 세션 쿠키방식은 어떻게 다른걸까?

앞서 말했듯 쿠키는 서버가 이를 받았을 때 사용자를 식별할 수 있는 정보다. 즉 쿠키의 정보가 사용자의 정보를 일부 담고 있다는 것이다. 쿠키에 어떤 정보가 담기는지는 웹사이트마다 다르지만 예로 아래와 같이 로그인 정보가 담길 수도 있다.

Cookie:"userName=kevin"; "password=abc123"

이러한 정보를 누군가가 취득했다면 당연히 굉장히 위험한 상황이 된다.
반면 아래와 예시와 같이 랜덤하게 생성된 JSESSIONID는 유저가 무한히 접속해있지 않는 한 반드시 삭제된다. 따라서 해커가 한번 취득했다 하더라도 일정 기간이 지나면 사용하지 못하게 된다. 이런 면에서 세션쿠키 방식은 쿠키보다 보안이 좋다.

JSESSIONID=FDB5E30BF20045E8A9AAFC788383680C

2. 효율성

앞서 언급되었듯 세션쿠키 방식은 서버에서 JSESSIONID와 서버에 저장된 세션쿠키를 매칭해야하므로 overhead가 발생한다. 더불어 쿠키를 서버에 저장하기에 디스크 사용량 또한 비교적 높다. 다만 최대 4KB의 데이터만 저장하는 쿠키 방식과 달리 세션쿠키 방식은 쿠키 크기의 한계가 없다.

쿠키와 세션의 보안

여기서 이상한 점이 있다. 세션쿠키가 보다 보안이 좋지만 결론은 쿠키든 세션쿠키든 누군가 취득하면 나를 사칭할 수 있다는 것이다. 이를 방지하기 위해 나온 것이 HttpOnly와 Secure flag다. 이를 하나씩 살펴보자

HttpOnly

여담이지만 처음 HttpOnly를 접했을 때 "아니 보안을 위해 http만 쓴다고?"라는 무식한 생각을 했다. 절대 이런 의미가 아니니 헷갈리는 분 없으시길.

본론으로 돌아와 HttpOnly는 Javascript 함수로 쿠키 정보를 못읽게 하겠다는 것이다. 이게 무슨 말인지 알기 위해서는 크롬의 개발자도구를 켜고 콘솔에서 document.cookie를 쳐보면 된다. 이 명령은 현재 페이지의 쿠키를 읽어 온다. 이때 httpOnly가 설정되지 않은 쿠키가 있다면 JSESSION 값이 떡하니 콘솔창에 출력이 된다. 참고로 만약 '_ga', '_gid' 키값의 데이터만 보인다면 이는 Google Analytics에서 사용하는 쿠키라고 한다. 물론 대부분 경우 HttpOnly를 설정하기에 이를 직접 확인하기는 힘든 것 같다. 이는 서버 response header의 set-cookie값에 'HttpOnly'라는 옵션을 추가해주면 된다.

Secure Flag

클라이언트에서 Javascript로 쿠키를 조회하지 못하게 했다면 앞서 말한 중간자 공격도 방지해야한다. 이는 Secure flag로 방지하며 마찬가지로 set-cookie에 'Secure'라는 값을 추가하여 적용한다. 해당 플래그가 설정되면 클라이언트는 암호화된 요청, 즉 HTTPS를 통한 요청에만 쿠키를 추가한다. 따라서 중간에 누군가가 패킷을 읽는다고 해도 JSESSIONID가 악용될 우려가 없다.

JWT(JSON Web Token)란?

JWT(영어로 'jot'이라고도 한다는데 어감이 썩 좋지는 않다)는 데이터베이스를 사용하지 않고 인증을 하는 방식이다. 쿠키와 세션 쿠키의 경우 대부분 경우 데이터베이스를 이용하는데, Scaling 및 로드밸런싱이 편리한 API 서버와 달리 데이터베이스는 스케일링이 까다롭기 때문에 데이터베이스가 보틀넥이 되기 쉽다. 물론 메모리(이 경우는 서버 스케일일업이 안된다), 레디스, sticky session 등을 이용하는 방법 또한 존재한다. 따라서 데이터베이스가 전혀 필요하지 않은 것이 JWT의 가장 두드러지는 장점이 되겠다.

JWT의 구조는 '.'로 구분되어 있는 Base64url(Base64 인코딩과 달리 URL-Safe하다) 인코딩 문자열 3개로 이루어져있다. 이름에도 명시되어 있듯 문자열을 디코딩하면 각각 하나의 JSON Object가 된다. 각 문자열은 header, payload, signature로 불리며 용도는 아래와 같다.

  • Header: 토큰 타입, 해시 암호화 알고리즘을 담고 있다.
  • Payload: 유저와 권한 식별에 사용되는 Claim(Key-value 페어로 되어 있는 정보)을 하나 이상 담고 있으며, 클레임의 종류는 registerd, public, private으로 나뉜다. 이 부분은 향후 JWT 심화글에서 한번 더 다뤄야겠다.
  • Signature: Secret Key와 Header의 암호화 알고리즘으로 header와 payload를 암호화한 object이다. 이때 Secret Key는 토큰에 포함되지 않고 서버에만 보관되기에 서버만 이를 복호화할 수 있고, 따라서 이 방법으로 데이터의 위변조 여부를 확인할 수 있다. 해징 알고리즘도 다양하고 사실 Secret Key가 직관적으로 이해되지 않지만 마찬가지로 이 부분은 JWT 심화글에서 다루도록 하겠다.

전반적인 인증 절차는 다음과 같다. 우선 로그인 시 서버가 토큰을 발급하고 Response에 담는다. 이후 모든 요청에 클라이언트는 토큰을 Header의 Authorization에 포함시키고 서버는 위변조 여부 확인만으로 유저와 권한을 식별할 수 있다.

토큰은 효율적이지만 전통적인 Cookie만큼 많은 문제를 가지고 있다. 대표적으로 토큰 또한 탈취 워험이 있는데 이때 서버는 토큰에 대해 완전히 무상태, 즉 토큰에 대한 아무 정보 없이 Signature로만 확인만 하므로 대응을 하기가 상당히 어렵다. 이러한 이유에서 토큰의 유효기간은 일반적으로 짧은데 사용자가 토큰 만료마다 로그인을 하면 사용자 경험을 해치므로 Sliding Token(작접 중에 토큰이 만료되면 자동 연장), Refresh Token(JWT와 함께 발급되는 토큰으로 주기적인 토큰 갱신에 사용됨) 등의 기법이 사용된다. 더불어 위의 이유(서버가 무상태이므로)로 로그아웃 또한 구현하기 다소 까다롭다. 이를 보완하기 위해 DB에 BlackList를 저장하기도 한다. 하지만 Refresh Token이나 Black List의 경우에 DB를 사용하기 시작하면 JWT의 이점이 줄게 된다.

출처

인증 방식: Cookie & Session vs JWT
쿠키(Cookie), 세션(Session) 특징 및 차이
What is session hijacking and how can you stop it
JWT 토큰 - 포프TV
JWT(JSON WEB TOKEN) 이해와 활용

profile
부족해도 부지런히

0개의 댓글