Understanding (and testing for) view state MAC in ASP.NET web forms

Remember view state? For that matter, do you even remember web forms?! I kid because although MVC is the new hotness in the world of building ASP.NET websites, web forms remains the predominant framework due to both the very long tail of sites already built on it and the prevalence of developers with skills in this area who haven’t made the transition to MVC (indeed some people argue that they can happily cohabit, but that’s another discussion for another day).

Anyway, back to view state. When we entered the world of .NET more than a decade ago now, view state was the smoke and mirrors that turned that stateless HTTP protocol into something that actually persisted data across requests entirely automagically. If, like me, you’d come from a classic ASP world you would have been used to a lot of plumbing going into passing data between requests and manually binding it back up to HTML controls to create the veneer of persistence. View state also made for a much lower friction transition process for folks moving from a win forms world where these problems of persistence didn’t exist like they do in the web world. Ok, it could get out of control very quickly and many people bemoaned the (often hefty) overhead it could put on page and request sizes, but it served it a purpose.

But there’s one thing about view state that I suspect many people don’t know and even if they’ve messed with it before, may not understand the consequences: MAC. This is actually a very important feature of view state and misusing it can not only leave you vulnerable now but you may very well find it becomes a breaking change in future versions of ASP.NET. Let me explain what it is, why you need it and how to test whether it’s been disabled on a site.

What do Macs have to do with .NET?!

No, not Macs, MACs – Message Authentication Codes. The whole idea of a MAC is to provide assurance as to the authenticity of a message so that the recipient can have confidence that it hasn’t been tampered with. Don’t confuse this with encryption of the message; it’s not about keeping the message private, rather it’s about establishing message integrity and the concept is actually very simple.

Say you have a message on the sender’s side and in the case of this blog post, that message is your big whack of view state with data to be persisted between requests. What happens is that the message is combined with a private key then hashed to create the MAC. When the original message is then sent it’s accompanied by the MAC. The sender get the message, hashes it using the same private key as the sender (this is important as just the one key is involved on both sides), then compares the resultant MAC with the one sent alongside the original message. If they match, the message is intact and if they don't then the receiver knows that someone has been messing with it.

Wikipedia has a neat visual explanation of it:

Visual representation of MAC

The relevance of MACs to .NET and view state is simply that it provides a mechanism to ensure that an attacker hasn’t been messing with your view state. Unless you turn it off – that’s the story I really want to talk about here.

Disabling view state MAC (and why you should never, ever, ever do it)

Let’s look at how to turn it off then why you shouldn’t. There are a couple of different approaches, the first is to just disable it site-wide in the web.config:

<pages enableViewStateMac="false" />

The other is to turn it off on an individual page:

<%@ Page EnableViewStateMac="false" %>

Either of those options will put a dead stop to MAC’ing your view state, but why on earth would you ever want to do this?! A common reason would be when transferring requests between machines with different keys as unless the same one is used by both the sender and receiver, an exception will result. Disabling view state MAC hacks around the correct fix which is to simply sync the keys.

Another scenario might be to accept view state posted from third parties. There’s really not a good use case for this though and it’s a bit of an abomination of what view state was designed to do. I’m sure there are other scenarios as well where the developer has said “Hey, you know what? If we just turn off this security feature then it solves [insert random problem here]”.

So what can you do with view state turned off? Well you can send whatever the hell you want in view state! The damage an attacker can do with this depends on how the view state is used, let’s consider some possibilities:

  1. Set their own values in your controls
  2. Change control state
  3. Inject XSS into the page

Think of it like this: anything the page depends on that comes from view state could be compromised. Without MAC, the entire view state becomes “untrusted data” or in other words, expect it to contain nasties injected by an attacker. This might then be weaponised by the attacker tricking the victim into posting invalid view state (a classic social engineering attack often used with reflected XSS) or depending on the nature of the app, an attacker might directly exploit the system themself if that tampered view state is then processed by the server. There are many, many possible exploits here.

What you should be doing with view state MAC

The clearest advice I’ve seen on this is from Levi Broderick on the ASP.NET team via this Stack Overflow question (his caps – not mine):"

It should never be set to false. THERE ARE NO EXCEPTIONS TO THIS RULE.

In that response Levi also says:

The EnableViewStateMac property will be removed in a future version of the product since there is no valid reason to set it to 'false'

Levi then talks about this again in his post on Cryptographic Improvements in ASP.NET 4.5:

Never set EnableViewStateMac to false in production. Not even for a single page. No exceptions! The EnableViewStateMac switch will be removed in a future version.

But what if you’re not even using view state? What’s the harm of disabling MAC then? Barry Dorrans from the Azure team at Microsoft has this to say:

There are cases where, despite your best attempts viewstate may sneak in, under the guise of control state, so the warning still applies.

As he also says, if you’re not using it then what’s the point of disabling MAC in the first place?! There’s a bit of a theme happening here with Microsoft people telling you not to mess with the secure default.

Still not convinced? Damian Edwards (a Program Manager on the ASP.NET team) also touches on it in his talk from NDC earlier this year (20 mins and 35 secs onwards):

Do not disable MAC

Note also that Damian refers to how the EnableViewStateMac setting doesn’t just, well, enable view state MAC. Instead it also has an impact on things like control state and event validation, among others. Wait – what?! Ok, so now you’re starting to get a sense of why Damian is giving people open license to tease the ASP.NET team about ever allowing this in the first place!

He then goes on to say this:

In a future version of .NET we will remove the support for this. If you set this to false we’ll just blow your application up! It is incredibly dangerous.

Understood? Good!

Testing for disabled view state MAC with ASafaWeb

This is a perfect scenario for ASafaWeb to test for because it’s already receiving the view state from web forms apps by virtue of the fact that it’s embedded in the response to requests the tool is already making. Because the MAC is simply appended to the other data in view state it’s also easy to detect, in fact there’s an online tool that enables you to decode any view state (it’s also a good reminder why nothing sensitive should ever go into view state if you’re not making use of the viewStateEncryptionMode property and even then, storing this sort of data in there is a really, really bad idea).

Here’s how it works: Firstly, head on over to asafaweb.com and enter the URL of the site you want to scan into the extremely large text box on the home page:

Scanning a site via ASafaWeb

This one is my dedicated insecure test site and after running it you’ll get a bunch of results relating to various aspects of the site’s security profile:

An ASafaWeb scan result

Drill down into the “View State MAC” entry and you’ll see this:

Details of view state MAC address validation

That’s it! Hopefully you won’t see red and you’ll either see green for a pass or “Not tested” (usually it’s not an ASP.NET app or it’s an MVC app or view state was encrypted and can’t be tested) but if you do see red, fix it right now! For context, since I silently launched this scan a few days ago about 5% of sites where view state was present and readable had disabled MAC on the view state.

Check your sites folks!

Security .NET ASafaWeb
Tweet Post Share Update Email RSS

Hi, I'm Troy Hunt, I write this blog, create courses for Pluralsight and am a Microsoft Regional Director and MVP who travels the world speaking at events and training technology professionals