Application Security Testing: An Integral Part of DevOps
One of the permissions defined in ASP.NET's Medium and High partial trust files is System.Net.WebPermission. This is probably one of the most confusing permissions for developers to use due to the interaction between ASP.NET's <trust /> element and the settings for this permission. The default declaration for System.Net.WebPermission looks like this:
<IPermission class="WebPermission" version="1"> <ConnectAccess> <URI uri="$OriginHost$"/> </ConnectAccess> </IPermission>
Although a WebPermission can be used to define both outbound and inbound connection permissions, normally, you use WebPermission to define one or more network endpoints that your code can connect to. The default declaration shown previously defines a single connection permission that allows partially trusted code the right to make a connection to the network address defined by the <URI /> element.
However, the definition for this element has the string replacement token: $OriginHost$. This definition is used conjunction with the <trust /> element, which includes an attribute called originHost and its value is used as the replacement value for $OriginHost$. For example, if you define the following <trust /> element in your web.config:
<trust level="Medium" originUrl="http://www.microsoft.com/"/>
. . . when ASP.NET processes the trust policy file, it will result in a web permission that grants connect access to http://www.microsoft.com/. Although the attribute is called originUrl, the reality is that the value you put in this attribute does not have to be your web server's domain name or host name. You can set a value that corresponds to your web farm's domain name if, for example, you make Web Service calls to other machines in your environment. However, you can just as easily use a value that points at any arbitrary network endpoint as was just shown. One subtle and extremely frustrating behavior to note here is that you need to have a trailing / at the end of the network address defined in the originUrl attribute. Also, when you write code that actually uses System.Net classes to connect to this endpoint, you also need to remember to use a trailing / character.
With the <trust /> level setting shown previously, the following code allows you to make an HTTP request to the Microsoft home page and process the response:
HttpWebRequest wr = (HttpWebRequest)WebRequest.Create("http://www.microsoft.com/"); HttpWebResponse resp = (HttpWebResponse)wr.GetResponse();Response.Write(resp.Headers.ToString());
Because the WebPermission class also supports regular expression based definitions of network endpoints, you can define originUrl using a regular expression. The reason regular expression based URLs are useful is that the WebPermission class is very precise in terms of what it allows. Defining a permission that allows access to only www.microsoft.com means that your code can access only that specific URL. If you happened to be curious about new games coming out, and created an HttpWebRequest for www.microsoft.com/games/default.aspx, then a SecurityException occurs.
You can rectify this by instead defining originUrl to allow requests to any arbitrary page located underneath www.microsoft.com.
<trust level="Medium" originUrl="http://www\.microsoft\.com/.*"/>
Notice the trailing .* at the end of the originUrl attribute. Now the System.Net.WebPermission class will interpret the URL as a regular expression; the trailing .* allows any characters to occur after the trailing slash. With that change, the following code will work without throwing any security exceptions:
HttpWebRequest wr = (HttpWebRequest)WebRequest.Create(" http://www.microsoft.com/games/default.aspx");
Although the examples shown all exercise the HttpWebRequest class directly, the most likely use you will find for a custom WebPermission is in partial trust ASP.NET applications that call into Web Services. Without defining one or more WebPermissions, your Web Service calls will fail with less than enlightening security errors.
Because your web application may need to connect to multiple Web Service endpoints, potentially located under different DNS namespaces, you can define an <IPermission /> element in your custom policy file with multiple nested <URI /> entries. As an example, the following code programmatically constructs a WebPermission with two different endpoints, and then writes out the Xml representation of the permission:
WebPermission wp = new WebPermission();Regex r = new Regex(@"http://www\.microsoft\.com/.*"); wp.AddPermission(NetworkAccess.Connect,r);r = new Regex(@"http://www\.google\.com/.*"); wp.AddPermission(NetworkAccess.Connect, r);SecurityElement se = wp.ToXml(); Response.Write(Server.HtmlEncode(se.ToString()));
The resulting XML, looks like this (note: in this sample the class attribute has been changed to use the short name for referencing the WebPermission class. Since WebPermission is already defined in ASP.NET partial trust configuration files, you can use the short name in the class attribute rather than listing the full strong named definition of the WebPermission type):
<IPermission class="WebPermission" version="1"> <ConnectAccess> <URI uri="http://www\.microsoft\.com/.*"/> <URI uri="http://www\.google\.com/.*"/> </ConnectAccess> </IPermission>
The $OriginHost$ replacement token is no longer being used in this sample. Realistically, after you understand how to define a WebPermission in your policy file, the originUrl attribute isn't really needed anymore. Instead, you can just build up multiple <URI /> elements as needed inside of your policy file. With the previous changes applied to ASP.NET's medium trust configuration file, you can now write code that connects to any page located underneath www.microsoft.com or www.google.com.
HttpWebRequest wr = (HttpWebRequest)WebRequest.Create(" http://www.microsoft.com/games/default.aspx"); HttpWebResponse resp = (HttpWebResponse)wr.GetResponse();... resp.Close();wr = (HttpWebRequest)WebRequest.Create("http://www.google.com/microsoft"); resp = (HttpWebResponse)wr.GetResponse();
Although not covered here, the companion classes to HttpWebRequest/HttpWebResponse are the various System.Net.Socket* classes. As with the Http classes, the socket classes have their own permission: SocketPermission. Just like WebPermission, SocketPermission allows the definition of network endpoints for both socket connect and socket receive operations.
This article is adapted from Professional ASP.NET 2.0 Security, Membership, and Role Management by Stefan Schackow (Wrox, 2006, ISBN: 0-7645-9698-5), from chapter 3 "A Matter of Trust." Reprinted with the publisher's permission.