개요
안녕하세요. 이전 포스팅 [OAuth2] OAuth2 개론 - 개요와 Authorization Code Flow을 통해서 OAuth2 개론을 알아보았습니다. OAuth2는 http 기반에서의 인증의 표준으로써 안전하게 토큰을 발급하고 이를 통해서 인증(Authentication)된 유저만 접근할 수 있도록 할 수 있습니다.
하지만 기본 OAuth2는 네이티브 앱 또는 SPA 웹을 사용할 경우 authorization code interception attack을 당할 수 있습니다. 이 공격을 당하면 본인이 아닌 다른 유저가 token을 발급받을 수 있게됩니다. 따라서 이를 방지하기 위해서 OAuth 2.1의 업데이트의 하나로 Proof Key of Code Exchange(PKCE)가 있습니다.
오늘은 이 PKCE에 대해서 알아보는 시간을 가져보도록 하겠습니다.
요약
- OAuth2에서 native App과 SPA에서는 Authorization Code Interception Attack 취약점이 있음
- OAuth2.1에서 이를 해야결하기 위한 방법 출시
- 해당 취약점을 PKCE를 통해서 해결
상세
OAuth2에서의 가능한 공격 방법 (Authorization Code Interception Attack이라는 취약점)
OAuth2에서는 Clint에서 기 정의된 "clinet_id"와 "client_secret"을 Key로 사용합니다. 네이티브 앱은 디컴파일하여 코드를 확인할 수 있습니다. 그리고 SPA의 경우 소스 코드 또한 브라우저에서 모두 들여다 볼 수 있습니다. 이러한 이유로 OAuth2의 경우 Secret 정보를 원하면 확인해볼 수 있기 때문에 실제로 비 인증된 클라이언트로도 인증 시스템을 이용할 수 있습니다.
아래는 이러한 정보를 이용해서 실제 공격 방법인 Authorization Code Interception Attack가 있습니다. 아래에서 해당 flow입니다.
공격을 위해서는 아래의 조건들이 필요합니다. 아래의 4가지 조건이 만족되면 공격자는 공격을 성공할 수 있습니다.즉, 이 상태에서 인증 flow에 대해서 4번의 시퀀스에서 아래와 같이 취약점이 사용될 수 있습니다.
- 악의를 가진 앱이 설치되어 있어야합니다. redirectUrl로 공격자가 원하는 url이 있어야합니다.
- authorization code grant를 OAuth2로 사용중이어야합니다.
- 공격자는 client_id와 client_secret의 정보를 가지고 있어야합니다.
위의 조건은 많지만 불가능한 조건이 아닙니다. 잏후 flow 4번의 인증 코드가 공격 앱에 흘러들어가면 정상적으로 access token을 취득할 수 있습니다. 이후에는 공격용 앱을 통해서 어떠한 사용도 가능하게 됩니다.
PKCE(Proof Key of Code Exchange)란 어떠한 extension인가 ? (방어 방법)
위에서 자세하게 OAuth2에서 일어날 수 있는 Authorization Code Interception Attack에 대해서 알아보았습니다. 그러면 이번에는 이를 방어할 수 있는 PKCE(Proof Key of Code Exchange)에 대해서 자세히 알아보도록 하겠습니다.
PKCE는 OAuth2.1 RFC에 기술되어 있는 내용으로 authorization code grant를 사용할 때 사용할 수 있는 방법입니다.single-page application과 native application에서의 Authorization Code Interception Attack을 방어할 수 있는 방법으로 사용할 수 있고 보안성을 높일 수 있는 방법입니다.
PKCE를 포함한 방법과 flow 정리
PKCE 메커니즘은 간단히 말하면 인증서버에 /authorize 요청에 code_challenge 필드를 추가하고 /token 요청에 code_verifier fields를 추가해서 동일한 어플리케이션에서 요청이 온것이 맞는가를 추가 검증하는 것입니다. 추가된 각 필드는 아래와 같습니다.
- code_verifier : Client Application에서 생성한 random key.
- code_challenge : code_veirifier를 특정한 함수를 통해서 만들어낸 hashing key
- code_challenge_method : code_verifier를 어떻게 code_
즉, code_challenge는 code_veirifier의 값을 code_challenge_method를 통해서 만들어진 hashing key 입니다. AuthZ 서버에서 이 값이 동일한지 확인해서 동일하다면 동일한 클라이언트 어플리케이션에서, 그렇지 않다면 다른 클라이언트 어플리케이션에서 들어온 요청이라고 판별하게 되는것입니다. 그렇다면 실제로 어떻게 돌아가는지 flow를 보도록 하겠습니다.
- 유저가 client application에 접근해서 access_token을 취득하고 싶어합니다.
- client application은 code_verifier를 생성하고 이것을 기 정의된 메서드를 통해서 code_challenge로 변경한 값 또한 생성합니다.
- client application에서 인증 서버의 인증 endpoint로 code_challenge, code_challenge_method, 그리고 기정의된 필드를 함께 요청합니다. (기정이된 필드는 이전 포스팅을 참고)
https://{{인증 서버 주소}}/authorize ?response_type=code &client_id=29352915982374239857 &redirect_uri=https%3A%2F%2Fexample-app.com%2Fcallback &scope=create+delete &state=xcoiv98y2kd22vusuye3kch &code_challenge=$CODE_CHALLENGE &code_challenge_method=$CODE_CHALLENGE_METHOD
- 접근에 대해서 동의를 요구하는 페이지 전송
- 유저가 동의한다는 내용을 전송
- token 발급에 사용할 authorization code 발급.
- code_verifier 값을 기존 token 발급에 사용되는 authorization code 및 다른 값들과 함께 전송
https://{{인증 서버 주소}}/token ?grant_type=authorization_code &authorization_code=$CODE &client_id=29352915982374239857 &client_secret=$CLIENT_SECRET &code_verifier=$CODE_VERIFIER
- 인증 서버에서는 3번 스텝에서 받은 code_challenge 값과 7번 스텝에서 받은 code_verifier를 hashing 한 값이 동일한지 체크하고 동일하다면 정상접근으로 인정.
- access token을 정상 발급
code_verifier와 code_challenge과 위의 flow를 통해서 동일한 App에서 요청이 온것인지에 대한 확인이 가능하며 native app 또는 SPA에서도 Authorization Code Interception Attack에 대한 취약점을 극복할 수 있게됩니다.
참조
- https://cloudentity.com/developers/basics/oauth-grant-types/authorization-code-flow/
- https://cloudentity.com/developers/basics/oauth-extensions/authorization-code-with-pkce/
- https://cloudentity.com/developers/basics/oauth-client-authentication/client-auth-set-to-none-with-pkce/?q=code_verifier
- https://medium.com/@itsinil/oauth-2-1-pkce-%EB%B0%A9%EC%8B%9D-%EC%95%8C%EC%95%84%EB%B3%B4%EA%B8%B0-14500950cdbf
- https://datatracker.ietf.org/doc/html/rfc7636#section-1.1
댓글