me

Using Fiddler to force a web service to support CORS for debugging

Posted on 12/03/2013

It started with a hybrid native app developer's Declaration of Independence, then came the liberation of HttpOnly cookies, so now we need to deal with the issue of cross domain restrictions that browsers put on XHR because of previous XSS exploitations.

Problem: Debugging in a browser

This post applies to you if:

  1. You are building some sort of native application based on HTML and JavaScript (PhoneGap in my case), where all calls to a backend web service will always be treated as a cross domain request from your XHR code.
  2. You are working with a web service that you don't control, and it doesn't support CORS, which modern browsers use as a policy for allowing cross domain calls.
  3. You have come to terms with this reality and you're using native web libraries on actual devices to do your integration testing, or you're using a mock service in the browser with faked responses
  4. You are no longer able to run and debug your application in a browser with the actual service, and now you feel like you've been tossed back about 20 years in the past of application development and maybe even you've resorted to using console.log for your debugging and feel defeated (I know I did!)

Solution: Proxy FTW!

Surprise, Fiddler is again our proxy tool of choice to help us out.  Instead of repeating all the steps to set up a custom rule from the HttpOnly cookies post here, please go and read that first. Once you use the following code snippet, you should be able to use the Force CORS Response rule as pictured here.

Force CORS Response Fiddler rule

The Fiddler Custom Rule Implementation

Just like in the HttpOnly cookie rule, you should just copy and paste the following code to the bottom of the method, OnBeforeResponse, which should already be in the default rules script.

if (m_ForceCORS &&
        (
            oSession.oRequest.headers.HTTPMethod == "OPTIONS" ||
            oSession.oRequest.headers.Exists("Origin")
        )
)
{                                
    if(!oSession.oResponse.headers.Exists("Access-Control-Allow-Origin"))
        oSession.oResponse.headers.Add("Access-Control-Allow-Origin", "*");
    
    if(!oSession.oResponse.headers.Exists("Access-Control-Allow-Methods"))
        oSession.oResponse.headers.Add("Access-Control-Allow-Methods", "POST, GET, OPTIONS");
    
    if(oSession.oRequest.headers.Exists("Access-Control-Request-Headers"))
    {
        if(!oSession.oResponse.headers.Exists("Access-Control-Allow-Headers"))
            oSession.oResponse.headers.Add(
                "Access-Control-Allow-Headers"
                , oSession.oRequest.headers["Access-Control-Request-Headers"]
            );
    }
    
    if(!oSession.oResponse.headers.Exists("Access-Control-Max-Age"))
        oSession.oResponse.headers.Add("Access-Control-Max-Age", "1728000");
    
    if(!oSession.oResponse.headers.Exists("Access-Control-Allow-Credentials"))
        oSession.oResponse.headers.Add("Access-Control-Allow-Credentials", "true");
    
    oSession.responseCode = 200;
}

Unlike the HttpOnly cookie rule, forcing CORS is a bit more challenging.  There is a chance you may need to tweak this, but I trust this example rule should get you past most of the hurdles of not having adequate documentation for this in the search engine(s).

Happy debugging!

1 comment:

  1. FWIW, creating an AutoResponder rule for METHOD:OPTIONS TARGETURL and an Action value of *CORSPREFLIGHTALLOW will behave very similarly to the code you've written above.

    ReplyDelete