웹 개발을 하고 있다면, 인증이랑 인가 쪽을 직접 한땀한땀 구현해야할 일은 많이 없을지라도! 그래도 인증, 인가의 개념이 무엇인지 이해해야할 상황은 반드시 있으리라 생각한다. 왜냐하면 대부분의 유료 서비스는 '인증'된 사용자만 사용할 수 있고, 그 안에서도 기능에 따라 '인가'된 사용자만 사용할 수 있기 때문이다. 인증, 인가 쪽은 카카오 간편 로그인 서비스 정도를 붙일 때 많이 들어봤을 수 있고, 요즘 뜨고 있는 keycloak(키클록) 오픈 소스를 사용하면서 좀 더 관심이 생겼을 수 있고, 이렇게 둘다 아니더라도 리소스 서버를 개발하면서 토큰의 유효성을 검사하고, 토큰을 까서 사용자 권한을 체크하는 과정을 해보면서 필연적으로 만나게 된 개념일 수도 있다.
익숙하게 느껴지더라도, 정확하게는 모를 수도 있으니까! 이번 기회에 한번 같이 알아보면 좋을 것 같다. : )
그럼, 시작!
인증(Authentication)
Authentication is the act of validating that users are whom they claim to be.
This is the first step in any security process.
인증은 사용자들이 누구인지 검증하는 행위이고, 보안 프로세스의 첫번째 단계이다. 즉 여기서 가장 중요한 것은 validating 이다. 즉, 이 사용자가 정말 '그' 사용자가 맞는지 체크를 하는 것이다. 인증 방법의 대표적인 것은 비밀번호, 생체인증(지문인식 등)이 있다.
최근에는 보안의 중요성이 강조되면서, multi-factor authentication(MFA) 방식의 인증도 많이 사용되고 있다. 비밀번호 입력 후에 추가적으로 이메일, 문자 인증을 받는 것, 카카오 보안서 인증인가? 등을 하는 절차를 생각하면 좀 더 와닿는다.
인가(Authorization)
인가는 특정 리소스나 기능에 접근할 수 있는 권한을 사용자에게 부여하는 과정을 말한다. 인가는 개인 사용자에게 주어질 수도 있고, 특정 클라이언트에게 주어질 수도 있다. 그리고 인가를 하기 위해서는 반드시 앞선 인증은 필수적으로 거쳐야 한다. 영어로 봤을 때, Authentication(인가) 그리고 Authorization(인증)은 비슷하게 들릴 수도 있지만(한국어로도 비슷해서 헷갈리지만!), 이 둘은 Identity and access management(IAM)에서 완전히 구별되는 보안 절차이다.
Okta 에서 보안과 관련된 좋은 글들이 많다. 그래서 읽어보다가 좋은 표가 있어서 가져와봤는데, 같이 보면 좋을 것 같아서 넣어봤다.
정리해보자면, 인증은 사용자 검증 단계 그리고 인가는 사용자에게 권한 부여 단계이다. 이렇게 정리하면 깔끔하게 쉬워보인다. 그러면, 인증, 인가 쪽을 공부할 때마다 나오는 OAuth에 대해서도 살펴보자.
OAuth
위키피디아를 찾아보면, 영어로 이렇게 적혀있다.
OAuth is an open standard for access delegation, commonly used as a way for internet users to grant websites or applications access to their information on other websites but without giving them the passwords. This mechanism is used by companies such as Amazon, Google, Facebook, Microsoft, and Twitter to permit the users to share information about their accounts with third-party applications or websites.
한국말로 다시 번역하자면 이렇다.
OAuth 는 패스워드를 제공하지 않고도 다른 웹사이트 상의 그들의 정보를 웹사이트나 애플리케이션에 접근 권한을 부여할 수 있도록 공통적으로 사용되는 접근 위임의 개방형 표준이다. 이 매커니즘은 아마존, 구글, 페이스북, 마이크로소프트, 트위터 등 기업들에 의해 사용되는데, 제 3자의 애플리케이션이나 웹사이트들과 그들의 계정 정보를 공유하도록 사용자들에게 허가를 해주는 것이다.
OAuth를 처음 접해봤다면, 위 설명을 듣고도 어려울 수 있을 것 같다.
우선, 핵심에 대해 먼저 기억하고 가자면, OAuth 는 Authorization Framework 라는 것이다. 즉, OAuth의 핵심은 인가에 있지, 인증에 있는 것이 아니다. 이것을 기억하는 것은 굉장히 중요하다.
OAuth를 이루는 구성요소
1. Resource Owner
2. Client
3. Authorization Server
4. Resource Server
OAuth 에서 사용되는 Client 의 종류
Confidential Client
A client able to securely authenticate with the authorization server,
for example being able to keep their registered client secret safe.
Public Client
A client unable to use registered client secrets,
such as applications running in a browser or on a mobile app
결국 쉽게 생각하면, client credentials를 안전하게 보관할 수 있는지 없는지에 따라 confidential vs public 타입인지 나뉜다고 생각하면 될 것 같다. 예를 들어서, authorization server (권한인증서버)와 주고받는 주체가 서버라고 한다면, 브라우저로부터 authorization code 를 받아서 서버에 보관한 client secret 값을 통해 토큰을 받아올 수가 있다. 이 경우는 OAuth에서 가장 스탠다드한 방법이기도 하고, 이 경우는 confidential client를 쓰고 있는 경우이다.
하지만 문제는 SPA(Single Page Apps)와 같이 서버가 아니라, 브라우저나 앱이 직접적으로 권한인증서버와 소통할 때다. 브라우저나 앱은 절대 그 중요한 값 자체를 보관하고 있을 수가 없다. 그래서 public client가 필요해졌고, 실제로 쓰인다고 보면 되는 것이다.
그러면 public client 의 경우에는 어떻게 인가를 할 수 있을까?
Authorization Code Flow vs Implicit Flow
Authorization Code Flow
권한인증서버가 주는 code 를 받아서 오면, 그 값을 가지고 back channel을 통해서 server가 갖고 있는 client credentials 값과 함께 권한 인증 서버에 가서 토큰을 받아오는 것이 OAuth Flow 에서 가장 보편적인 방식이다. 여기서 아무나 code 를 가져가면 토큰을 주는 것이 아니라, 이미 권한인증서버가 알고 있는 검증된 클라이언트라는 것이 증명이 되어야 된다. 그것을 바로 server 가 알고 있는 client credentials 값으로 증명하는 것이다.
Implicit Flow
implicit flow 가 탄생한 배경 자체는, 프론트엔드의 웹 어플리케이션이 직접 사용자에 대한 인가를 받아오기 위함이었다. 그렇기 때문에, 웹은 스스로 client credentials 를 안전하게 보관할 수 있는 환경이 아니었고, 그래서 implicit flow에는 위 authorization code flow 에서 client credentials 를 확인하는 과정 즉 client authentication 과정이 빠져있다. 대신, 미리 authorization server 에 등록한 redirect uri 에 access token 을 보내는 방식으로 보안을 고려한다.
또한, OAuth 2.0 이 처음 나왔을 때, 모바일이나 네이티브 앱의 경우에는 고려 대상이 아니었다. 하지만 점점 OAuth 2.0 의 고려대상이 되어야 할 필요성이 생겼다. 처음에는 authorization code flow를 사용하려고 했으나, 브라우저가 앱으로 리다이렉트 되는 시점에서 가로챔을 당해서 해킹 공격을 당할 가능성이 높았고, client credentials은 모바일 앱에서도 보관할 수가 없으니, 이를 보완하기 위해 보다 '안전한' 방법이 필요했다. 그래서 등장한 것이 바로 PKCE, Proof Key for Code Exchange 이다.
PKCE(Proof Key for Code Exchange)
여기서도 client credentials 을 갖고 있는 서버가 존재하지 않는다. 그래서 클라이언트가 code verifier, code challenge 를 최초에 생성한다. 이것이 PKCE 방법의 핵심이다. code verifier는 48 ~ 128 글자수를 가진 Random String이다. 그리고 선택한 Hash 알고리즘으로 Code Verifier를 Hashing 한 후 Base64 인코딩을 한 값이 바로 code challenge이다. 그래서 권한인증 서버로 인증요청을 할 때(로그인 페이지로 이동할 때) code_challenge, code_challenge_method(알고리즘 종류)를 보낸다. 그러면 이 값을 권한인증서버가 갖고 있다가, 나중에 클라이언트가 authorization code 를 갖고 권한인증서버에게 토큰 요청을 하러갈 때, code_verifier 를 함께 가져간다. 그러면 권한 인증서버는 갖고 있는 code_challenge 값과 해싱된 code_verifier 를 base64 인코딩해서 비교를 하게 되고, 서로 일치하면, 토큰을 발급해주게 된다.
Reference
'프로그래밍, 개발' 카테고리의 다른 글
왜 그래프 데이터베이스를 사용하는가? (0) | 2023.03.19 |
---|---|
keycloak : id of client 와 client id 값의 차이 (0) | 2023.03.06 |
Relational Databases Lack Relationships (0) | 2023.03.05 |
DDD 개발 이해하기 : 도메인(Domain)과 애그리거트(Aggregate) (0) | 2023.02.26 |
헥사고날 아키텍처(Hexagonal Architecture) 란? (0) | 2023.02.26 |