.Net CSRF Guard
This page, like the tool, is a work in progress. Questions? Contact Jason Axley (Jaxley) or use the Talk page.
- 1 Problem Overview
- 2 Threat Model
- 3 How it works
- 4 Implementation Approach
- 5 Implementation
- 6 Related work
- 7 TODO
A realization that I just had today was that it seems that the root cause of CSRF is cookie-based session IDs that get auto-sent by the browser with each request. What CSRFGuard (Java and this .Net version) therefore try to do is to allow one to continue using Cookie-based sessions by layering on top of this yet another session token that isn't sent in a cookie to essentially attempt to authenticate the HTML page contents and links as belonging to a legitimate session.
ASP.Net specific concerns
CSRF can actually be prevented in .Net already -- but you have to be using ViewState. In fact, ViewState prevents many other attacks as a happy coincidence, such as several data input validation attacks for non-text-form fields.
There are problems with relying on ViewState however:
- Developers can disable ViewState per-page or on an entire ASP.Net application. They can also forget to enable it on a key page. Knowing you have protection becomes a laborious code-and-configuration-review-problem.
- ViewState can result in hugely bloated page content if it is not cared for properly during development
- Developers can inadvertently divulge sensitive date in ViewState that may go unnoticed since ViewState is Base64-encoded in the page content
There are also those out there who think that ASP.Net is immune to CSRF already, probably because ViewState is enabled by default so if you try CSRF attacks without knowing this key fact, you may be lulled into a false sense of security (or at least may not appreciate why CSRF doesn't work in a default setup). You can try it yourself easily enough (and I will probably include a demo of ViewState CSRF protection in my sample test web application when the code is released).
Try to submit a CSRF form post to a page with ViewState enabled. Notice that it does not work. Now, edit the Web.config and add:
<pages enableViewState="false" />
How it works
Incoming Requests: Protection
The module hooks the YYYYYY event and calls on the CSRFGuard object to check the contents of the request for whether to even bother validating the request or not. There are several cases (many configurable) where it makes sense to skip the request (meaning that it doesn't represent a CSRF attack risk)
- case 1
- case 2
- case n
If it determines that the request needs checking, then it compares the passed CSRFGuard Session Token to the one stored in the user's ASP.Net session. If they do not match, or if the token is not present, then we've got a CSRF attempt.
When a CSRF attempt is detected, the Module then decides what to do about it, based in large part to the configuration. There are likely to be many, many possible cases so an attempt will be made to design high-level generic mechanisms that can support various use cases.
Outgoing Responses: Page Rewriting
The module also hooks the ZZZZZZ event and provides a custom Request Filter that interrogates the outgoing HTML so that we can inject our CSRFGuard Session Token
This project takes an analagous approach to the J2EE CSRF Guard J2EE Filter in the ASP.Net world: an ASP.Net HTTP Module / Filter.
- Threat-modeled design and implementation
- Fully test-driven (will be using nunit2)
- And very high code coverage for unit tests (using ncover)
- Automated build (will be using nant)
- Highly configurable
- Allow for flexibility to support all different kinds of applications.
- Highly modular code
- Bulk of the decision-making is done automagically in objects who can then be interrogated for access decisions
- Small classes and methods for clarity and avoiding overly-complex code.
- Ease potential rolling multiple utilities like this into a single uber-HTTP-Module framework later (need to check out status of the mod_security port to .Net)
- No tight coupling to the application required (but may be useful to support for optimizing performance or integration)
- Allow non-security code to be overridden by another implementation (e.g. use your own Logger class, use your own Config file class, support additional response mechanisms, etc.)
- Ability to run in a partial trust environment (hat tip to User:Dinis.cruz)
- Ability to optimize the configuration to just where you most expect to have CSRF vulnerabilities (e.g. avoid work for no security gain)
- Not just a straight code port from J2EE version
Differences between this and the J2EE version (to be resolved)
TODO Insert UML / Class diags and discussion of design
- PHP CSRF Guard
- J2EE CSRF Guard
- OWASP Enterprise Security API
- Finish this wiki page
- Check out J2EE CSRF Guard 2.0 features and nomenclature for possible alignment
- Investigate threats of bad applications that leak ASP.Net session info from HTTPS to HTTP. This module right now is implicitly assuming that the session is trustworthy which it would be nice if we could have some programmatic basis for believing this.
- Write nunit test cases for everything
- Write nant build script
- Investigate techniques/designs to allow overriding of the logging method, etc. to hook in the platform log4net logger, for example
- Loads of error handling to be production-ready.
- Secure Coding:
- Data input validation on everything
- Data input canonicalization
- Implement URL whitelisting
- Regex filter
- Implement parameter substitution
- HTMLParser filter
- Regex filter
- Implement logging options
- Implement configurable evasive actions
- Kill session
- redirect to URL (with optional parameters to denote the error info or message type)
- Simply Print error message to screen and block
- Call another authentication source to validate the user action
- Investigate an option for an application to provide its own web control (hidden) that you could override with the value from session instead of replacing the form tags with regex.
- Or, an option that would involve tightly coupling the app and the module -- the module could stick the token in session and the app could put it in the pages; then the module would only need to validate the data coming back and not do any rewriting.
- Document the design and configurable options on the wiki
- Get the code into source control