Following my previous question as to whether ASP.net’s default Page.IsPostBack implementation is secure (it’s not; it can be faked… the HTTP verb doesn’t even have to be POST!), I was thinking; surely there must be a better way to implement it? Can we come up with a Page.IsPostBack implementation which, when it is true, is almost guaranteed to indicate that the page is an actual ASP.net postback? This is important if one wants to do security checking only once (like whether some content is going to appear, based on the user’s role(s)), and wants to do it only if we’re NOT dealing with an ASP.net postback.
My first thoughts as to how to do this are to implement the checking code in a property, so I can write something like this inside Page_Load:
if (!_isPostBack)
{
// Do security check
if (userIsNotAuthorized)
{
btnViewReports.Visible = false;
btnEditDetails.Visible = false;
// etc.
}
}
Is there a way to securely implement _isPostBack? Perhaps storing something in the ViewState that would be hard or impossible to jerry-rig to fake a postback? A random string?
OK, here’s what I think is the solution: Page.IsPostBack is already secure enough, as long as event validation is enabled. Let me explain my reasoning below and I’d be happy for anyone to add a comment if I’ve gotten something wrong.
In order for a spoof postback to be posted to ASP.net and trigger a control’s
OnClickevent, with event validation enabled, the client has to send the__EVENTVALIDATIONform field. This field contains a uniquely-generated string that basically tells ASP.net which controls a postback event for that page may have originated from. If you try to spoof a postback for a button which has had.Visibility = falseset on it, you’ll see an event validation error message. So, it looks like you can’t directly spoof a click on a hidden control.What about spoofing a postback of one of the existing buttons on the page that you has been rendered (ie. you do have permission to view/click on it)? Well, you can send the postback to the page, but you need to submit a valid
__VIEWSTATEor you’ll just get a ‘state information invalid’ error. In order to have a valid__VIEWSTATE, you already need to have loaded the page as a non-postback, right? That means that the security-checking code will have executed at least once, hiding the appropriate controls and recording that in the__VIEWSTATE. So, when you post the spoof postback, yes it will causePage.IsPostBackto be true, but it doesn’t matter because the submitted__VIEWSTATEwill already have been generated on the previous non-postback page load to hide the content that you shouldn’t have access to… so, you can spoof a postback, but only by passing a__VIEWSTATEthat has been previously generated by a non-postback page load.So, because of these facts, it should be safe to only put security-checking code inside a
Page.IsPostBack == falseblock. This must always get run once before a valid postback can be submitted to the ASP.net server. Or am I missing something?