头图

Hello everyone, I am a laboratory researcher in this issue-wait for it to get dark. Today our research object is the OAuth extended protocol PKCE. In the OAuth 2.1 draft, the authorization model of Authorization Code + PKCE is recommended. Why is PKCE so important? Next, let us go to the laboratory to find out!

image.png

Foreword

The full name of PKCE is Proof Key for Code Exchange. It was released in 2015. It is an extended protocol at the core of OAuth 2.0, so it can be used in conjunction with existing authorization modes, such as Authorization Code + PKCE. This is also the best practice. PKCE was originally Created for mobile device applications and local applications, mainly to reduce the authorization code interception attacks of public clients.

In the latest OAuth 2.1 specification (draft), it is recommended that all clients use PKCE, not just the public client, and the Implicit and Password modes are removed. What about the clients that used these two modes before? ? Yes, you can now try to use the authorization mode of Authorization Code + PKCE. So why does PKCE have this magic? In fact is that the client provides a self-created certificate to the authorization server, and the authorization server verifies the client through it, and issues the access token (access_token) to the real client. Instead of the fake .

Client type

As mentioned above, PKCE is mainly to reduce the authorization code interception attacks of public clients, so it is necessary to introduce the next two client types.

OAuth 2.0 core specification defines two client types , confidential, and public. The way to distinguish between these two types is to determine whether the client has the ability to maintain its own confidentiality credential client_secret.

  • confidential
    For an ordinary web site, although the user can access the front-end page, the data comes from the back-end api service of the server. The front-end just obtains the authorization code code, and the step of exchanging the code for access_token is done in the back-end api. It is an internal server. The client has the ability to maintain password or key information. This is a confidential client.
  • public
    The client itself does not have the ability to save key information, such as desktop software, mobile apps, and single-page programs (SPA). Because these applications are published, there is actually no security at all. Malicious attackers can use decompilation and other means. View the client's key, which is a public client.

In the OAuth 2.0 authorization code mode (Authorization Code), when the client obtains the access token (access_token) from the authorization server through the authorization code code, it also needs to carry the client secret (client_secret) in the request, and the authorization server performs Verification, to ensure that access_token is issued to a legitimate client. For public clients, there is a risk of key leakage. Therefore, the authorization code mode of conventional OAuth 2.0 cannot be used. Therefore, the client_secret cannot be used. The scene, derived from Implicit implicit mode, this mode is not safe from the beginning. After a period of time, the PKCE extended protocol was launched to solve the authorization security problem of public clients.

authorization code interception attack

e7aa9581c7f49ece5c8511eedadd6ff1.png

The above is a complete process model OAuth 2.0 authorization code, authorization code block attacks that figure C step occurs, that is, when the authorization server returns an authorization code to the client, so many steps C step Why is it unsafe ? In the OAuth 2.0 core specification, the anthorize endpoint and token endpoint of the authorization server must be protected by TLS (Secure Transport Layer Protocol), but when the authorization server carries the authorization code code back to the callback address of the client, it may not be affected by TLS Protection, malicious programs can intercept the authorization code code in this process. After getting the code, the next step is to exchange the code for the access token access_token to the authorization server. For confidential clients, the client’s secret is required when requesting access_token. The key is client_secret, and the key is stored on the back-end server, so it is useless for malicious programs to obtain the authorization code code through interception. For public clients (mobile apps, desktop apps), they have no ability to protect client_secret, because You can get the client_secret by decompilation and other means, and you can exchange the authorization code for access_token. At this point, the malicious application can request the resource server with the token.

State parameter, in the OAuth 2.0 core protocol, in the step of exchanging token by code, it is recommended to use the state parameter to associate the request and response to prevent cross-site request forgery-CSRF attacks, but state does not prevent the authorization code interception attack above , Because the request and response were not forged, but the authorization code of the response was intercepted by a malicious program.

PKCE protocol flow

4a27490a5e673f9068291e269b7efeab.png

The PKCE protocol itself is an extension of OAuth 2.0. It is basically the same as the previous authorization code process. The difference is that when requesting the authorize endpoint of the authorization server, additional code_challenge and code_challenge_method are required. When requesting the token endpoint, Additional code_verifier parameters are required. Finally, the authorization server will compare and verify these three parameters and issue a token after passing.

code_verifier

For each OAuth authorization request, the client will first create a code verifier code_verifier, which is a high-entropy encrypted random string, using URI unreserved characters (Unreserved characters), range [A-Z] / [a-z] / [0-9] / "-" / "." / "_" / "~" , because it is not reserved
Characters do not need to be URL-encoded when they are transmitted, and the minimum length of code_verifier is 43, and the maximum is 128. It is difficult to guess if code_verifier has enough entropy.

The extended Backus Normal Form (ABNF) of code_verifier is as follows:

code-verifier = 43*128unreserved
unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
ALPHA = %x41-5A / %x61-7A
DIGIT = %x30-39

Simple point that is in [A-Z] / [a-z] / [0-9] / "-" / "." / "_" / "~" the range, generates a random string of bits 43-128.

javascript example

// Required: Node.js crypto module
// https://nodejs.org/api/crypto.html#crypto_crypto
function base64URLEncode(str) {
    return str.toString('base64')
        .replace(/\+/g, '-')
        .replace(/\//g, '_')
        .replace(/=/g, '');
}
var verifier = base64URLEncode(crypto.randomBytes(32));

java example

// Required: Apache Commons Codec
// https://commons.apache.org/proper/commons-codec/
// Import the Base64 class.
// import org.apache.commons.codec.binary.Base64;
SecureRandom sr = new SecureRandom();
byte[] code = new byte[32];
sr.nextBytes(code);
String verifier = Base64.getUrlEncoder().withoutPadding().encodeToString(code);

c# example


public static string randomDataBase64url(int length)
{
    RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
    byte[] bytes = new byte[length];
    rng.GetBytes(bytes);
    return base64urlencodeNoPadding(bytes);
}

public static string base64urlencodeNoPadding(byte[] buffer)
{
    string base64 = Convert.ToBase64String(buffer);
    base64 = base64.Replace("+", "-");
    base64 = base64.Replace("/", "_");
    base64 = base64.Replace("=", "");
    return base64;
}

string code_verifier = randomDataBase64url(32);

code_challenge_method

The method of converting code_verifier, this parameter will be passed to the authorization server, and the authorization server will remember this parameter, and compare it when issuing the token, code_challenge == code_challenge_method(code_verifier) , if they are consistent, the token will be issued.

The code_challenge_method can be set to plain (original value) or S256 (sha256 hash).

code_challenge

Use code_challenge_method to convert code_verifier to get code_challenge, you can use the following method to convert

  • plain
    code_challenge = code_verifier
  • S256
    code_challenge = BASE64URL-ENCODE(SHA256(ASCII(code_verifier)))

The client should first consider using S256 for conversion. If it does not support it, then use plain. At this time, the values of code_challenge and code_verifier are equal.

javascript example

// Required: Node.js crypto module
// https://nodejs.org/api/crypto.html#crypto_crypto
function sha256(buffer) {
    return crypto.createHash('sha256').update(buffer).digest();
}
var challenge = base64URLEncode(sha256(verifier));

java example

// Dependency: Apache Commons Codec
// https://commons.apache.org/proper/commons-codec/
// Import the Base64 class.
// import org.apache.commons.codec.binary.Base64;
byte[] bytes = verifier.getBytes("US-ASCII");
MessageDigest md = MessageDigest.getInstance("SHA-256");
md.update(bytes, 0, bytes.length);
byte[] digest = md.digest();
String challenge = Base64.encodeBase64URLSafeString(digest);

C# Example

public static string base64urlencodeNoPadding(byte[] buffer)
{
    string base64 = Convert.ToBase64String(buffer);
    base64 = base64.Replace("+", "-");
    base64 = base64.Replace("/", "_");
    base64 = base64.Replace("=", "");
    return base64;
}
[InternetShortcut]
URL=https://segmentfault.com/a/1190000041093435/edit###

string code_challenge = base64urlencodeNoPadding(sha256(code_verifier));

principle analysis

We mentioned the authorization code interception attack above. It means that in the entire authorization process, you only need to intercept the authorization code code that is called back from the authorization server to the client, and then you can go to the authorization server to apply for a token, because the client is public. Even if there is a key client_secret, it is useless. After the malicious program gets the access token, it can openly request the resource server.

PKCE do it ? Since the fixed client_secret is insecure, a random key (code_verifier) is generated every time a request is made. When the first request is made to the authorize endpoint of the authorization server, the code_challenge and code_challenge_method are carried. That is, the converted value and conversion method of code_verifier. Then the authorization server needs to cache these two parameters. When the second request to the token endpoint, it carries the original value of the generated random key (code_verifier), and then the authorization server uses the following The method to verify:

  • plain
    code_challenge = code_verifier
  • S256
    code_challenge = BASE64URL-ENCODE(SHA256(ASCII(code_verifier)))

The token is issued after passing, how should the two requests to the authorization server authorize endpoint and token endpoint be related? The authorization code code is enough, so even if the malicious program intercepts the authorization code code, but there is no code_verifier, It is also impossible to obtain an access token. Of course, PKCE can also be used on a confidential client, that is, the dual key of client_secret + code_verifier.

Finally, look at an example of request parameters:

GET /oauth2/authorize 
https://www.authorization-server.com/oauth2/authorize?
response_type=code
&client_id=s6BhdRkqt3
&scope=user
&state=8b815ab1d177f5c8e 
&redirect_uri=https://www.client.com/callback
&code_challenge_method=S256 
&code_challenge=FWOeBX6Qw_krhUE2M0lOIH3jcxaZzfs5J4jtai5hOX4
POST /oauth2/token  
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded

https://www.authorization-server.com/oauth2/token?
grant_type=authorization_code
&code=d8c2afe6ecca004eb4bd7024
&redirect_uri=https://www.client.com/callback
&code_verifier=2D9RWc5iTdtejle7GTMzQ9Mg15InNmqk3GZL-Hg5Iz0

Use Postman below to demonstrate the authorization process using PKCE mode.

b374ed09db42c6e3239a473d89403f63.jpg

Reference

Microsoft Most Valuable Professional (MVP)

bc93fde364ea9dd3d9106b58e805b770.png

Microsoft's Most Valuable Expert is a global award granted by Microsoft to third-party technology professionals. For 28 years, technology community leaders around the world have won this award for sharing their expertise and experience in online and offline technology communities.

MVP is a team of experts who have been carefully selected. They represent the most skilled and intelligent people, and they are experts who have great enthusiasm for the community and are willing to help others. MVP is committed to helping others through speeches, forum questions and answers, creating websites, writing blogs, sharing videos, open source projects, organizing conferences, etc., and to help users in the Microsoft technology community use Microsoft technology to the greatest extent.
For more details, please visit the official website:
https://mvp.microsoft.com/zh-cn


Welcome to follow the Microsoft China MSDN subscription account for more latest releases!
image.png


微软技术栈
423 声望996 粉丝

微软技术生态官方平台。予力众生,成就不凡!微软致力于用技术改变世界,助力企业实现数字化转型。