Skip to content

SharePoint custom web service with SSOM and Request Digest

When developing a custom web based application (like ASP.NET in conjunction with IIS) that relies on the usage of the SharePoint server side object model you have to make sure that your code is valid in security related terms.

Microsoft integrated a functionality that protects the system against cross-site scripting attacks. The protection is always active when doing updates (POST requests) when being active in an GET request that is encapsulated in an running HTTP context.

That’s why Microsoft introduced the “AllowUnsafeUpdates” property most of you are familiar with for sure. When setting that value to “True” the cross-site scripting prevention will be deactivated temporary. This will be used mostly to prevent this kind of exception when updating SharePoint objects that need a referenced SPSite or SPWeb object:

System.Exception: Microsoft.SharePoint.SPException: The security validation for this page is invalid. Click Back in your Web browser, refresh the page, and try your operation again. —> System.Runtime.InteropServices.COMException (0x8102006D): The security validation for this page is invalid. Click Back in your Web browser, refresh the page, and try your operation again.

But to be honest you should always try to prevent those kind of “trick” because first of all you are weaken the security measurements of your environment (especially in Internet scenarios) and further more there can be strange behaviors in excessive usage of this property.

Here is a quote from a very detailed article about that:

The Microsoft idea behind introducing the AllowUnsafeUpdates property is to protect YOU from cross-site scripting attacks. The way this works is that if your application is running in an HTTPContext (i.e. it’s a web part for instance) and the request is a GET request then SharePoint will refuse to do any changes unless the value of AllowUnsafeUpdates is set to true and by default it will be false for GET requests. If you try to do any updates to lists, webs or any SharePoint objects that require an SPSite to be created first, and if you don’t set AllowUnsafeUpdates to true you will get this exception

And here is some official information from Microsoft on MSDN.

So let’s get to a practicable example on how to to handle this security issue the correct way. Assume we want to implement a web service that is able to create Site Collections. Normally Site Collection can only be created using the Central Administration or the SSOM (.NET, PowerShell).

Here’s the code that the web service will execute:

using (var rootSite = new SPSite("http://corp"))
{
    var sites = rootSite.WebApplication.Sites;
    site = sites.Add(a lot of arguments);
}

So far so good. The web service is being called from an authenticated user (or without authentication, your choice) and the process that hosts your solution is executing your code. And it will throw the COMException we already talked about. And you are not able to change “AllowUnsafeUpdates” because the SPWebApplication instance does not offer such a possibility.

So SharePoint won’t let you create additional site collections this way because it is vulnerable to cross-site scripting attacks. The magic key word here is “Request Digest”.

In the standard SharePoint implementation each client gets a unique request digest token when surfing on a SharePoint site. This token is valid for about 30 minutes in general. After that a new token is being requested. You can find those settings in the general settings page of the web application.

Web Page Security Validation for a Web Application
Web Page Security Validation for a Web Application

So we could turn off the security validation, create the site collection and then turn it on again. Sounds like a dirty solution, right? Yes it is not just dirty it is quite insecure. When doing this you would open a security threat for the whole web application, including all your sites.

The right way to make the magic happen is to get an own valid “Request Digest” token for our current HTTP context our web service is using. The token is transported by the HTTP protocol and is added to the headers. Then the digest is being validated with SPUtility.ValidateFormDigest or SPWeb.ValidateFormDigest. You could use those methods without the usage of a digest token but it won’t work out – makes sense eh? 🙂

So how do we get a valid request digest token? Internally Microsoft uses a SOAP web service that creates such a valid token. The web service is named “sites.asmx” and can be found under “/_vti_bin/sites.asmx” relative to a site URL. At least this kind of method is used by the CSOM when creating a new “ClientContext” object. To save some work we can just reuse that functionality and implement it in our own client, that consumes our web service.

Microsoft is so nice that the development team decided to make the method “GetFormDigestDirect()” a public API method we can consume. The method returns a FormDigestInfo object that contains the digest value.

This value has to be added to the default request headers of our client, that is doing the call to our web service. In this case a standard HttpClient.

var clientContext = new ClientContext("http://corp");
var digestInfo = clientContext.GetFormDigestDirect();
httpClient.DefaultRequestHeaders.Add("X-RequestDigest", digestInfo.DigestValue);
// do your async call to the web service

Quite simple, eh? Yes it is, when one knows where to find, get and use the needed functionalities – typically SharePoint.

Ok now we can intercept the digest token on web service side. We just need to call the appropriate function and SharePoint does the rest for us.

using (var rootSite = new SPSite("http://corp"))
{
    rootSite.RootWeb.ValidateFormDigest();
    var sites = rootSite.WebApplication.Sites;
    site = sites.Add(a lot of arguments);
}

Finally you won’t get an exception anymore. You just have to make sure that the URL you used to create the ClientContext represents the same site collection you instantiate on your web service side. Otherwise the digest token is not valid!

Leave a Reply

Your email address will not be published. Required fields are marked *

By transmitting your comment you agree to our mentioned privacy policy content.

5 + eleven =