Omicron Llama

Coding all day, every day.

Fun with AllowUnsafeUpdates

I’ve heard a little confusion lately about the use of the property “AllowUnsafeUpdates” on the SPWeb object and when it should be used. So I decided to do a little digging.

According to MSDN, the definition of the property is:

Gets or sets a Boolean value that specifies whether to allow updates to the database as a result of a GET request or without requiring a security validation.

Sounds simple, right? But when you’re knee-deep in C# code, a dozen calls down a chain of methods somewhere in your own process, you find yourself needing to use this property as it’s the most commonly known workaround for the error message:

<nativehr>0x80004005</nativehr><nativestack></nativestack>Updates are currently disallowed on GET requests.  To allow updates on a GET, set the ‘AllowUnsafeUpdates’ property on SPWeb.

GETError

Weirdly, this error tells you what to do to work around this, without giving away too much into understanding what’s happened.

To illustrate, let’s create a very simple scenario where we can reproduce this instantly. Create a new solution in Visual Studio (for SharePoint 2010 or 2013, doesn’t matter) and add an Application Page (you might need to add a LAYOUTS mapped folder before you see the “Application Page” project item in Visual Studio’s “Add New Item” dialog).

On this application page, add a button, and give the button a server side click handler. Inside the click handler, lets add some very simple code to modify the Title of the current website.

Let us ignore the fact that most scenarios you can think of in this situation would be done via client side code. This scenario is presented as is for the purposes of simplicity and demonstrating the concepts in this article

MyApplicationPage

The code behind for the application page might look a little like this:

Now if you deploy this, visit your page and click the button, not much will seem to happen. It’ll refresh the page but that will be it. But if you navigate again (or refresh the page again), you’ll notice the page title change!

TitleChanged

 

Now let’s start to have some fun. Let’s reproduce the error.

To do this, simply move the body of the button click handler into the page load handler. The code should now look like this:

Now if you redeploy the solution and navigate to the page you’ll get the error immediately! But why? The exact same code has ran!

The answer lies in the word “GET” in the error message. When you visit the page, and the codebehind runs, it is all happening in the context of a HTTP GET request. No matter how many SPSite objects you instantiate in this cycle of the code, it is still happening within a HTTP GET.

Now, SharePoint has a safeguard to prevent some dangerous requests from accessing and updating the databases – it is a very old method but it works – and that that is for it to be able to change anything in the content database, you must supply what is known as a “Request Digest”. This is simply a large string that is generate when a page is created in SharePoint (or, more correctly when a request is served by SharePoint).

This digest is used by the internals of SharePoint to validate that the operation that is asking to make changes to SharePoint has originated from someone who has logged in to the site. Without this Digest, the request to change the database could theoretically come from anywhere.

Developers who use the JavaScript Client Object Model for SharePoint may be vaguely aware of the FormDigest being used to make updates to SharePoint content. The exact same mechanism is in use here.

In order to send the digest to the server when you make a request, you need to perform a HTTP POST request, as the digest (along with a lot of other information) is passed to the server in the request payload (remember that HTTP GET can only pass data via the querystring).

Now back to our application page. In the first example with the button that works, SharePoint generates a lot of javascript when the page is built that handles the button click event. The job of this javascript is to collect data on the page, such as the name of the button, the name of the server side function that handles the click event, the values of other form fields that might be on the page, including our critically important request digest (note: SharePoint 2013 seems to handle where the digest is stored on the page vastly different from SharePoint 2010, but the principle is still there). All of this is packaged up in a POST request which is sent to the server. HttpHandlers in SharePoint read this, populate the SPContext object for the current site, including loading the form digest and validating it.

By the time we get to our code, everything is pre-loaded, the background context is a HTTP POST request, complete with a valid request digest – and our newly instantiated SPSite and SPWeb object can freely have changes made to it (like changing the Title).

When we move the code to the page load handler, we don’t have a POST request being created, just a simple GET request (because we hit the URL via the browser). The code that is running this time round is in the context of the GET request, is missing the request digest, and by the time our call hits the database it bounces back immediately warning you that you’re in a GET.

That property, “AllowUnsafeUpdates”, prevents this error being thrown when you set it to “true”.

An “Unsafe Update” is essentialy one that is made through a GET request, and is missing a request digest.

As this is a security mechanism, there is an interesting tid-bit on the MSDN Documentation, for the method “SPUtility.ValidateFormDigest“:

If the method that is passed to the RunWithElevatedPrivileges method includes a write operation, either of the SPUtility.ValidateFormDigest() or SPWeb.ValidateFormDigest() methods should be called before a call is made to RunWithElevatedPrivileges.

So this means that if you are performing “RunWithElevatedPrivileges”, it is a recommended best practice to Validate the request digest beforehand, and to prevent the code running (by maybe returning an error) if the validation is false. However, if you are planning on running code that will be modifying the SharePoint databases, it’s highly recommended to instantiate your SPSite object using the system account security token instead. There is a good amount of discussion on this topic on this question on SharePoint StackExchange.

I hope this post clears up a little bit of confusion as to why you might get this error, and why sometimes we see code automatically default to setting AllowUnsafeUpdates to “true”. When you do see this, try to understand that your code is likely to be running as when a page is being loaded, and will not include a request digest. Try to think of a better, more secure pattern for what it is you’re trying to do.

An important point to note here, is the importance of performing “updates” or “changes” to the database. If you query SharePoint for data or do other processing, you don’t change the database, therefore this concept is even less relevant.

Another important note, this property is never persisted to the content database for the current SPWeb. It is only valid for, and applies only to the instance of SPWeb that the property is a member of. Dispose of this SPWeb and the setting will change to the default value depending on your scenario (read on below…)

PowerShell Bonus

When you instantiate an SPWeb object via PowerShell using “Get-SPWeb“, the AllowUnsafeUpdates properties is always set to “true”. This is because the object does not have a HTTP Request present at all, no GET or SET, and oftentimes we will be using PowerShell to make changes, so the default setting is for the property is “True”.

Console App Bonus

My good friend Matthew Bramer asked me if the PowerShell tidbit above was true for Console Applications. The answer is “yes”:

consoleapp

4 thoughts on “Fun with AllowUnsafeUpdates

Leave a Reply

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