Skip to content

Instantly share code, notes, and snippets.

@jkuemerle
Created August 8, 2012 16:07
Show Gist options
  • Select an option

  • Save jkuemerle/3296254 to your computer and use it in GitHub Desktop.

Select an option

Save jkuemerle/3296254 to your computer and use it in GitHub Desktop.
CSRF Prevention Aspect for ASP.NET MVC and PostSharp
using System;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Web.Mvc;
using PostSharp.Aspects;
using PostSharp.Extensibility;
namespace WebApplication.Aspects
{
public class OverrideCSRFValidation : Attribute { }
[Serializable]
public class CSRFAttribute : MethodLevelAspect {
public override bool CompileTimeValidate(System.Reflection.MethodBase method) {
if (method.MemberType == MemberTypes.Method && method.GetParameters().Count() > 0) { // only check methods that have parameters
var attribs = method.GetCustomAttributes(true);
if (attribs.Length > 0) { // only check methods that are decorated with some attributes
var postAttribute = (from a in attribs where a.GetType() == typeof(System.Web.Mvc.HttpPostAttribute) select a).Count();
var bypassAttribute = (from a in attribs where a.GetType() == typeof(OverrideCSRFValidation) select a).Count();
if (postAttribute > 0 && bypassAttribute < 1) { // only bother looking for an anti-forgery attribute if this is a Post method and it does not have a bypass attribute
var antiForgeryAttribute = (from a in attribs where a.GetType() == typeof(ValidateAntiForgeryTokenAttribute) select a).Count();
if (antiForgeryAttribute < 1) {
var mi = method as MethodInfo;
string solutionFile = PostSharpEnvironment.Current.CurrentProject.EvaluateExpression("{$SolutionFile}");
if (String.IsNullOrEmpty(solutionFile) || !File.Exists(solutionFile)) // use PostSharps experimental functionality to find the method location in the code
Message.Write(PostSharp.MessageLocation.Of(mi), SeverityType.Error, "1000", "Security Error: method {0} in {1} is an HTTP Post without an anti-forgery validator.", mi.Name, method.DeclaringType.Namespace);
else { // otherwise use CodeFreud and Project Roslyn to find the method location in the code
var res = CodeFreud.Finder.FindMethod(solutionFile, method);
if (null != res)
Message.Write(PostSharp.MessageLocation.Explicit(res.SourceFile.FullName, res.LineNumber, res.ColumnNumber), SeverityType.Error, "1000", "Security Error, method {0} in {1} is an HTTP Post without an anti-forgery validator.", mi.Name, method.DeclaringType.Namespace);
else
Message.Write(PostSharp.MessageLocation.Unknown, SeverityType.Error, "1000", "Security Error: method {0} in {1} is an HTTP Post without an anti-forgery validator.", mi.Name, method.DeclaringType.Namespace);
}
return false;
}
}
}
}
return true;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment