Question

I'm working on improving the security of my company's website and wanted to create a token to prevent forgery attempts that could be easily maintained this is what I came up with.

public class AntiForgeryToken
{
    private readonly string _referenceToken;

    public AntiForgeryToken()
    {
        _referenceToken = Guid.NewGuid().ToString();
    }
    public string ReferenceToken
    {
        get { return _referenceToken; }
    }
}

In my base class for my MasterPage I have a HiddenField wrapped with property named: ReferenceToken

protected virtual void Page_Load(object sender, EventArgs e)
{
    if (!Page.IsPostBack)
    {
        InjectToken();
    }

    ValidateToken();
}

private void InjectToken()
{
    var token = ObjectFactory.GetInstance<AntiForgeryToken>();
    ReferenceToken = token.ReferenceToken;
}

private void ValidateToken()
{
    var token = ObjectFactory.GetInstance<AntiForgeryToken>();
    if (ReferenceToken.Equals(token.ReferenceToken, SC.InvariantCultureIgnoreCase)) 
            return;
    ...do stuff for failed token
}

I have StructureMap handle storing the token inside the Session so it's persisted per user session, would all of this be a valid implementation of an AntiForgery scheme?

Edit: There seems to be some confusion on my question, yes I understand ASP.NET MVC has a built in AntiForgeryToken scheme, this question is explicitly about how to recreate this for WebForms to prevent the usage of a CSRF attack (Cross Site Request Forgery). I understand this in no means removes the need for proper authorization of user rights.

I was going to bring up the very link that @Neal and @solairaja posted: Prevent Cross-Site Request Forgery (CSRF) using ASP.NET MVC’s AntiForgeryToken() helper. This article explains more of what the CSRF attack is and how MVC stops it however their solution isn't applicable to webforms which is why I went about implementing my own.

After seeing the response from @Neal I think that will most likely be the accepted answer since I didn't realize I could just get the actual source code from the MVC tool which will most likely replace the guid creation. But I'll leave the question open incase anyone else has some valuable information to add.

Was it helpful?

Solution

Chris,

your approach more or less mimics the anti-forgery approach in MVC, except they use a base64 encoded byte array generated from RNGCryptoServiceProvider and store the token both in the page ( hidden form field ) and in a cookie. I would recommend moving more of the logic into the token implementation ( e.g. encapsulate most of the validation logic inside the token ).

The code for the MVC implementation is freely accessible at http://aspnet.codeplex.com/sourcecontrol/changeset/view/23011?projectName=aspnet#391757 if possible you should probably review that as well as http://blog.codeville.net/2008/09/01/prevent-cross-site-request-forgery-csrf-using-aspnet-mvcs-antiforgerytoken-helper/ for an analysis + ideas.

OTHER TIPS

ASP.NET Web Forms prevents CSRF attacks out of the box by default if you are using View State. Unless if you have effectively disabled view state in your application, you are adding code to solve a problem you don't have.

View State prevents CSRF Attacks
.Net CSRF Guard - OWASP

First, I suppose I should ask... what do you really mean by "AntiForgery"? What are you concerned about being forged? The rest of what follows is just some general info that pops into mind...

One thing I would change is to not use Guid.NewGuid. There's debate about whether it is random or not and thus not suitable for security purposes. That said, I think it would be a very hard attack to pull off.

Look at RNGCryptoServiceProvider for the GetBytes method for something that should be better for generating a random token. In addition to better randomness, another advantage to this is you can make it whatever size you want.

Are you doing this over ssl though? First off, ssl is line of defense number one for man in the middle attacks. It may not be secure enough (and others can debate about that) for every need, but if you're concerned about such things, it's the starting point if nothing else. If not, how do you ensure that you are getting a response from the right machine and not a man-in-the-middle who is responding first? Without SSL or an equivalent, your token is just as easily stolen as anything else you do.

One additional thing to consider adding is having your tokens be only good for one trip and you generate a new one back to the client on the next trip. Trying to reuse it fails.

I would not try to replace SSL with something else of your own contrivance if that is what you are thinking. If you are concerned about replay though, one time token generation is one way to stop it. If you're worried about a user submitting the same form data twice, this is one thing to do. I would also consider your overall application design if you're concerned about that. Many replay and similar scenarios can be defeated by sound design of your business logic such as not trusting the client to send you sensitive information like the price of an item in a shopping cart.

Please also check out the various microsoft guidance on ASP.NET and IIS security (i.e. Google ASP.NET or IIS security site:microsoft.com) as a starting point. A lot smart people have solved many issues already for us.

would all of this be a valid implementation of an AntiForgery scheme?

As far as I can tell, it looks like you are inserting a GUID onto a page, and then looking for the same GUID when the page comes back.

I don't know what your requirements are, so I can't say if the scheme is really "valid." However, I can point out a few things:

  1. If the GUID only lives on the page, then what would prevent a user from reading the page on one machine, and submitting the form from another? It would be good to associate it with a cookie or a session (which also uses a cookie), if you aren't already.
  2. If the GUID is written into the page as a static hidden <input> field, then the form could be read and submitted by bots. You can get around that by requiring script on the page to process the token, before submitting it.
  3. Are you using ViewState? If so, you might consider just setting ViewStateUserKey to some repeatable value that's unique per client; it performs a similar function to what you've described here.

As NICK told, for me too the code which you have given, looks like you are inserting a GUID onto a page, and then looking for the same GUID when the page comes back. Thats good idea too when ur using a structure map storing into the session.

But there are some inbuilt methods are available for this AntiForgery concepts.

Kindly refer to the below link first and understand

http://blog.maartenballiauw.be/post/2008/09/01/ASPNET-MVC-preview-5s-AntiForgeryToken-helper-method-and-attribute.aspx

Now,

Check the below link for the details descriptions and methodology of approaching.

http://msdn.microsoft.com/en-us/library/system.web.mvc.htmlhelper_methods.aspx

http://blog.codeville.net/2008/09/01/prevent-cross-site-request-forgery-csrf-using-%20aspnet-mvcs-antiforgerytoken-helper/

Thank you !!

That looks to me as if it's generating a canary with every request. Now what happens if a user opens multiple tabs? :)

The problem with your approach (and the ASP.NET MVC implementation) is it relies on developers to implement it. Security like this should be opt-out, not opt-in. When I wrote a AntiCSRF module I ended up using the ASP.NET page lifecycle instead, which mean no changes to the underlying code, unless a developer wanted to opt a page out of the CSRF checks. You'll note that it uses a single token which lasts for the lifetime of that user's browser session - there's no actual need to change the token with every request.

Now I wrote the module mainly as a way to illustrate some concepts for my forth coming book (insert advertisement here grin), you could of course use the ViewStateUserKey, but again this is opt-in, rather than opt-out.

First rule of security: Don't try to roll your own security

As I understand your description, that wouldn't be a valid anti-forgery scheme. All an attacker would need to circumvent it would be to use the View Source feature of his or her browser to find the token. Then he or she could post whatever they like as long as they remember to post that token, and your code wouldn't know the difference.

Apologies if I completely misunderstood your description...

Instead of using anti forgery tokens like that I would validate that the authenticated user actually has the necessary rights to make the requested modifications.

E.g. is the web page a "create user page", I would check that the authenticated user has authorization to create new users. Is the page an "edit user X page", I would check that the authenticated user has authorization to modify user X. Maybe because he himself is user X, or an administrative user.

That said, using GUIDs is not very secure. Guids are generated based on an algorithm written for uniqueness, not randomness. AFAIK there are three valid algorithms, name based, time based, and random. If the Guid algorithm used by the system (which could be changed by a future .NET version) is time based, then guessing valid Guids is not very difficult.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top