Monday, 10 December 2018

Understanding PKCE as a Solution for Interception Attack

The OAuth2 Code Grant flow allows a secure Client be granted access to a protected resource on behalf of the owner. The Client, usually a server side web application, must be able to be trusted so as to mitigate Man In the Middle attacks and interception of the Client key which the Authorization server uses to verify the client's authenticity. For that reason the Code Grant flow, without proof of key, is not suitable for clients which are publicly accessible, such as a browser based Javascript web app or native mobile app.

Browser based apps are driven by an API, the resource server in the OAuth flow, and should carry no state. For this scenario the usual alternative to the Code Grant is the Implicit Grant. The Client is loaded into the browser, is visible to the user or anyone with access to the static content and therefore is redundant. The user is granted a token immediately in exchange for valid credentials as there is no benefit for a code exchange.



The implicit grant is inherently insecure because the authentication response, containing the token, is open to interception, once it is received by the browser. This can then be replayed to the resource server and accepted as a valid request for the protected resource.



The solution to these problems is not to use the Implicit Grant on any public client and instead use the Code Grant with an additional feature called 'Proof of Key for Code Exchange' to mitigate the interception attack problem of exposing the Client publicly. This is similar to the use of a cryptographic nonce in the OpenID implicit authentication request.

PKCE introduces an additional verifier into the process which is present on the initial code request and code exchange transactions. The verifier is a randomly generated encrypted string with a high enough entropy that the probability of guessing it is impossible. The Code Grant flow now goes like this:


  1. The User opens their browser and navigates to the web page, this is redirected, within the browser application to the authorization server, probably the hosted login screen. 
  2. The user enters their credentials and a code verifier value is created and stored in the browser and sent on the authorization request. The auth' server stores the code verifier, validates the user's credentials and returns the code. 
  3. Now the client makes the code exchange, it supplies the code and verifier to the auth' server which checks the verifier against the value originally supplied in 1. The code is exchanged for a token and returned to the client browser application.
  4. The client browser application may now use the token to request the resource.



Any attacker intercepting the code is not in possession of the verifier and therefore cannot exchange it for a token. The verifier can only be used once for each authentication request, so even if it were leaked it couldn't be replayed.