简体   繁体   中英

A secure implementation of Page.IsPostBack?

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?

I had a project a couple of years ago where we had some penetration testing done on the code. They flagged up the fact that by default IsPostback doesn't check the http verb. To address this I created an abstract Page class with its' own implementation of IsPostback that shadows the default implmentation:

Public Class ProjectPage : System.Web.UI.Page

    public new bool IsPostBack()
    {
        return (Page.IsPostBack && Request.HttpMethod.ToUpper() == "POST");
    }

End Class

This allows you to do testing on the http verb, but you could easily extend the method to do other checks as well.

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 OnClick event, with event validation enabled, the client has to send the __EVENTVALIDATION form 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 = false set 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 __VIEWSTATE or 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 cause Page.IsPostBack to be true, but it doesn't matter because the submitted __VIEWSTATE will 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 __VIEWSTATE that 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 == false block. This must always get run once before a valid postback can be submitted to the ASP.net server. Or am I missing something?

A cookie is a much better mechanism for your needs. The cookie is a token that could only have been generated by the server and vouches for the holder of the token certain claims such as having signed in recently and for having certain permissions and/or preferences. Some of these features are built into FormsAuthentication. You can implement your own cookie mechanism, but you should research secure cookie protocols because there are several non-obvious security considerations.

The benefit is that you don't have to go to the database on every request, you just trust it. This could also be a good strategy for weathering certain DoS attacks because you can tier your app such that a dedicated device in front of your app servers validates tokens too and throws out invalid requests.

If cookies aren't allowed, you can send the token as part of the url, as formsauth allows, or as a form field in your postback. But that's more work to manage then cookies, IMHO, once you've gone through the trouble of generating a proper token.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM