Category Archives : Security

A general category for security and information system securiity


Getting to know Cross-Origin Resource Sharing (CORS)

Hello there.  I’ve been spending a lot of time of late trying to develop a solution to a very obscure problem scenario.  The entire problem itself is outside the scope of this article – and to be honest, probably wouldn’t be terribly relevant to many – however, I felt there was value in articulating my recent experiences with Cross-Origin Resource Sharing, or CORS for short.

So what is CORS? 

 

To quote from Wikipedia:

Cross-origin resource sharing (CORS) is a mechanism that allows many resources (e.g., fonts, JavaScript, etc.) on a web page to be requested from another domain outside the domain from which the resource originated.[1] In particular, JavaScript’s AJAX calls can use the XMLHttpRequest mechanism.

Such “cross-domain” requests would otherwise be forbidden by web browsers, per the same-origin security policy. CORS defines a way in which the browser and the server can interact to determine whether or not to allow the cross-origin request.[2] It is more useful than only allowing same-origin requests, but it is more secure than simply allowing all such cross-origin requests.”

Now that we’ve cleared that up…  my take – a web site makes use of resources which are hosted on another site outside of its domain.  This is an important distinction owing primarily due to cross-site scripting (XSS) and cross-site request forgery (CSRF) vulnerabilities.

 

What does something like CORS address exactly?

Well, the concept is fairly straightforward.  What CORS aims to do is have two websites (sites, pages, APIs etc.) agree on what kind of resources and types of requests one website will provide to another.  Both must agree exactly on what is being shared and how.

 

How is this accomplished?

There’s a few parties who need to participate to enable CORS – the two parties involved, of course, and the user’s browser.  Both sites need to request and respond to each other in an expected manner, and browsers need to be aware of, and in some cases make special requests to ensure CORS works correctly.

In essence, what happens is that both websites agree on how resources will be shared.  The requesting site must be known as an “allowed origin” by the site providing the resources.  The response also must contain headers which contain scope for acceptable resource sharing, e.g. naming allowable methods (e.g. GET, PUT) and whether credentials are supported.  Browsers themselves are the last key – they must respect the restrictions established by the requesting site and the resource site.

 

What is a “pre-flight request”?

In some cases, a browser might make a special type of request known as an OPTIONS request, which is sort of like an initial handshake before performing the actual request specified (e.g. a GET request). 

In essence, an OPTIONS request attempts to determine what supported methods and other information is available from a resource sharing server.  In browser terms, this is known as a “pre-flight” request and is often attempted automatically by the browser.

The first time a cross-site request might fail (and in subsequent attempts) the browser’s JavaScript console might log something similar to the following error:

XMLHttpRequest cannot load https://<TARGETSERVER>/p?ReadViewEntries&outputformat=json. The request was redirected to ‘https://<ANOTHERSERVER>’, which is disallowed for cross-origin requests that require preflight.

Here’s an example of a browser (Chrome) attempting an OPTIONS pre-flight request and failing:

failed

Let’s take a look at a pre-flight HTTP(S) request example.

Remote Address:<IPADDRESS>:443

Request Headers URL:https://<TARGETSERVER>/p?ReadViewEntries&outputformat=json

Request Method:OPTIONS

Status Code:200 OK

Request Headers

OPTIONS /p?ReadViewEntries&outputformat=json
HTTP/1.1

Host: <TARGETSERVER>

Connection: keep-alive

Access-Control-Request-Method: GET

Origin: https://<ORIGINSERVER>
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.116 Safari/537.36

Access-Control-Request-Headers: accept, content-type

Accept: */*

Referer: https://<ORIGINSERVER>/Home/Test

Accept-Encoding: gzip,deflate,sdch

Accept-Language: en-US,en;q=0.8

Query String Parametersview sourceview URL encoded

ReadViewEntries:

outputformat:json

count:4000

r:0.88333622

charset:utf-8

 

Under normal circumstances, a target server which honours this request would respond with something similar to this:

HTTP/1.1 200 OK

Date: Tue, 11 Nov 2014 03:35:05 GMT

Access-Control-Allow-Origin: https://<ORIGINSERVER>

Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept,Access-Control-Request-Headers,Access-Control-Allow-Methods,Access-Control-Allow-Origin,Access-Control-Allow-Credentials

Access-Control-Allow-Methods: POST, GET, OPTIONS, DELETE, PUT, HEAD

Access-Control-Allow-Credentials: true

Content-Length: 495

Keep-Alive: timeout=10, max=100

Connection: Keep-Alive

Content-Type: text/html; charset=iso-8859-1

 

The most important thing in this response isn’t probably what you’d expect it to be.  It’s actually the HTTP STATUS CODE (i.e. 200).  For CORS pre-flight to work, the resource target must respond with a Status Code of 200 to a HTTP OPTIONS request – and it must do so for unauthenticated requests!

 

Why must the pre-flight/OPTIONS requests be unauthenticated?

It’s actually a requirement direct from the respective W3C specification regarding pre-flight requests:

Otherwise, make a preflight request. Fetch the request URL from origin source origin with the manual redirect flag and the block cookies flag set, using the method OPTIONS, and with the following additional constraints:

[1] https://dvcs.w3.org/hg/cors/raw-file/tip/Overview.html#preflight-request

Therefore, a response status code of 302 (Found – Redirect, usually to authenticate) or 401 (unauthorised) will clearly fail pre-flight.  Note that the resource (target) server doesn’t have to honour all OPTIONS requests, you could lock down the server’s security to only respond (Status 200) to requests on certain paths, for example.

In the example screenshot earlier, the pre-flight was failing because the resource server had authentication enabled for the OPTIONS request, and it was redirecting to a security token service (STS) for authentication.

 

Now that that’s all cleared up, how about some sample code? 

Here’s a pretty straightforward request which sets the appropriate header values for cross-domain and with credentials for a GET request, which is expecting a JSON response:

var aQuery = function()

{

     var url = ‘https://<TARGETSERVER>/p?ReadViewEntries&outputformat=json';

    
$.ajax(url, {

            type: “GET”,

            contentType: “application/json; charset=utf-8″,

            success: function(data, status, xhr) {

                alert(data);

            },

            xhrFields: {

                withCredentials: true

            },

            crossDomain: true

        });

}

In many cases though, this is not enough.  Some browsers, particularly older versions for example Internet Explorer 8 and 9 simply don’t support CORS well enough.  A more version sensitive approach might be something like this:

var basicQuery = function ()

{    

      var url = ‘https://<TARGETSERVER>/p?ReadViewEntries&outputformat=json';

      var method = ‘GET';

      var xhr = new XMLHttpRequest();

       

      if (“withCredentials” in xhr) {           

           // Most browsers.       

            xhr.open(method, url, true);

            xhr.setRequestHeader(“Access-Control-Allow-Origin”, “https://<ORIGINSERVER>)”);

            xhr.setRequestHeader(“Access-Control-Allow-Credentials”, “true”);

            xhr.setRequestHeader(“Access-Control-Allow-Methods”, “GET”);

      } else if (typeof XDomainRequest != “undefined”) {

                 // IE8 & IE9      

           xhr = new XDomainRequest();

           xhr.open(method, url);

      } else {

           // CORS not supported.

           xhr = null;

      }

 

      if (xhr != null)

      {                

            xhr.followsRedirect=false;          

            xhr.withCredentials=true;

 

            xhr.onreadystatechange  = function() {

                  if(xhr.readyState==4)

                  {

                        if(xhr.status == 200)

                        {

                              alert(xhr.responseText);                 

                        }

                        else

                        {

                              alert(“error”);

                        }

                  }

            }

            xhr.send();

      }

}

 

Finally, let’s see that gratifying successful CORS request:

success

 

Some notes about setting headers

  • CORS header values in a request must be supported on the resource server for a given request to succeed, i.e. for a request which specifies Access-Control-Allow-Credentials, the target server must respond with Access-Control-Allow-Credentials listed in the Access-Control-Allow-Headers. 
  • The same applies to methods, e.g. a GET method must be listed in the response Access-Control-Allow-Methods
  • When you set the Access-Control-Allow-Origin value, it should be the name of the origin server (the origin of the request) it really shouldn’t be asterisk (*) which is often used in sample code.  The target resource server also must recognise/honour the origin.

A lightweight implementation OWIN OAuth for ASP.NET Web Forms using Visual Studio 2013 – Part 3

Introduction

In Part 1, we had a brief look at OWIN/OAuth concepts, and then prepared a clean ASP.NET web forms project for integration with NuGet packages essential to supporting a lightweight integration for OAuth handling.

In Part 2  we established the information required to authenticate users against the Live Connect OAuth provider, and also established a debugging environment; it’s time for the meat of the article.

Finally, this article will demonstrate the code necessary to handle authenticated user identities.  I must stress that this is incredibly lightweight, and hopefully it will be clear what you need to consider if taking this approach to a new or existing project.

Note: This article was originally published at Sanders Technology, check here for updates to this article and related technical articles.

The Concept Applied

Let’s quickly take a look at what you’ll be implementing from a conceptual point of view.  What you’ll be doing is effectively redirecting your users to a third party.  Once they have successfully authenticated, they’ll return to your site (or app) with some sort of token or claim (query string based).

Your site or app will then exchange this information with the third party to validate it is correct and valid.  If this is successful, the third party will share a bit of information about this user with you, which you could use to tie to a local identity if you preferred.

Here’s the concept in diagram form:

image
How the OAuth process works

Armed with this knowledge, there are a few design decisions you’ll need to make.  The most obvious one is planning how you’ll handle those redirects back to your site or application, once a user has authenticated with their OAuth provider (in this article, Microsoft Live Connect/Live Accounts).

In Part 2, I briefly discussed the importance of the Redirect Domain when configuring the Live Application.  This is, in fact, the target URL that your users will be given, once they’ve authenticated.  This can be a basic URI or a specific page.  In any case, the target has to be able to handle the authentication tokens.

Enough theory, show me some code

The code to handle authentication is ridiculously simple and lightweight.  In fact, I’ve encapsulated the logic into a single class.  In my example, I’ve hardcoded the implementation to the Microsoft provider, but I’m positive you could easily write a more generic implementation which accepts multiple OAuth providers.

This class handles the following functionality:

  • Initiate authentication (redirect to oAuth provider)
  • Handle and process authentication result (from redirect URL)
  • Save/store or cache authentication results (for subsequent requests)
  • Return basic user information (if authenticated)
  • Clear or expire authentication details

using DotNetOpenAuth.AspNet; using DotNetOpenAuth.AspNet.Clients; using System; using System.Collections.Generic; using System.Linq; using System.Web; namespace YourNamespace { public static class AuthenticationHelper { /// <summary> /// Determines if a user is presently authenticated /// </summary> /// <returns>True if authenticated, else false</returns> public static bool IsAuthenticated() { var auth = //TODO: Retrieve authentication information from temp local store or cache if (auth != null && auth.IsSuccessful) { //NOTE: Hard coded to the Microsoft provider string userName = OAuthDataProvider.Instance.GetUserNameFromOpenAuth("microsoft",

auth.ProviderUserId); //TODO: verify user id is a valid user return true; } return false; } /// <summary> /// Returns the user name for the currently authenticated user /// </summary> /// <returns></returns> public static string GetUserName() { var auth = //TODO: Retrieve authentication information from temp local store or cache if (auth != null) { return auth.UserName; } return String.Empty; } /// <summary> /// Verifies the authentication from the various OpenId and OAuth services,

///returns generic Authentication Result in res variable. /// </summary> /// <returns>Authentication information (can be null)</</returns> public static AuthenticationResult VerifyAuthentication() { var ms = new MicrosoftClient("<YOUR CLIENT ID>", "<YOUR SECRET KEY>"); var manager = new OpenAuthSecurityManager(new HttpContextWrapper(HttpContext.Current), ms, OAuthDataProvider.Instance); var result = manager.VerifyAuthentication("<YOUR REDIRECT URI>"); if (result != null) { //TODO: Save authentication information to temp local store or cache } return result; } /// <summary> /// Starts the authentication process. User will be redirected away from the current page /// </summary> public static void Authenticate() { var ms = new MicrosoftClient("<YOUR CLIENT ID>", "<YOUR SECRET KEY>"); new OpenAuthSecurityManager(new HttpContextWrapper(HttpContext.Current), ms, OAuthDataProvider.Instance)
.RequestAuthentication("<YOUR REDIRECT URI>"); } /// <summary> /// Used to “unauthenticate” an authenticated user /// </summary> public static void Unauthenticate() { //TODO: Clear authentication information from temp local store or cache } } }

Class diagram views follow:

image
Class diagram view of the Authentication Handler

There is an additional class required to make use of the OpenAuthSecurityManager class – a concrete class which implements the IOpenAuthDataProvider interface.  Luckily, you don’t have much to implement for this to work successfully:

using DotNetOpenAuth.AspNet;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace WebApplication3
{
    public class OAuthDataProvider : IOpenAuthDataProvider
    {
        public readonly static IOpenAuthDataProvider Instance = new OAuthDataProvider();

        public string GetUserNameFromOpenAuth(string openAuthProvider, string openAuthId)
        {
            return openAuthId;
        }
    }
}

As you can see, I don’t even really do anything here, I’m just returning the provider-supplied value.  You could do much more with this, including your own application-specific formatting.

image

Class view of the OAuthDataProvider class

Taking a look at the runtime process

To illustrate how this all works, I’ve updated the “clean” example solution from Part 1.  I must stress, this is a very, very simple implementation, and should in no way be used in a Production website.  It’s simply to illustrate how lightweight the implementation can be.

The sample site has a master page with a simple user control on it.  This control reflects whether a user has authenticated or not, and provides a mechanism for initializing the authentication process (in short: a “login button).

I’ll now show you what the process looks like from a series of screenshots of the working solution.  In this example, I’ve made the modifications mentioned in Part 2, as I have aliased “atempuri.org” to my localhost (for debugging purposes).

I’ve also created a Live Application at the Live Connect site. Remember – you need the Client ID and Secret ID plus have set the correct Redirect URL for this to work.

The Process

To begin, I load the default page on the site.  Notice in the top left hand corner the fairly boring “[ Authenticate ]” button.  When I click the button, it redirects me to the Live Connect page to sign in with a Microsoft (formerly Live, formerly Passport) Account.

image    image
The default page / Authenticate to Microsoft

Once I have authenticated, the Microsoft site asks me to allow my application to access basic account data.

image
The user is prompted to authorise the application

Notice here that I have not supplied an application logo – doesn’t it look ugly and unprofessional?  Once the user clicks the “Yes” button, the Microsoft site redirects the user’s browser to the URI set in the Live Application’s settings – which must match the address specified in the code in your site or application.

In this case, the user’s browser is directed to http://atempuri.org/Login (with additional data in the query string).  My login.aspx page handles the request and checks that the user is not already authenticated.

image
The Login.aspx event hander code

This page forces the “VerifyAuthentication” call, and checks again OnPreRender to see if validation worked or not.  If it is successful, the user is redirected to the default page.

Below is an example of some of the information retrieved with a successful authentication:

image
Successful authentication provides very basic information

The ProviderUserId can be used to uniquely identify the authenticated user, and also provides a “friendly name” which you can use for display purposes.

image
We’ve achieved the Zen like state of “authenticated”

The default page now displays a more friendly user experience, and provides a mechanism for “logging off”.

More on the “TODO” elements of this approach

Again, I can’t stress strongly enough that this is only a simple proof of concept.  I’ve specifically cut corners here to demonstrate how little is needed to implement OAuth support for authentication.

If you look at the sample solution, there are three values you need to supply:

public static class AuthenticationHelper
{
      private const string KEYID = "<YOUR KEY>";
      private const string SECRET = "<YOUR SECRET KEY>";
      private const string REDIRECT = "http(s)://<YOUR REDIRECT URL>";
}

At a minimum you should consider doing the following with your own website or application, up-front:

  • Determine your complete security and identity requirements
  • Decide if you want  to have user profiles “local” to your application, and whether you’ll map these identities to their Provider ID
  • Consider an approach to storing or looking up the authentication data
  • Decide how your site or application should handle:
    • Unauthenticated users
    • Authenticated users
    • The location of your “Redirect URL”
  • Decide if you want to integrate this into the ASP.NET Role Provider
  • Consider using HTTPS/SSL for some or all of your site/application

That’s just a start, this barely scratches the surface.

Summary and Download

Well, I think I’ve managed to cover off all the basics of a lightweight implementation of OAuth (OWIN) using ASP.NET.  To aid you, I’ve attached a copy of the “clean” ASP.NET web forms solution, with the authentication classes and the user control included.  I’ve personally tested the solution with real Application keys and it is working as depicted here.

It’s not a bad start if you are just looking for a very lightweight way to integrate OAuth as a mechanism for identifying users, and could obviously be extended or used to integrate into your existing authentication/authorisation mechanisms.

If you’ve had any issues or have general feedback, shoot me an email: rob.sanders@sanderstechnology.com

Sample Solution


A lightweight implementation OWIN OAuth for ASP.NET Web Forms using Visual Studio 2013 – Part 2 2

Introduction

Where we left off in Part 1, we’d established the prerequisites to prepare either a new or existing web forms project for the implementation of a lightweight OWIN/OAuth provider.

This article, Part 2, will focus on how to prepare your development environment and also how to configure for Windows Live Account authorisation.

This article was first posted on Sanders Technology.  Check the site for updates to this article, and for more excellent technical articles.

Let’s start with the Live Application first:

Configuring the (Microsoft) Live Account Provider

You need to get two API keys in order to use the Microsoft OAuth interface.  To get the keys, you have to configure your application via the Live Connect Developer Center.

The first thing you’ll need is a Microsoft Account.  If you don’t have one, it’s easy enough to create one.  If you do already have an account, you just need to browse to http://msdn.microsoft.com/en-us/live to and sign in.

Click on “My apps” (https://account.live.com/developers/applications) from the menu:

image
Live.com – create application

You’ll want to then click on the “Create application” link, which will bring you to the introduction page.  Here you have to agree to the Ts and Cs and give your application (or website!) a name:

image
Create Windows Live application

Configure your Application

Once you have progressed, the site takes you directly to the API settings.  Notice the Client API key (Client ID) and Client secret key (Client secret) are already populated.  These are the two values you need for your site or application.

The key field you must complete here is the redirect domain.  This URL is critical and must match the endpoint that you wish to authenticate users from. 

The location must be able to handle the credentials returned from the Microsoft Live services.  If you aren’t sure what to use initially, you can come back and add it later.

image
Live application – API settings

If you like to do things properly, you should go to the Basic Information page and upload an application logo. 

When users first authenticate against your site or application they’ll be prompted to agree to share their identity with you. From this page, ensure you have copied the Client ID and the Client secret.

The page asking them to agree will show your application’s logo, so it’s best to have something nice and neat here.

image
Windows Live application – basic info

For completeness, I like to add links to privacy and terms of service policies, which you can do in the two fields provided.  They are optional.

That said, as long as you have the client key and client shared secret key, then you have everything you need for now.  Before you can go integrating Live OAuth, you’ll need to configure your development environment.

Configuring Visual Studio/Development Environment

Before you can integrate OAuth handlers into your solution, you’ll need to configure your environment so that you can debug and also so you can test the authentication process.  This is not as hard as you might suspect, since you have the client key and the shared secret key.

The first thing you’ll need to do is set up an entry in your HOSTS file to redirect your chosen domain to 127.0.0.1.  This means your outbound requests will go to your local host.   For example:

Open Notepad (with elevated permissions) and open the file “HOSTS” (no extension) which lives in sysdrive%:\Windows\System32\Drivers\etc

image
A local HOSTS file configured for contoso.org

image
A ICMP test (ping) showing contoso.org resolving to localhost (127.0.0.1)

IF you want to test out whether it has been set correctly, just jump to a console and try and ping the domain.  You should get responses as shown above.  Next, you need to configure your local development web server.

Configuring your Web Host

For this example, I’ll be configuring IIS Express for the task of hosting my requests.  You can also configure a local IIS service as well, but I’m not going to go into detail – for IIS, it’s a matter of configuring site bindings to add a HOST HEADER value.

IIS Express uses a set of configuration files, and they are conveniently located under your profile’s “My Documents”.  Here’s an example of where to find the applicationhost.config file:

image
Location of the IIS Express applicationhost.config file

Hint: It’s under your local profile’s directory.

Note: that after you have finished this step, you’ll need to launch Visual Studio with elevated permissions, or else IIS Express won’t be able to load your site.

In the file, locate the <sites> element, and then the site you wish to configure.

image

the key here is to add to the bindings collection for the site you are using.  As you can see from the above example, I’ve added contoso.org to the WebSite1 entry.  When IIS Express is launched, this binding will be applied, and since I have modified the HOSTS file, requests to contoso.org will be routed to IIS Express.

I recommend using port 80, as you need to give Live Connect a redirect URL which would work when live.  Naturally you can change URLs both with Live Connect and locally at any time.

Configure the Redirect domain

Now that you’ve gotten this far, you should be able to raise an instance of your site hosted in IIS Express, and the domain you’ve configured should resolve to the local server.  Note that if you are behind a proxy configuration, localhost and the domain should be added to the list of exclusions.

The domain you’re using should be configured appropriately in your Live Application, as mentioned earlier in this article.  The URL should match the URL you wish to authenticate OAuth tokens.  This can be HTTP or HTTPS based.

If you’ve gotten this far, you’re ready to implement the lightweight OWIN OAuth provider.  We’ll pick up on how to proceed in Part 3.

Summary

Apologies to those who have already accomplished the configuration mentioned here – however, I had to cover it off before I launched into the specifics of configuring the application implementation.  The last article in this series, Part 3, will focus entirely on implementing and testing integration with the Live OAuth provider.