보안과 원활한 인증 방법이 중요한 시대에 OAuth 2 및 OpenID Connect와 같은 프로토콜이 산업 표준으로 자리잡았다. 이 장에서는 이러한 프로토콜의 복잡성을 해체하고, 그들의 메커니즘, 이점, 그리고 잠재적인 위험 요소에 대해 설명한다.
- 액세스 토큰의 목적을 이해한다.
- OAuth 2 시스템에서 토큰이 발급되고 검증되는 방법을 파악한다.
- OAuth 2 / OpenID Connect 시스템에 관여하는 역할을 알아낸다.
여러가지 도구를 사용하는 대규모 조직에서 근무한다고 가정한다. 예를 들어, 버그 추적 앱, 업무 문서화 앱, 시간 등록 앱 등을 매일 사용해야 한다. 각 앱에 접근하려면 매번 인증을 해야 한다. 이러한 앱에 대해 서로 다른 자격 증명을 사용하게 되는데. 이는 사용자에게 번거로움을 주고 각 앱을 사용하는 목적을 복잡하게 만든다.
이 경우, 자격 증명을 여러 번 기억하고 각 앱에 로그인해야 하는 복잡성이 발생한다. 또한, 자격 증명을 안전하게 관리하고 실제 인증을 구현하는데 드는 노력도 커진다.
자격 증명과 인증 관리를 별도의 앱에서 처리한다면 사용자는 한 번만 로그인하면 되고, 이후에는 반복적인 인증 과정 없이 모든 앱을 사용할 수 있다. 이러한 방식으로 인증을 구현하는 솔루션이 OAuth2다.
이 솔루션은 더 넒은 범위로 확장할 수 있다. 예를 들어 조직 외부의 사용자들, 즉 전 세계를 대상으로 하는 공개 앱에도 이 인증 시스템을 사용할 수 있다.
- 이 앱에서 인증을 구현하는 데는 더 많은 작업과 노력이 필요하다.
- 사용자는 이 앱에 대한 특정 자격 증명이 필요하다.
- 사용자는 때로는 사용하는 작은 앱마다 특정 자격 증명을 생성하는 것을 신뢰하지 않을 수 있다.
웹에 있는 많은 앱들은 사용자가 가입하고 다양한 소셜 미디어 플랫폼을 통해 인증할 수 있도록 허용한다. 이러 방식으로 앱은 사용자가 이미 보유하고 있는 자격 증명을 사용해 인증을 처리할 수 있게 되며, 개발자는 별도의 인증 기능을 구현할 필요가 없다. 이 접근 방식은 여러 가지 장점이 있다.
- 인증을 구현하고 유지하는 비용을 줄인다.
- 사용자 신뢰 문제를 회피한다. (앱이 유지하는 다른 자격 증명을 등록하고 생성해야 하는 문제)
- 사용자가 사용하는 자격 증명의 수를 최소화하는 데 도움이 된다.
OAuth2는 인증 책임을 시스템에서 분리하는 방법을 제시하는 명세다. 이를 통해 여러 앱은 인증을 구현한 다른 앱을 사용할 수 있게 되며, 사용자는 더 빠르게 인증을 완료하고 자신의 정보를 더 안전하게 보호할 수 있다. 또한, 앱에서는 인증 기능을 직접 구현하는 비용을 최소화할 수 있다.
1. OAuth 2와 OpenID Connect의 큰 그림
대기업 면접에 참석하기 위해 본사로 호출되었다고 가정해보자. 대면 회의에 참석하려면 누구나 사무실에 들어갈 수 있는 것은 아니다. 방문객을 위한 프로토콜이 마련되어 있다.
회의에 참석하려면 먼저 프런트 데스크에서 신분증으로 자신을 증명해야 한다. 신분증이 식별되면, 프론트 테스크에서 액세스 키를 받고 이를 통해 특정 구역에 접근할 수 있다. 예를 들어 모든 엘리베이터를 사용할 수는 없고, 특정 엘리베이터만 사용할 수 있다.
회의를 위해 건물에 들어가는 과정은 OAuth2에서의 인증과 인가 작업 방식과 매우 유사하다. 우리는 특정 작업을 수행해야 하는 사용자로, 회의를 위해 특정 방으로 가야한다. 이 작업은 신분증 (ID)을 사용하여 프런트 데스크 (인가 서버)에서 인증을 받는다. 자신이 누구인지 증명한 후 액세스 카드 (토큰)를 받게된다. 이 카드는 특정 엘리베이터나 문 (특정 리소스)에만 접근할 수 있도록 제한된다. 또한 액세스 카드는 유효 기간이 있어 회의가 끝나면 프런트 데스크에서 반납해야 한다.
이 과정을 통해 OAuth2 시스템 내에서 상호작용하는 책임과 흐름을 이해할 수 있다. OAuth2는 인증 및 인가의 명세서로, 사용자가 신원 확인을 받고 제한된 자원에 접근할 있도록 토큰을 발급 받는 방식이다.
또한 OAuth2와 OpenID Connect (프로토콜)의 차이를 이해해야 한다. OAuth2는 인증 및 인가를 위한 기본 명세서로, 자원 접근을 제한하는 역할을 한다. 반면 OpenID Connect는 OAuth2위에 구축된 프로토콜로, 주로 사용자 인증에 초점을 맞추어 사용자의 신원을 확인하는 역할을 한다.
- 사용자(User): 애플리케이션을 사용하는 사람. 사용자는 일반적으로 클라이언트라고하는 프런트엔드 애플리케이션과 함께 작업한다. 사용자는 항상 OAuth 2 시스템에 존재하지는 않는다.
- 클라이언트(Client): 백엔드를 호출하고 인증 및 인가가 필요한 애플리케이션이다. 클라이언트는 웹 앱, 모바일 앱, 데스크톱 앱 또는 별도의 백엔드 서비스일 수 있다. 클라이언트가 백엔드 서비스인 경우 시스템에는 일반적으로 사용자 역할이 없다.
- 리소스 서버(Resource Server): 하나 이상의 클라이언트 애플리케이션이 보낸 호출을 인증하고 처리하는 백엔드 애플리케이션이다. 인가 서버(Authorization Server): 인증 및 자격 증명의 안전한 저장을 구현하는 앱이다.
사용자는 백엔드 서비스 (리소스 서버)에서 특정 작업을 위해 인가를 받아야하는 클라이언트를 사용한다. 클라이언트의 백엔드에서 인가를 받기 위해 먼저 인가 서버에서 인증되어야 한다. 인증과 권환 부여는 아래와 같은 단계로 이루어진다.
- 사용자가 클라이언트 앱을 사용하여 특정 사용 케이스를 실행한다.
- 클라이언트 앱은 사용자의 요청을 처리하기 위해 리소스 서버를 호출할 수 있는 권한을 받는다.
- 인가를 받기 위해 클라리언트는 먼저 인가 서버에서 토큰 (엑세스 토큰)을 요청한다. 이 토큰은 클라이언트가, 인가 서버가 클라이언트 자신을 올바르게 식별했다는 것을 증명하는데 도움이 되는 특정 정보다.
- 클라이언트는 인가 서버가 발급한 토큰을 사용하여 자신의 백엔드 (리소스 서버)에 요청을 보낸다.
더 자세한 내용은 아래와 같다.
- 사용자가 특정 사용 사례를 실행하기 위해 클라이언트 애플리케이션을 사용하려고 한다.
- 클라이언트 애플리케이션은 자신의 백엔드를 호출하기 위해 토큰을 먼저 가져야 함을 알고 있다. 이를 위해 클라이언트는 인가 서버에서 해당 액세스 토큰을 요청한다.
- 클라이언트 앱의 요청에 따라, 인가 서버는 토큰을 발급하고 클라이언트 앱에게 전송한다.
- 클라이언트는 앱을 사용하여 요청을 백엔드 (리소스 서버)로 보낸다.
- 리소스 서버는 클라이언트의 요청을 인가한다. 성공적으로 인되면 리소스 서버는 클라이언트의 요청을 실행하고 응답한다.
- 클라이언트는 결과를 사용자에게 표시한다.
클라이언트는 인가 서버에서 토큰을 요청하고 이 토큰을 사용하여 백엔드 앱 (리소스 서버)에 요청을 보낼 때 승인을 받는다.
인가 서버가 발급하는 토큰은 클라이언트가 인가 서버에 의해 인증되었음을 증명하는 임의의 데이터 조각 (주로 문자열)이다. 이 토큰은 사용자가 클라이언트에 대한 추가 정보를 얻는 방법을 제공할 수 잇다. 인가 서버가 사용자 및 클라이언트의 모든 세부 정보를 관리하므로, 때때로 백엔드 시스템은 토큰을 통해 필요한 세부 정버를 인가 서버에서 가져와야 한다.
토큰 자체에 사용자와 클라이언트에 대한 세부 정보가 포함될 수 있고 (투명 토큰), 그렇지 않은 경우 백엔드는 인가 서버를 호출하여 데이터를 얻어야 한다. (불투명 토큰). 또한, 액세스 토큰은 실제 키와는 달리 수명이 짧다. 일반적으로 몇 분 후에 만료되며 클라이언트는 새로운 토큰을 요청해야 한다. 이렇게 하면 분실된 토큰이 남용되는 것을 방지할 수 있다.
OAuth2는 클라이언트가 토큰을 얻을 수 있는 다양한 흐름을 설명한다. 이러한 흐름을 그랜트 타입이라고 한다.
2. 다양한 토큰 구현 사용
토큰은 클라이언트가 백엔드 (리소스 서버)에 요청을 보낼 때 인가를 받기 위해 사용하는 액세스 카드다. 이는 OAuth2 인증 및 인가 프로세스의 중요한 요소로, 클라이언트와 사용자의 신원을 증명하는데 사용된다. 동시에 백엔드는 이 토큰을 통해 클라이언트와 사용자에 대한 추가 정보를 얻을 수 있다.
사용자는 리소스 서버에 액세스해야 한다. 이를 위해 먼저 인가 서버에서 인증을 받은 다음 엑세스 카드 (토큰)을 받는다. 사용자는 액세스 카드를 사용하여 리소스 서버의 특정 영역 (리소스)에만 액세스할 수 있다.
2.1 불투명 (Opaque) 토큰 사용
불투명 토큰은 백앤드가 사용자나 클라이언트를 식별하거나 인가 규칙을 적용하는데 필요한 데이터를 포함하지 않는다. 이 토큰은 단순히 인증 시도의 증거에 불과하다. 리소스 서버가 불투명 토큰을 받으면, 이 토큰의 유효성을 확인하고 인가 규칙을 적용하기 위해 인가 서버에 추가적인 호출을 해야한다.
불투명 토큰은 금고의 열쇠와 같다. 토큰 자체에는 아무론 정보가 담겨 있지 않으며, 유효성 검증을 통해서만 실제 정보를 알 수 있다. 유효하다는 것이 확인되면, 금고 (사용자 및 클라이언트)에 접근할 수 있게 된다.
리소스 서버는 권한 부여 서버에서 제공하는 엔드포인트를 호출하여 불투명 토근이 유효한지를 확인하고, 토큰이 발급된 클라이언트와 사용자에 대한 필요한 세부 정보를 가져온다. 이 호출을 내부 검사 호출이라고 한다. 리소스 서버는 권한 부여 서버로부터 받은 세부 정보를 바탕으로 인가 규칙을 적용하고, 요청에 대한 액세스 권한을 결정한다.
내부 검사 호출은 리소스 서버가 인가 서버에 요청을 보내여 불투명 토근이 유효한지와 해당 토큰이 발급된 대상에 대한 세부 정보를 확인한다.
2.2 투명 (non-opaque) 토근 사용
투명 토큰은 인가 서버가 인증 프로세스 중에 발급한 클라이언트와 사용자에 대한 정보를 포함하고 있다. 이러한 토큰 서명된 문서와 비교할 수 있으며, 토큰 자체에서 정보를 확인할 수 있다. 리소스 서버가 별도로 인가 서버를 호출할 필요 없이, 토큰을 검증하고 즉시 사용자와 클라이언트에 대한 세부 정보를 얻을 수 있다.
투명 토큰은 서명된 문서와 같다. 이는 리소스 서버가 인가 규칙을 적용하기 위해 필요한 세부 정보와 토큰의 유효성을 확인하기 위한 서명을 포함한다.
투명 토큰의 가장 일반적인 구현은 JWT (JSON Web Token)이다. JWT는 3가지 부분으로 구성된다.
- 헤더(Header): 일반적으로 토큰에 대한 데이터를 포함하며, 토큰을 서명하는데 사용된 암호화 알고리즘이나 인가 서버가 토큰을 서명하는 데 사용한 키 식별자와 같은 정보가 포함된다.
- 바디(Body): 일반적으로 토큰이 발급된 개체에 대한 데이터를 포함하며, 클라이언트 및 사용자 세부 정보와 같은 내용이 포함된다.
- 서명(Signature): 토큰이 실제로 인가 서버에서 발급되었음을 증명하고, 토큰이 생성된 후에 헤더나 바디의 내용이 변경되지 않았음을 증명하는 데 사용되는 암호화된 값이다.
헤더와 바디에 포함된 데이터는 JSON (JavaScript Object Notation) 형식으로 구성되며, 이후 Base64로 인코딩되어 크기를 줄이고 전송을 더 용이하게 한다. 세 부분은 점으로 구분된다.
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6I // 예시
투명 토큰은 오늘날 가장 일반적으로 사용되며, 내부 검사 없이 즉시 유효성을 검증할 수 있다. 하지만 이 토큰은 데이터를 포함하고 있어 클라이언트가 이 데이터를 백엔드로 전송한다. 이로 인해 토큰을 획득한 사람은 해당 데이터를 볼 수 있게 된다. 대부분의 경우 이는 문제되지 않지만, 토큰에 많은 데이터나 민감한 정보가 포함되면 보안에 위험이 있을 수 있다.
따라서 데이터 양이 많거나 민감한 정보가 포함될 때는 불투명 토큰을 사용하는 것이 더 안전한 선택이 될 수 있다. 불투명 토큰은 실제 데이터를 포함하지 않고, 오직 인증의 증거 역할만 하므로 민감한 정보를 보호할 수 잇다. 처음에는 불투명하지 않는 토큰을 사용하는 것이 일반적이며, 데이터의 양이 많거나 민감한 정보를 포함할 때만 불투명 토큰으로 변경하는 것이 좋다.
2.3 다양한 권한 부여 통한 토큰 획득
부여 유형은 클라이언트가 토큰을 얻는 과정이다.
2.3.1 인가 코드 부여형으로 토큰 획득
인가 코드 부여 유형은 오늘날 가장 많이 사용되는 부여이다. 이 유형은 우리 앱이 사용자를 인증해야 할 때 사용된다.
순서는 아래와 같다.
- 사용자는 앱에서 특정 작업을 수행하려고 한다.
- 앱은 클라이언트 역할을 한다. 현재 사용자는 로그인하지 않은 상태이므로 앱은 사용자를 인가 서버가 제공하는 로그인 페이지로 리디렉션한다.
- 이제 사용자는 브라우저에서 로그인 페이지를 볼 수 있다. 이 페이지는 사용자가 접속한 앱이 아닌 별도의 시스템에서 호스팅되고 있다. 사용자는 이 리디렉션된 페이지가 회사에서 사용하는 중앙 인증 애플리케이션임을 인식한다. 사용자는 자신의 자격 증명을 입력한 후, 브라우저가 청구서 애플리케이션으로 돌아가 데이터를 확인할 수 있음을 알고 있다. 사용자는 올바른 자격 증명을 입력한 후 로그인 버튼을 클릭한다.
- 사용자가 제공한 자격 증명이 올바르다면, 인가 서버는 초기 애플리케이션(클라이언트)으로 다시 리디렉션한다. 이 과정에서 인가 서버는 초기 애플리케이션에 인가 코드라는 고유한 코드를 제공한다. 클라이언트는 이 코드를 사용해 액세스 토큰을 요청하게 된다.
- 클라이언트는 인가 서버에 액세스 토큰을 요청한다. 클라이언트는 이 액세스 토큰이 필요하다. 클라이언트가 리소스 서버(백엔드)에 요청을 보내 인가를 받으려면 액세스 토큰이 필수다.
- 클라이언트가 제공한 인가 코드가 유효하다면, 인가 서버는 이에 대한 응답으로 액세스 토큰을 반환한다.
- 클라이언트 앱은 발급받은 액세스 토큰을 사용해 리소스 서버에 요청을 보낸다. 리소스 서버는 토큰을 확인한 후 요청에 대해 인가를 부여한다.
인가 서버는 클라이언트에게 인가 코드를 제공하며, 클라이언트는 이 인가 코드를 사용하여 액세스 토큰을 가져올 수 있다. 클라이언트는 액세스 토큰을 사용하여 리로스 서버에게 요청을 인가할 수 있다.
- 브라우저에서의 리디렉션은 실제 요청이나 응답을 나타내는 것은 아니다. 2단계에서 클라이언트 앱은 사용자를 인가 서버 로그인 페이지로 리디렉션한다. 4단계에서 인가 서버는 일반적으로 쿼리 파라미로 인가 코드를 제공하면서 클라이언트 앱으로 리디렉션한다.
- 사용자는 4~7단계까지를 알지 못한다. 로그인 한 후에는 결국 클라이언트에 의해 승인된 후 7단계 응답으로 인해 송장 (invoke)이 표시된다.
- 인가 코드와 액세스 토큰을 혼동하면 안된다. 액세스 토큰은 클라이언트가 최종적으로 백엔드에 승인을 받기 위해 필요한 것이다 (7단계). 그러나 액세스 토큰을 얻기 위해 클라이언트는 먼저 액세스 토큰을 얻기 위해 사용할 인가 코드를 얻는다 (4단계).
인가 서버가 인가 코드 대신 바로 액세스 토큰을 제공하는 방식을 암시적 부여 유형이라고 한다. 그러나 이 방식은 현재 사용이 권장되지 않는다. 그 이유는 리디렉션 과정에서 보안 취약점이 발생할 가능성이 높기 때문이다. 악의적인 사용자는 리디렉션 요청을 가로채어 액세스 토큰을 쉽게 탈취할 수 있다.
반면, 인가 코드 방식을 사용하면 보안이 강화된다. 인가 서버가 액세스 토큰 대신 인가 코드를 반환하기 때문에, 클라이언트는 이 코드를 사용해 다시 인가 서버에 요청을 보내야 한다. 이 요청에서 클라이언트는 추가적으로 자격 증명을 인증해야 하며, 이를 통해 인가 서버로부터 액세스 토큰을 받을 수 있다.
따라서, 설령 리디렉션을 가로채고 인가 코드를 획득한다 하더라도, 이 정보만으로는 액세스 토큰을 얻을 수 없다. 액세스 토큰을 발급받으려면 클라이언트 자격 증명을 함께 알아야 하므로, 보안성이 크게 향상된다.
이 요청을 보낼 때 클라이언트는 자신의 자격 증명을 사용해 인증해야 한다. 이로 인해 액세스 토큰을 탈취하려는 공격자가 더 큰 어려움에 직면하게 된다. 단순히 인가 코드를 가로채는 것만으로는 충분하지 않으며, 클라이언트 자격 증명까지 알아야 하기 때문이다. 이러한 추가적인 인증 단계는 보안을 강화하고, 액세스 토큰 도난의 위험을 효과적으로 줄여준다.
2.3.2 인증 코드 부여 유형에 PKCE 보호 적용
나쁜 의도를 가진 개인이 클라이언트 자격 증명 까지 훔치게 되면, 액세스 토큰을 획득하고 리소스 서버에 요청을 보낼 수 있다. 이런 상황을 방지하기 위해 코드 교환을 위한 증명 키 (PKCE)라는 기능이 도입되었다. PKCE는 인가 코드 플로우를 더 안전하게 개선하며, 특히 공개 클라이언트 (모바일 앱, SPA 등)가 자격 증명을 안전하게 저장하기 어려운 경우에 유용하다.
PKCE는 인가 코드 부여 유형의 일부 단계를 강화하는데, 두 가지 핵심 개념인 검증자 (verifier)와 챌린지 (challenge)를 사용한다.
- 검증자 생성: 클라이언트는 무작위 값 (임의 바이트 문자열)을 생성한다. 이 값을 검증자라고 한다.
- 챌린지 생성: 검증자에 해시 함수 (일반적으로 SHA-256)를 적용한다. 해시 함수는 단방향 암호화 함수로, 입력 값으로부터 출력을 쉽게 생성할 수 있지만, 출력을 통해 입력값을 역추적할 수 없다.
이제 클라이언트틑 챌린지를 인가 서버로 보내고, 나중에 토큰을 요청할 때 검증자를 함꼐 제출한다. 인가 서버는 받은 검증자에 동일한 해시 함수를 적용해 챌린지와 일치하는지 확인함으로써 요청의 무결성을 보장한다.
PKCE는 특히 공개 클라이언트에서 유용하며, 인가 코드 플로우를 보다 안전하게 만들어준다.
클라이언트는 사용자 로그인과 함께 챌린지를 보낸다. 이때, 인가 서버는 챌린지를 보관하고 클라이언트가 액세스 토큰을 요청할 때 검증자 값을 제공할 것을 기대한다.
클라이언트가 이후 액세스 토큰을 요청할 때 검증자를 전송하면, 인가 서버는 보관 중이던 챌린지와 검증자를 비교한다. 검증자가 챌린지와 일치하면, 인가 서버는 액세스 토큰을 발급한다.
이 방식에서는 인가 코드가 가로채여도 액세스 토큰을 얻을 수 없다. 그 이유는 검증자 값을 알아야 하기 때문이다. 클라이언트는 아직 검증자를 전송하지 않았으므로, 검증자 값을 가로챌 방법이 없다. 또한, 챌린지를 가로챘다고 해도 검증자를 알아낼 수 없다. 이는 챌린지가 해시 함수로 생성되었기 때문에, 결과 값을 입력 값으로 되돌릴 수 없기 때문이다.
2.3.3 클라이언트 자격 증명 부여 유형으로 토큰 가져오기
가끔 앱이 사용자 개입 없이 인가를 받아야 할 때가 있다. 사용자가 없는 경우 앱은 **클라이언트 인가 유형(client credentials grant type)**을 사용해 액세스 토큰을 얻는다. 이러한 상황은 예정된 프로세스나 타이머 같은 이벤트로 인해 한 서비스가 다른 서비스를 호출해야 할 때 일반적으로 발생한다.
클라이언트 인가 유형에서는 앱이 자신의 클라이언트 자격 증명으로 인증을 수행하면 된다.
- 앱은 인가 서버에 액세스 토큰을 요청한다. 이때 자신의 자격 증명을 사용하여 인증한다.
- 자격 증명이 유효하면, 인가 서버가 액세스 토큰을 발급한다.
- 앱은 발급받은 액세스 토큰을 사용해 리소스 서버에 요청을 보내며 인가를 받는다.
2.3.4 리프레시 토큰을 사용하여 새 액세스 토큰 얻기
토큰은 비교적 짧은 수명을 가져야 한다. 일반적으로 15분 정도로 짧으며, 한 시간 이상 지속되는 토큰은 드물다. 모든 토큰은 만료되며, 만료된 토큰은 리소스 서버에서 더 이상 허용되지 않는다.
만약 클라이언트가 만료된 토큰을 가지고 있다면, 두 가지 옵션이 있다
- 그랜트 유형 단계를 반복하여 새 액세스 토큰을 얻는다. 이 경우, 사용자에게 다시 로그인을 요청해야 한다.
- 리프레시 토큰을 사용하여 새 액세스 토큰을 얻는다.
리프레시 토큰은 사용자가 로그인해야 하는 권한 부여 코드와 같은 부여 유형을 사용하는 경우에 유용하다. 예를 들어, 15분 동안 유효한 액세스 토큰이 있다고 가정해보자. 매번 15분마다 다시 로그인하라는 메시지를 받는 것은 사용자에게 매우 불편할 것이다. 대신, 앱은 액세스 토큰이 만료될 때마다 사용자에게 다시 로그인을 요청하는 대신 리프레시 토큰을 사용하여 새 액세스 토큰을 얻을 수 있다.
리프레시 토큰을 사용하는 과정은 아래와 같다.
- 사용자가 데이터를 얻으려고 시도하면, 이는 클라이언트가 자체 백엔드를 호출해야 함을 의미한다.
- 액세스 토큰이 만료되었으므로 클라이언트는 새 액세스 토큰을 받아야 한다. 클라이언트는 이전에 인증한 사용자임을 증명하기 위해 리프레시 토큰을 보낸다.
- 인가 서버는 리프레시 토큰을 인식하고 클라이언트에게 새 액세스 토큰을 제공한다.
- 클라이언트는 백엔드 (리소스 서버)를 호출하여 새 액세스 토큰으로 인증을 받을 수 있다.
클라이언트 앱은 이전에 얻은 액세스 토큰이 만료되면 리프레시 토큰을 사용하여 새 액세스 토큰을 얻을 수 있다. 이렇게 함으로써 앱은 사용자에게 다시 인증을 요청하는 것을 피할 수 있다.
2.4 OpenID Conncet가 OAuth2에 제공하는 이점
OpenID Connect (OIDC)는 OAuth 2 사양을 기반으로 구축된 프로토콜이다. 이는 전 세계적으로 전기 콘센트의 형태가 다르지만 결국 동일한 방식으로 작동하는 전기 시스템과 유사하다. 여행할 때 서로 다른 지역 간에 디바이스를 충전할 수 있도록 어댑터가 필요할 수 있듯이, 두 앱이 OAuth 2 명세를 준수하더라도 호환되지 않는 상황이 발생할 수 있다. 이를 해결하기 위해 OpenID Connect는 OAuth 2 명세를 기반으로 몇 가지 주요 변경 사항을 도입한다. 주요 변경 사항은 다음과 같다.
- 스코프에 대한 특정 값 (프로필 또는 openid).
- 사용자와 클라이언트에 대한 ID 토큰이라는 추가 토큰 사용으로 발급된 토큰에 대한 ID 토큰의 세부 정보 저장.
- 일반적으로 OIDC를 사용할 때 그랜트 타입을 플로우로 참조하며 인가 서버는 일반적으로 "Identity provider(아이덴티티 제공자)" 또는 IdP로 불린다.
2.5 OAuth2의 취약점
OAuth 2를 사용할 때 발생할 수 있는 문제를 이해하는 것은 애플리케이션 개발에서 중요한 부분이다. OAuth 2는 강력한 인증 및 인가 프로토콜이지만, 절대로 완벽하지 않다. 개발자가 이를 사용할 때 인식해야 할 몇 가지 취약점이 있다. 예를 들어, 토큰 탈취, 리디렉션 공격, 세션 하이재킹, 불완전한 구현 등 다양한 보안 취약점이 존재한다. 이러한 취약점을 잘 이해하고, 이를 예방할 수 있는 방법을 채택하는 것이 중요하다.
- 클라이언트에서 Cross-Site Request Forgery (CSRF)를 사용하는 경우: 사용자가 로그인한 상태에서, 애플리케이션이 CSRF 보호 메커니즘을 적용하지 않으면 CSRF가 발생할 수 있다.
- 클라이언트 자격 증명 탈취: 자격 증명을 보호하지 않고 저장하거나 전송하는 것은 공격자가 이를 탈취하고 사용할 수 있는 침해를 초래할 수 있다.
- 토큰 재생: 토큰은 OAuth 2 인증 및 인가 아키텍처 내에서 리소스에 액세스하는 데 사용되는 키이다. 토큰을 네트워크를 통해 전송하고 때로는 가로채질 수 있다. 만약 가로채진다면, 토큰이 도난당하고 재사용될 수 있다.
- 토큰 탈취: 인증 과정에 개입하여 리소스에 액세스할 수 있는 토큰을 도용하는 것이다. 이는 새로운 액세스 토큰을 얻기 위해 가로채어 사용할 수 있는 새로 고침 토큰의 잠재적인 취약점이다.
OAuth 2는 자체적으로 프레임워크이며, 취약점은 주로 이를 잘못 구현했을 때 발생한다. 예를 들어, OAuth 2의 핵심 개념인 토큰 관리, 인증 흐름, 리디렉션 등을 제대로 설정하지 않으면 보안 문제를 초래할 수 있다. 그러나 Spring Security와 같은 잘 설계된 보안 프레임워크를 사용하면 대부분의 취약점을 효과적으로 완화할 수 있다. Spring Security는 OAuth 2 구현을 위한 다양한 기능과 기본적인 보안 흐름을 제공하므로, 개발자는 구성을 적절히 설정하여 보안을 강화할 수 있다.
따라서 Spring Security를 사용하면 OAuth 2의 복잡한 인증 및 인가 흐름을 자동으로 처리하면서도, 추가적인 보안 설정을 통해 위험 요소를 최소화할 수 있다.
'Spring Boot > Spring Security' 카테고리의 다른 글
CORS (Cross Origin Resource Sharing) (0) | 2024.11.01 |
---|---|
CSRF 보호 (1) | 2024.11.01 |
Jason Web Token (0) | 2024.11.01 |