Search code examples
oauth-2.0clientowincredentialsverification

Vulnerabilities when using client credentials and OWIN Middleware OAuth


I've implemented OAuth2 client_credentials flow in our MVC app. Our MVC app is actually the Resource in this scenario. I had much difficulty in securing a sample for this specific use case, since this flow is primarily used for API access, but I did it nonetheless.
I'd like to share some of the implementation details with you to ask for any information regarding vulnerabilities that I may be unaware of. I am in no way a security expert, which is what brought me here.
In .NET Framework 4.5.2 I used the Microsoft.Owin libraries v3.0.1. I know there are newer ways to set up this sort of thing, (.NET Core and IdentityServer4 for example), but as I said I was having difficulty finding a viable sample for this specific use case, so I did the best I could.
I implemented a Provider:

public class ApplicationOAuthProvider : OAuthAuthorizationServerProvider
{
    private ClientService clientService;

    public ApplicationOAuthProvider()
    {
        this.clientService = new ClientService();
    }

    public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
    {
        string clientId;
        string clientSecret;
        context.TryGetFormCredentials(out clientId, out clientSecret);

        if (clientId == "XXXX" && clientSecret == "XXXXX")
        {
            context.Validated(clientId);
        }

        return base.ValidateClientAuthentication(context);
    }

    public override Task GrantClientCredentials(OAuthGrantClientCredentialsContext context)
    {
        var client = clientService.GetClient(context.ClientId);
        var oAuthIdentity = new ClaimsIdentity(context.Options.AuthenticationType);
        oAuthIdentity.AddClaim(new Claim(ClaimTypes.Name, client.ClientName));
        var ticket = new AuthenticationTicket(oAuthIdentity, new AuthenticationProperties());
        context.Validated(ticket);
        //context.OwinContext.Response.Headers.Add("Access-Control-All‌​ow-Origin", new[] { "*" });
        return base.GrantClientCredentials(context);
    }

with the following startup code:

public partial class Startup
{
    public static OAuthAuthorizationServerOptions OAuthOptions { get; private set; }

    static Startup()
    {
        OAuthOptions = new OAuthAuthorizationServerOptions
        {
            TokenEndpointPath = new PathString("/Token"),
            Provider = new ApplicationOAuthProvider(),
            AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(60),
            //AllowInsecureHttp = true,
            AuthenticationMode = AuthenticationMode.Active,

        };
    }

    public void ConfigureAuth(IAppBuilder app)
    {
        app.UseCors(CorsOptions.AllowAll)
            .UseOAuthBearerTokens(OAuthOptions);
        //app.UseOAuthBearerTokens(OAuthOptions);
    }
}

public partial class Startup
{
    public void Configuration(IAppBuilder app)
    {
        app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);

        ConfigureAuth(app);
    }
}    

and then created a Client app that is also a website and eventually gained access to the Resource (MVC app). The Resource has no users, therefore no login screen. The Resource (now) has a token endpoint. The Client app makes a request to the token endpoint with their credentials and, (after being authenticated), then uses that token in subsequent requests to the Resource.
I've found 2 different ways of using this token to gain access.

  • Include the access token in the request header. OR
  • Include the access token as a form parameter

My questions are concerning vulnerabilities to this scenario:
Assuming all communications between the client app and the server are happening over secure channels (https) and the client app is able to maintain the credentials in a secure fashion, what are the chances that an access token could be obtained or intercepted? Or, are there methods included in this flow (or perhaps another OAuth flow) that also include client verification? I realize that the client is already being authenticated via client_id/client_secret, but when I ask about verification, I'm asking about the origin of the request (assuming of course, that the method of verification does not include checking something that can be spoofed by a malicious user).
Is there an additional step of verification that I should be including that I may have missed - because there's alot of information out there and I did my best to scour, but I can't claim that I have a solid understanding of everything I've read so far.
If there is an additional verification step that I have missed, how does that fit into this (client_credentials) flow?

Thanks, Carrie


Solution

  • I've found 2 different ways of using this token to gain access.

    • Include the access token in the request header. OR
    • Include the access token as a form parameter

    This means that your access token is of type Bearer token (therefore, you can also use a third way to send the access token: using GET method with a query parameter).

    what are the chances that an access token could be obtained or intercepted?

    Or, are there methods included in this flow (or perhaps another OAuth flow) that also include client verification?

    You have a Bearer token, thus the RFC-6750 applies. The Threat Mitigation section answers your questions:

    • first, your access token may be disclosed if the version of TLS between your client app and the authorization server (to get the token), and between the client app and the resource server (to give the token), have a security flaw (excerpt: This requires that the communication interaction between the client and the authorization server, as well as the interaction between the client and the resource server, utilize confidentiality and integrity protection. Since TLS is mandatory to implement and to use with this specification, it is the preferred approach for preventing token disclosure via the communication channel.)

    • secondly, another way for your access token to be disclosed is when using a TLS accelerator. As said in the same section of the RFC: In some deployments, including those utilizing load balancers, the TLS connection to the resource server terminates prior to the actual server that provides the resource. This could leave the token unprotected between the front-end server where the TLS connection terminates and the back-end server that provides the resource.

    There are other ways to get the access token disclosed.

    The solution is not to implement another OAuth flow but to apply the recommandations in section 5.3 of the RFC. As a summary, the main recommandations are:

    • always use TLS,
    • validate TLS certificate chains,
    • use token encryption in addition to the usage of TLS protection: for instance, encrypt the token with a shared secret between the client app and the resource server,
    • don't store bearer tokens in cookies,
    • issue short-lived bearer tokens,
    • issue scoped bearer tokens (use audience restriction).

    This is not in the RFC but I would add this recommandation: use mutual authentication. This means that the client app must have a X.509 certificate that must be verified by the resource server. This is possible in the specific Oauth2 flow you have chosen, because the client app is known by the resource server (with some alternative flows, it can not be done).