Leave my endpoints alone!

By default, LightSwitch apps expose the server tier by one public OData endpoint per data-source. Both the desktop and the HTML client make direct calls to these .svc urls to retrieve the data they need.

So here’s an interesting question I got this afternoon: this means that all data is publicly visible?

Well, yes and no. The endpoints are publicly visible, however when you access them, the LightSwitch (actually asp.Net) framework’s authentication and authorization will kick in to protect the data (authentication determines if you can access the endpoint, authorization determines if you can access that particular entity set and what records you can access).

However, there’s some cases where you want to protect your endpoints even more, for example when you’re forced to build an application without authentication, or if you want to prevent a user with a valid username&pw (or windows credentials) to access the data from outside your own apps.

In that case, you can add a custom IHttpModule. This would include registering the module in your web.config…

  <system.webServer>  
    <modules>
      <add name="CustomHeaderModule" type="StrongNamespace.HttpModules.CustomHeaderModule"/>
    </modules>

and adding whatever code you want to your server project…

using System;
using System.Web;

namespace StrongNamespace.HttpModules
{
    public class CustomHeaderModule : IHttpModule
    {
        public void Init(HttpApplication application)
        {
            application.PostReleaseRequestState += new EventHandler(application_PostReleaseRequestState);
        }

        public void Dispose()
        {
        }

        void application_PostReleaseRequestState(object sender, EventArgs e)
        {
            if (HttpContext.Current.Request.Url.ToString().ToLower().Contains(".svc") 
                && !HttpContext.Current.Request.Url.ToString().ToLower().Contains("authenticationservice.svc")))
            {
                var referrer = HttpContext.Current.Request.UrlReferrer;
                if (referrer == null)
                    throw new Exception("Not allowed to access this data"); 
                else if (referrer.Host != HttpContext.Current.Request.Url.Host)
                    throw new Exception("Not allowed to access this data"); 
            } 
        }
         
    }
}

The above sample will block any calls to the .svc endpoints (your OData endpoints that expose your data) if the call is not made from a site within the same domain.

This hasn’t been production tested yet (and honestly you’ll probably need to customize the business rules a bit) but at first sight seems not to interfere with the LS desktop (OOB or inB) or HTML client, but do blocking any other calls.

It’s not really ‘web-friendly’ either, in production code I’d suggest rewriting the response to a 403-forbidden instead. But then again who gives a fuck about http status codes… (*grabs popcorn*)

 

Keep rocking LS!
Jan

Advertisements

11 thoughts on “Leave my endpoints alone!

    • Haven’t tested that specific scenario yet, but when a LS app is protecting his endpoints with this hack, I was unable to connect using JSFiddle, a custom website, excel, … So I would assume if the other LS app is not hosted on the same domain, it’ll block that too 🙂

  1. Jan,could the UrlReferrer be an issue? I have read that it could be spoofed to contain the needed information? I don’t know, I am not a hacker.
    Also, I read that UrlReferrer can be excluded from the request header. this is no big deal as I can demand that if the base url and “HTTPClient” isn’t right then I can simply reject the request.
    But, I would like to accommodate legitimate users that choose not to include the UrlReferrer.
    I guess I might be forced to just ask my users to always provide the UrlReferrer.

  2. Your blog was very helpful. Maybe it is something I don’t understand, but …
    I sent a bug report/suggestion to Microsoft. I simply asked them to put a flag in so we can tell if this request is from an external request, or a request made internally by the application, or, put an option in the properties for the particular entity that says something like “allow request to this entity from other than the application.
    I also asked them what percentage of LS app developers need to have their data automatically exposed? I have never encountered a situation where data exposure is the rule and not the exception.
    But, I am thinking that LS does this for a reason. even so, they should have a seemless way to protect the data as a default rather than suggest RIA Services, filters, permissions and all that other extra code just to lock down the data..

    • Hey IQWorks,

      actually in any client-server application service exposure is the norm, how else would the client interact with the server? I understands your concerns though, I myself asked to be able to exclude particular entities/properties from the OData (that are only used on the server for example).

      URL Referrer can be easily spoofed using middleware indeed, for a techie it’s not that hard. 😦

      Not sure if there’s a way that’s 100% fail proof… 😦

      • Yea, if the UrlReferrer is the closest you can get, then that’s that. I am investigating tokens in addition to the UrlReferrer..

        Your right about the client/server. I guess I should of said that a light switch user who is authenticated can put in a url something like this “http://www.domain/entity.svc” and see all the records AND fields in of an entity. Somehow, that looks different to me than a hacker getting data access through an ajax call or other techniques that are used to get data from the client. with LS all you need is the entity name. I will adjust my mindset however :-).
        thanks again.

      • Also, the client server apps I have made have the data locked down initially, then you give permissions as needed. with LS, the data is NOT locked down initially, then you have to write code to lock the data down. Something dosnt feel right about that. BUT,
        Like I said, I am adjusting my mind set.:-)

  3. Hi Jan, the approach looks great, but I’m having a hard time testing it. If “referrer == null” the exception is thrown, but somehow the code continues executing, entering the “else if” and returning a Server error 500 (with the message thrown by the exception, of course). I just can’t find a decent way to send a 403 – Forbidden to the browser. Any ideas?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s