인증(Authentication)과 인가(Authorization)
인증authentication
인증은 어떤 개체(사용자나 장치)의 신원 확인 과정이다.
일반적으로 개체는 어떤 인증 요소를 제시해 자신을 인증한다.
예시
- 은행에서 돈을 인출하기 위해 신분증을 제시한다.
- 비행기 티켓을 구매하기 위해 여권을 제시한다.
예시처럼 신원을 확인하고 싶다면 인증 요소를 제시해 인증 절차를 거쳐 신원을 확인한다.
온라인의 경우, 아이디와 패스워드를 입력하거나 SMS로 전달된 코드를 입력해 인증 절차를 진행할 수도 있다.
인가authorization
인가는 어떤 개체가 어떤 리소스에 접근할 수 있는지 또는 어떤 동작을 수행할 수 있는지를 검증하는 것, 즉 접근 권한을 얻는 과정이다.
예시
- 공연장 입장 티켓을 제시하는 상황
- 공연 기획사는 신원에 대해서는 관심을 갖지 않는다.
- 공연장 입장 권한이 있는지에만 관심을 갖는다.
- 공연장 입장 권한을 증명하려면 공연장 티켓이 필요하다.
- 공연장 티켓은 신원 정보를 포함하지 않지만 공연장 입장 권한의 인가 과정이 실패하지 않는다.
인터넷 기반 애플리케이션에서는 일반적으로 토큰을 사용해 인가를 진행한다.
- 유저가 로그인하면(인증을 거쳐 신원이 확인되면) 애플리케이션은 유저가 무엇을 할 수 있는지에 대해 관심을 갖는다.
- 유저의 신원을 바탕으로 인가 세부사항을 가진 토큰을 생성한다.
- 애플리케이션은 유저의 인가 토큰을 사용해 어떤 권한을 부여할지, 즉 어떤 리소스에 대한 접근 요청을 허용할지 거부할지를 결정하게 된다.
인증 vs 인가
인증과 인가는 혼용되어 사용되기 때문에 혼란스러운 점이 많다.
중요한 점은 인증은 인가로 이어지지만 인가는 항상 인증으로 이어지지 않는다는 점이다.
- 어떤 개체가 리소스에 대한 접근 권한을 얻는다고 해서 개체를 식별할 수 없다는 것을 말한다.
예시
- 공연장 티켓
- 공연장 티켓은 공연장 입장 권한을 인가할 수 있다. 하지만 신원 데이터를 포함하지 않아 인증할 수 없다.
이런 점 때문에 인가에 사용하는 토큰으로 유저의 신원을 파악하는 방법은 유용하지 않다.
HTTP stateless
- 웹사이트는 HTTP 프로토콜로 동작하므로 웹사이트 내의 모든 요청과 응답은 HTTP의 stateless한 특성을 갖는다.
- stateless한 특성을 갖는다는 것은 서버에 클라이언트의 이전 상태를 기억하고 있지 않다는 의미이다.
- HTTP의 stateless 특성을 고려했을 때, 유저가 로그인을 통해 인증 과정을 거쳤더라도 이후에 전달하는 요청에서는 서버가 유저의 인증 상태를 유지하지 않는다.
- 이런 상황에서 웹사이트에서 인증과 인가가 필요한 모든 상황에서 유저는 반복적으로 인증과 인가 과정을 진행해야 하는 매우 불편한 상황이 발생하게 된다.
인증과 인가 구현 방법
쿠키
- HTTP 쿠키란 서버가 클라이언트 브라우저로 전송하는 작은 데이터를 말한다.
- 브라우저는 전달받은 쿠키를 저장해 놓고, 동일한 서버로 요청을 보낼 때 쿠키를 함께 전달한다.
- 이런 방법으로 HTTP stateless 특성을 보완하여 HTTP 통신에서도 상태 정보를 보존한다.
- 인증과 인가에 쿠키를 사용할 수 있다.
- 유저가 로그인할 때 서버는 ID, PW를 쿠키에 담아 응답한다.
- 이후 동일한 서버로 요청을 보낼 때 브라우저가 ID, PW를 쿠키에 담아 보낸다.
- 쿠키에 ID, PW를 담아 보내므로 유저는 인증과 인가가 필요한 상황에서 매번 인증과 인가 과정을 진행할 필요가 없어진다.
- 인증과 인가에 쿠키를 사용하면 첫 번째 인증 때 로그인 정보를 쿠키 형태로 브라우저에 심고, 이후 요청마다 쿠키를 통해 로그인 정보를 요청과 함께 보낸다.
- 쿠키를 사용하는 방법은 기존 로그인 정보를 사용하므로 인증과 인가를 위한 추가 데이터 저장이 필요 없다는 점이 장점이다.
- 하지만 쿠키를 사용하는 방법은 민감한 로그인 정보를 매번 요청에 담아서 전송해야 하므로 보안상 문제를 갖는다는 단점이 있다.
세션
- 민감한 로그인 정보를 요청마다 담아 보내는 것(쿠키 방식)은 보안 문제가 발생할 가능성이 높은 방식이다.
- 이 방식을 보완하기 위해 나온 방식이 세션이다.
- 세션은 유저를 식별할 수 있는 값을 생성해 쿠키로 주고 받는 방식이다.
- 유저가 ID, PW로 로그인했다면 해당 유저를 식별할 수 있는 값을 생성해 쿠키에 담아 전달한다.
- 브라우저는 유저 식별 값을 담고 있는 쿠키를 저장하고, 요청마다 쿠키를 전달해 유저 식별 값을 사용하여 인증과 인가를 진행한다.
- 세션 방식은 유저의 민감한 정보를 주고 받지 않아 쿠키 방식보다 보안상 장점이 있지만, 유저 식별 값을 생성하고 서버에 저장해야 하는 작업이 필요해진다.
- 서버가 유저를 식별하기 위해 생성하는 값을 Session ID라고 하고, Session ID를 어디에 저장하는가에 따라 2가지 방식이 존재한다.
- 서버 내부에 Session 저장소가 있는 방식
- 다중 서버일 경우 문제가 있는 방식이다.
- 매번 같은 서버로 요청이 가는 것이 보장되지 않는 다중 서버 환경에서 각 서버가 개별 Session 저장소를 가질 경우, Session ID가 저장되지 않은 서버로 요청이 가면 유저를 식별할 수 없다.
- 이 문제점을 보완하는 두 가지 방법
- Load Balancer를 통해 사용자를 식별하여 이전에 통신한 서버로 요청이 가도록 경로를 지정하는 방법
- 다중 서버의 모든 session 저장소를 동일하게 유지하는 방법
- 두 번째, 단일 Session 저장소를 두고 서버에서 저장소에 접근해 Session ID를 삽입하고 조회하는 방식
- 다중 서버 환경에서 단일 session 저장소가 감당할 부하가 커질 수 있다.
- 세션을 사용하는 인증과 인가 방식은 로그인 정보를 직접 사용하지 않는다는 점에서 쿠키만 사용하는 인증과 인가 방식보다 안전하다.
- 하지만 Session ID도 유출 가능성이 있고, 클라이언트의 상태를 서버가 관리한다는 점이 HTTP의 stateless 특성과는 거리가 있다.
토큰
- 토큰은 유저 인증 정보가 숨겨진 암호화된 Access Token을 발행하고, 인증이 필요할 때마다 서버에 토큰과 함께 요청을 보내는 방식이다.
- 서버는 전달받은 토큰을 복호화하여 토큰 속에서 유저 식별 정보를 얻고, 이를 바탕으로 인증과 인가를 진행한다.
- 여러 토큰 중에서 JWT는 웹서비스에서 자주 사용되는 토큰이다.
- JWT의 구성 요소는 다음과 같다.
- 헤더: 토큰 유형, 서명 알고리즘(HS256, RSA 등)이 담기는 영역
- 페이로드: 클레임이 포함되는 영역으로, 전송할 데이터가 담긴다.
- 시그니쳐: Base64로 인코딩된 헤더, 페이로드와 서버가 갖고 있는 Secret Key를 암호화 알고리즘으로 암호화한 값이 담기는 영역
- 헤더, 페이로드, 시그니쳐는 “.” (점)으로 구분된다.
- JWT ⇒
헤더Base64인코딩결과
. 페이로드Base64인코딩결과
. 암호화알고리즘함수(헤더Base64인코딩결과 + “.” + 페이로드Base64인코딩결과, Secret Key)
JWT 검증 방식
- JWT가 서버에 도착한 경우, 서버는 요청과 함께 도착한 JWT가 자신이 발행한 것이 맞는지를 먼저 확인한다.
- 암호화 방식에 따라 이 과정에서 차이가 있다.
- HS256 - 헤더와 페이로드 그리고 서버가 가지고 있는 Secret Key로 암호화를 진행해 시그니쳐 영역과 같은지를 확인한다.
- RSA - 퍼블릭 키로 시그니쳐를 복호화하여 헤더, 페이로드와 비교한다.
JWT 저장 장소
- 쿠키와 세션의 경우 브라우저 쿠키에 저장한다.
- JWT의 경우 브라우저의 로컬 스토리지와 쿠키 둘 중 하나에 저장할 수 있다.
참고