인증과 인가
인증과 인가
인증과 인가는 순차적으로 진행이 되어야 합니다. 인증되지 않는 사용자에게 인가를 제공할 수 없습니다. 그러므로 우리는 인증을 먼저 진행해야 합니다.
인증
인증이라는 단어는 쉽게 추측할 수 있습니다. 서비스에 접속하려는 사용자가 등록된 사용자 인지를 알아보는 것 입니다. 이로써 인증을 거치게 되면 해당 사용자는 서비스에 등록되어 있는 사용자이므로 접근할 권한을 갖습니다.
이러한 인증을 서비스에 적용하면 로그인이라고 말할 수 있습니다.
인가
인가는 리소스에 접근했을 때 해당 사용자가 접근하려는 리소스에 접근 할 권한이 있는지 알아보는 작업이라고 할 수 있습니다.
이 작업이 필요한 이유는 간단한 예시로 알 수 있습니다. 만약 여러분이 게임을 하기위해 회원가입을 통해 사용자를 등록하고 로그인 과정을 거쳐 인증을 마쳤다고 생각해보겠습니다.
여러분은 리소스에 접근 할 권한을 얻었지만, 과연 운영자만이 사용가능 한 공지사항에 글을 올릴 수 있을까요?
답은 아니다 입니다. 쉽게 안된다는 것을 알 수 있죠.
이처럼 인증된 사용자에게도 모든 리소스에 접근 할 수 있는 것이 아닌 특정 리소스에만 접근 할 수 있도록 하는 제재가 있어야 합니다. 이 때 사용하는 것이 권한 입니다.
사용자마다 권한을 설정하여 권한에 맞게 리소스에 접근 할 수 있게 도와주는 것을 인가라고 말할 수 있습니다.
인증과 인가의 방식
일반적으로 우리는 로그인 할 때 아이디와 비밀번호를 입력하고 인증을 받습니다. 하지만 서비스를 받을 때 마다 로그인을 해야 한다면, 많이 귀찮을 것 같습니다.
그렇기 때문에 한번 인증 한 후 인증을 받은 사용자라는 것을 서버에서도 알아야 합니다. 어떻게 알 수 있을까요?
처음에 인증을 했을 때는 아마 사용자의 아이디와 비밀번호를 클라이언트 내의 쿠키에 담아놓고 요청을 보낼 때 마다 전송을 했을 것 입니다. 하지만 클라이언트에 접근 하는 해커가 쉽게 정보를 읽을 수 있다는 단점이 있기에 다른 방법을 생각하기 시작합니다.
이제 발전한 방법에 대해서 제가 아는 만큼 설명해보도록 하겠습니다.
1. 세션 - 쿠키 방식
스프링 시큐리티의 인증과 인가 방식입니다. 이 방법은 이름 그대로 서버에서 관리하는 세션과 클라이언트에서 관리하는 쿠키를 기반으로 작동하는 방법입니다.
처음 인증을 시작할 때 아이디와 비밀번호를 서버측으로 보내게 됩니다. SSL인증서가 있는 HTTPS를 사용하는 서버라면 해당 정보는 공개키로 암호화 되어서 해당 서버만이 해독할 수 있도록 되겠죠.
여기까지 성공했다면 서버측은 가져온 정보를 보고 서비스에 등록 된 사용자임이 확인되면 세션에 해당 사용자의 정보를 저장합니다. 그리고 그 사용자에게 SID(세션ID)를 할당하여 클라이언트 측으로 보내줍니다.
이제 사용자는 자신의 쿠키에 해당 SID를 저장 한 뒤 이후로 서버에 리소스를 요청 할 때마다 쿠키에 담긴 SID를 담아서 보냅니다.
그럼 서버는 간단히 해단 SID를 보고 유저를 알아낼 수 있게 됩니다.
만약 해커가 이 과정에서 클라이언트의 SID를 훔칠 수 있게 되면 어떤 일이 벌어질까요? 이 부분에서는 문제가 생길 수 있습니다만, 이 문제를 어느정도 방지하는 방법으로 우리는 세션이 유지되는 시간을 설정할 수 있습니다.
예를 들면 60분 동안만 세션이 유지되는 서비스를 만든다면 해커가 사용자의 SID를 훔쳤더라도 60분이 지나면 유저의 정보와 매칭 된 SID는 만료되기 때문에 사용할 수 없게 됩니다.
이러한 방식으로 세션 - 쿠키 방식의 인증 방법은 진행됩니다.
2. Token 방식
Token 방식에 대한 설명은 현재 자주 사용되고 있는 JWT에 대해서 설명 드리겠습니다. 제가 가장 이해하기 어려웠던 부분이기에 조심히..
Token을 사용하는 이유에 대해서 먼저 알아보겠습니다.
세션을 이용하는 방법을 사용하다보면 세션ID에 매핑되는 사용자에 대한 정보등을 서버에 저장해야하는 문제가 생깁니다. 사용하는 사람이 많을수록 서버에 부하는 커지게 되죠.
또한 로드밸런싱과 트래픽이 높아질 경우 동일한 스케일의 다른 서버로 연결시켜주는 서비스를 이용하다보면 세션이 저장 된 서버와는 다른 서버로 접근 할 수 있습니다. 이 경우에는 세션의 정보는 사용할 수 없게 되죠.
이 문제를 해결하기위해 별도의 DB 서버(SID용 DB)를 만들어서 확인 할 수 있으나 서버의 부하가 생길 수 있는 문제가 있습니다.
그래서 Token 방식이 생겨났습니다. 이 방법의 활용을 이전 회사에서 작업 했을 때 알았다면 더 좋은 서비스를 만들 수 있었을텐데, 그땐 공부가 부족했네요
JWT는 Json Web Token 입니다. 이름 그대로 인증 절차를 JSON을 통해 해결하는 방식으로 이름만 보면 위험할 수 있다는 생각이 들지만 설명이 끝나면 대단하다는 생각을 하실 수 있습니다.
제가 이해한 내용에 대해 전반적인 그림을 그려보았습니다. 다음을 보시면 JWT를 이용한 인증의 절차를 알 수 있습니다. 중간에 4번과 6번의 인증 과정은 추가적으로 알아보겠습니다.
똑같이 사용자는 아이디와 비밀번호를 이용하여 로그인(인증)을 시도합니다. 그리고 서버는 등록된 사용자인지 확인하죠. 여기까지는 같습니다.
이 때 등록 된 사용자임이 확실해지면 서버는 세션에 정보를 저장하는 것 대신 JSON형태의 토큰을 보냅니다. 해당 토큰에 저장되는 토큰은 아래에서 더 자세하게 설명하겠습니다.
그럼 이후에 사용자는 서버에 요청을 보낼 때 토큰을 함께 보내게 되고, 서버는 해당 토큰을 서버가 가지고 있는 키를 기반으로 디코딩을 시켜서 확인하는 작업을 거칩니다. 그리고 정상적인 토큰이라면 요청에 대한 응답을 주는 방식입니다.
이제! 그림에서 빨간색으로 표시 된 부분을 더 자세하게 알아봅시다!
1. JWT 형식의 토큰은 어떻게 만들어지나?
정답은 서버만이 가지고 있는 해시를 위한 키입니다. JWT의 암호화 방식은 기본적으로 해시를 통한 암호화를 사용하기 때문에 해시의 키가 필요합니다. 오직 서버만이 가지고 있기 때문에 유출되지 않는 한 안전한 상태입니다.
이 키를 이용하여 사용자가 인증 여부를 알 수 있는 값을 해시로 암호화 하여 토큰을 만드는 방식입니다.
2. 토큰에는 어떤 정보가 들어가는가?
그러면 토큰에는 어떤 값이 들어갈까요?
1) Header
Header에 적히는 내용은 이 토큰의 형태(ex : jwt)와 암호화 한 알고리즘에 대한 정보가 들어갑니다. 대표적인 HS256과 같은 암호화 알고리즘이 적히는 것으로 알고 있습니다.
2) Payload
Payload는 사용자에 대한 정보가 들어갑니다. 일반적으로 토큰 형식으로 클라이언트에게 저장되는 값이기 때문에 비밀번호와 같은 중요 정보가 아닌 값이 저장되는게 일반적입니다.
이 부분은 서비스마다 다를 수 있습니다만, 일반적으로 해당 사용자의 권한/만료시간 등을 저장하는 것으로 알고 있습니다.
3) Signature
Signature는 토큰의 유효함을 알기 위해 사용하는 부분입니다. 추가적인 정보를 저장하는 것이 아닌 Header와 Payload 부분의 데이터를 base64 인코딩을 하여 .을 기준으로 연달아 나열한 값입니다.
3. 토큰이 유효함은 어떻게 아는가?
이 부분이 JWT에 대해 감탄사를 보낸 부분입니다.
Signature를 이용하여 유효함을 알 수 있습니다! 악의적인 목적으로 Payload에 적힌 값을 변경하여 서버에 요청을 보냈다고 생각을 해보겠습니다.
유저의 권한으로는 관리자 페이지에 접근 할 수 없지만 Payload에 관리자 페이지에 접근 할 수 있는 권한을 추가적으로 입력하여 접근을 시도한다면 접근할 수 있을까요?
이 때 토큰을 받은 서버는 가지고 있는 키를 이용하여 Header와 Payload에 적힌 내용을 읽어서 Header에 적힌 암호화 방식을 이용하여 다시 해시 값을 얻어낸 뒤 Signature와 비교하는 작업을 진행합니다.
해커 입장에서 Payload에 내용을 추가하는 과정까지는 진행했지만 키가 없기 때문에 해당 내용의 올바른 해시 값을 얻어낼 수는 없기 때문에 이 과정에서 적힌 내용이 유효한지 알 수 있습니다.
만약 Header와 Payload의 값이 Signature와 다르다면? 서버는 리소스에 접근 하지 못하도록 막게 됩니다.
3. OAUTH
마지막 OAUTH에 도달했습니다.
제가 실제로 네아로를 이용해서 서비스에 적용시켰던 경험이 있지만 다시 공부하면서 어설펐던 이해를 바로잡을 수 있었기에 제대로 이해해보겠습니다.
OAUTH는 현재 이용하려는 서비스가 아닌 다른 서비스에 저장되어있는 사용자의 정보를 이용하여 인증을 하는 방식이라고 말할 수 있을 것 같습니다.
우리가 흔히 알고있는 네이버 아이디로 로그인 혹은 카카오로 로그인 등이 Oauth를 이용한 인증이라고 할 수 있습니다.
Oauth의 진행 과정을 다음의 그림으로 표현해보았습니다.
Oauth를 통한 인증 즉 로그인을 기반으로 해당 개념을 생각해보겠습니다.
-
처음에 사용자는 A를 이용하여 로그인을 클릭합니다.
-
그러면 현재 사용중인 서비스에서는 A 서비스에게 현재 사용자가 A 서비스를 이용하여 로그인을 하고 싶어한다는 요청을 보내게 됩니다.
-
A 서비스는 사용자에게 자신들의 인증 페이지(로그인 페이지)를 띄워서 사용자에게 자신의 서비스에 대해 인증을 요청합니다.
-
사용자에게 A 서비스에 인증을 마칩니다.
-
등록 된 사용자가 맞다면 A 서비스에 접근 할 수 있는 인증코드를 보내줍니다.
-
인증코드를 서비스 제공 측에 전달합니다.
-
서비스 제공 측은 A 서비스에게 인증코드를 기반으로 원하는 서비스에 접근 할 수 있는 Access Token을 요청합니다.
-
Access Token을 받은 서비스는 이후 그 Token을 기반으로 A 서비스에서 제공하는 API를 사용합니다.
이번에 인증과 인가에 대해 알아보았습니다. 다음 포스팅은 제가 사용해 본 Spring Security에 대해 알아보는 시간을 갖겠습니다.
너무.. 어렵습니다.. 시큐리티..
참고
http://www.opennaru.com/opennaru-blog/jwt-json-web-token/
https://www.youtube.com/watch?v=MUUqogMpGiA&t=102s
https://www.youtube.com/watch?v=JZgD8aPkHSc&list=PLgXGHBqgT2TvpJ_p9L_yZKPifgdBOzdVH&index=119