Bing Maps Concepts
(formerly Virtual Earth)
Mike Garza   
VEMaps@garzilla.net   

   
Concept: Protecting your Map Key

This is the first article, in hopefully a muti-part series, on how to protect your map key for the Bing Maps AJAX control. With the new release of v7 of the Bing Maps AJAX control, it seems that a map key will now be required in order to implement this control. I mention “seems” as I have had mixed results on with this. In testing v7, some instances would not load without the map key while other instances loaded fine. For the purposes of this article, let’s go with the concept that the map key is required (or there is really no point to this article).

Since the use of this map key is implemented with client side logic (JavaScript), the key essentially needs to be part of the client side JavaScript code. This could pose some risk. Being part of the client side JavaScript code means that anyone who chooses to “view source” of your page or looked at the cached code, could have access to you Bing Maps Key. Your Bing Maps Key is tied to you Bing Maps Developer Account, so you certainly do not want anyone being able to use it. Now you are probably thinking “Mike, when I generated my key, I had to specify the URL for the site that it was being used for. Doesn’t that protect me?”. Good question. Answer: Yes, probably at some point in the future. As of the time of this article, the URL used during the key generation does not seem to be enforced. My guess is that is going to be some sort of future functionality. In testing this code, the page loaded fine regardless of the URL the web page was running under (localhost,garzilla.net, testdomain.com, etc;). Regardless, since this is information is tied to your account, you should make every effort to secure that information.

In this example, we will walk through the first step in securing this information. The main thing to note about this example is that it is specific to ASP.NET. Some future articles will touch on how to secure this in a general fashion, but this one is specific to ASP.NET, so if you are not using this platform, please check back later.

*DISCLAIMER: This code is merely an example of how you can begin to secure this information. This approach is not guaranteed to be 100% secure. In fact, I would be reluctant to use the word “secure”. This example is intended to show how you can begin to protect this information or more specifically, hide this information so that end users cannot easily obtain that data.

Walk Through:

The map on the page was implemented using the Bing Maps AJAX control v7. The implementation of the AJAX control for v7 is somewhat different than in the previous versions of this control. Conceptually this approach should be familiar, but it is syntactically it is different. In v7, the typical approach for instantiating the map uses the following code:

     var map = new Microsoft.Maps.Map(document.getElementById("MapDiv"),
                           { 
                               credentials: "Your Map Key",
                               center: new Microsoft.Maps.Location(41.8756, -87.9956),
                               mapTypeId: Microsoft.Maps.MapTypeId.road,
                               zoom: 7
                           });
    
Much like you would expect, an instance of a map object is created and associated to the DIV element named “MapDiv”. Next a series of “MapOptions” are included that control how the map will be initially rendered. In this code, the options that are specified are the credentials, center, mapTypeId and zoom. The important one for this article is “credentials”, which is you Bing Map key. You can see that in providing this information in code, that you could be exposing your key to the end users as mentioned previous.

Clearly we don’t want to do that so we need a way to hide or abstract that information away. One of the ways that we can do that is through the use of web services. A web service can be implemented that has the responsibility of providing the Bing Maps Key. Logic can be implemented on the web page to invoke that service, get the key information and use it in the code to instantiate the map. Yes, in establishing that web service, the end user could just simply call the web service and get the key information, so we would need to shield that information from the end user.

As mentioned this example is specific to ASP.NET. ASP.NET allows you to easily integrate web services with client side JavaScript code. The process is similar to what happens when a web reference is set in a class library. In establishing this link between the page and web service, you now have direct access to the web service methods via your JavaScript code and all of the wiring is done for you. The first step in this implementation is to utilize the ScriptManger control. The implementation is as follows:

    <asp:ScriptManager ID="ScriptManager" runat="server">
        <Services>
            <asp:ServiceReference Path="~/ws/ClientServices.asmx" />
        </Services>
    </asp:ScriptManager>
    
The thing to note about this implementation is that you are now defining the web services that are available to the ASP.NET AJAX framework. Here we are setting a reference to the “ClientServices.asmx” service through the asp:ServiceReference control. Now that this has been established, we can access the web methods of this service through client side JavaScript.

Before we get into the rest of the code that needs to be implemented at the UI, let’s take a quick look at the supporting service. The implementation is as follows:

    Imports System.Web.Services
    Imports System.Web.Services.Protocols
    Imports System.ComponentModel
     
    ' To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line.
    <System.Web.Script.Services.ScriptService()> _
    <System.Web.Services.WebService(Namespace:="http://tempuri.org/")> _
    <System.Web.Services.WebServiceBinding(ConformsTo:=WsiProfiles.BasicProfile1_1)> _
    <ToolboxItem(False)> _
    Public Class ClientServices
        Inherits System.Web.Services.WebService
         
        <WebMethod(EnableSession:=True)> _
        Public Function GetMapKey() As String
            Dim CanCall As Boolean = True
             
            If Context.Request.UrlReferrer Is Nothing Then
                CanCall = False
            Else
                If Context.Request.UrlReferrer.ToString.Contains("ClientServices.asmx") Then CanCall = False
            End If
             
            If Not CanCall Then Throw New ApplicationException("This service cannot be called directly")
            Return "Enter Your Bing Maps Key"
        End Function
         
    End Class
    
A standard web service was added to the project and named “ClientService.asmx” most of the code listed is part of the template for this type of file and is automatically stubbed out for you. In order to make this service available to the script manager, line 6 (which is commented out in the stubbed code) needed to be uncommented. Once that is done, you can add you application logic. A web method was added named “GetMapKey” that returns a string that is the map key and has some additional logic to control how it’s accessed.

A Boolean variable named “CanCall” is declared. Several tests will be executed to determine if the service can be accessed and depending on the outcome, the variable will be updated. Since “EnableSession” was set to true in the WebMethod declaration, we will have access to the “Request” object. In the Request object, the UrlReferrer will be examined to determine how the service was accessed. If the UrlReferrer is nothing it would indicate that an attempt was made to access the service directly. If the UrlReferrer contains the name of our service, it’s indicative of the service being executed from the default web service test page. Lines 17 – 21 test for both of those conditions and if either of them are true, the Boolean variable CanCall is set to false. After the tests have complete we then evaluate the Boolean variable “CanCall” (line 23). If the value is false, access is not allowed and an application exception in thrown indicating that. If value is true, the map key string information is returned to the calling application.

Now that the supporting service is in place, we can walk through the remainder of the UI logic. The implementation is as follows:

    function load() {
        VEMaps.ClientServices.GetMapKey(ProcessSuccess, ProcessFail);
    }
     
    function ProcessSuccess(result) {
        var MapKey = result;
        var map = new Microsoft.Maps.Map(document.getElementById("MapDiv"),
                        {
                            credentials: MapKey,
                            center: new Microsoft.Maps.Location(41.8756, -87.9956),
                            mapTypeId: Microsoft.Maps.MapTypeId.road,
                            zoom: 7
                        });
    }
     
    function ProcessFail(result) {
        alert('Sorry, but an error seems to have occurred.');
    }
    
Once the page has finished loading on the client side, the “load” function is executed. In this function the “GetMapKey” web method is call. There are two things to note about this call on line 2. The first is that the service reference created via the Script Manager has now become a full-fledged JavaScript object, in which the corresponding web methods are available. Second is that this method is asynchronous. While the web service that was created was not inherently asynchronous, in wiring it up through the Script Manager it has now become asynchronous. Being an asynchronous service, we need to identify the call back functions for this process. This method (as with all of the methods under this model) needs to have two separate call backs defined. The first call back is the function to execute if the web method executes successfully and the second call back is the function to execute if the call to web method fails. In this implementation, if the GetMapKey call succeeds, the ProcessSuccess function will be executed otherwise the ProcessFail function will be excuted.

Presuming that the execution of the web method, GetMapKey, succeeded, the ProcessSuccess function would be executed. In executing this function the return information from the web method is passed to the call back function and is captured in the parameter “result”. Since the web method that was created returns only a string value, the parameter “result” will contain just that. The variable “MapKey” is declared and assigned the value contained in the “result” parameter, which is the Bing Maps Key returned from the web service. The next lines of code instantiate the map and line 09 uses the MapKey variable to provide the Bing Maps Key to the Bing Maps Platform.

In the event that the web service call fails, the ProcessFail function will be executed. Whatever error information is available will be passed to the result parameter and can be evaluated accordingly. In this implementation, a simple error message is displayed via a JavaScript Alert. The thing to note is that this would be the location that you would process the error condition however it’s appropriate for you application.

Wrap-up:

Your Bin g Maps Key is your personal key and you need to ensure that you protect it as much as possible. In the previous example, an ASP.NET AJAX accessible web service was implemented to serve up the Bing Maps Key and logic was added to the service to ensure that service was not being called directly. The UI implemented an ASP.NET specific approach to consume the service, which also provided the additional benefit of abstracting away the web service URL, making it harder to discover.

This is just one approach that can be taken to protect your Bing Maps Key. Again the thing to note here is that this is not a 100% effective way of securing you Bing Maps Key. Since Bing Maps AJAX v7 control resides on and is executed on the client, you key information will always have to have some persistence on the client side. That being the case, it can always be discovered. The previous example shows just one way you can try to protect your key. Can it still be discovered? Yes. Am I going to tell you how? Hmmm…probably not, but I am sure you can guess.

As always, feedback, comments or questions are welcome. I look forward to hearing from you.

Return to Home Page

©2007-2017, Mike Garza, All Rights Reserved