1212 */
1313
1414import csharp
15+ import semmle.code.csharp.commons.Compilation
1516import semmle.code.csharp.frameworks.system.Web
1617import semmle.code.csharp.frameworks.system.web.Helpers
1718import semmle.code.csharp.frameworks.system.web.Mvc
@@ -34,20 +35,41 @@ private Method getAStartedMethod() {
3435 getAStartedMethod ( ) .calls ( result )
3536}
3637
37- /**
38- * Holds if the project has a global anti forgery filter.
39- *
40- * No AspNetCore case here as the corresponding class doesn't seem to exist.
41- */
42- predicate hasGlobalAntiForgeryFilter ( ) {
43- // A global filter added
38+ private predicate hasGlobalWebMvcAntiforgeryFilter ( Compilation compilation ) {
4439 exists ( MethodCall addGlobalFilter |
4540 // addGlobalFilter adds a filter to the global filter collection
4641 addGlobalFilter .getTarget ( ) = any ( GlobalFilterCollection gfc ) .getAddMethod ( ) and
4742 // The filter is an antiforgery filter
4843 addGlobalFilter .getArgumentForName ( "filter" ) .getType ( ) instanceof AntiForgeryAuthorizationFilter and
4944 // The filter is added by the Application_Start() method
50- getAStartedMethod ( ) = addGlobalFilter .getEnclosingCallable ( )
45+ getAStartedMethod ( ) = addGlobalFilter .getEnclosingCallable ( ) and
46+ addGlobalFilter .getFile ( ) = compilation .getAFileCompiled ( )
47+ )
48+ }
49+
50+ predicate hasGlobalAspNetMvcAntiForgeryFilter ( Compilation compilation ) {
51+ exists ( MethodCall addGlobalFilter , MethodCall registrationCall |
52+ (
53+ // The filter is the `AutoValidateAntiforgeryTokenAttribute` filter.
54+ addGlobalFilter .getTarget ( ) =
55+ any ( AspNetCore:: MicrosoftAspNetCoreMvcFilterCollection collection ) .getAddMethod ( ) and
56+ (
57+ addGlobalFilter .getArgument ( 0 ) .getType ( ) instanceof
58+ AspNetCore:: AutoValidateAntiforgeryTokenAttribute or
59+ addGlobalFilter .getArgument ( 0 ) .( TypeofExpr ) .getTypeAccess ( ) .getTarget ( ) instanceof
60+ AspNetCore:: AutoValidateAntiforgeryTokenAttribute
61+ )
62+ or
63+ addGlobalFilter .getTarget ( ) .getUnboundDeclaration ( ) =
64+ any ( AspNetCore:: MicrosoftAspNetCoreMvcFilterCollection collection ) .getAddMethod ( ) and
65+ addGlobalFilter .getTarget ( ) .( ConstructedGeneric ) .getTypeArgument ( 0 ) instanceof
66+ AspNetCore:: AutoValidateAntiforgeryTokenAttribute
67+ ) and
68+ // The filter is added in an ASP.NET Core registration call, which is provided as a lambda argument
69+ // to the Mvc registration method.
70+ registrationCall .getTarget ( ) instanceof AspNetCore:: MicrosoftAspNetCoreMvcRegistration and
71+ registrationCall .getAnArgument ( ) = addGlobalFilter .getEnclosingCallable ( ) and
72+ addGlobalFilter .getFile ( ) = compilation .getAFileCompiled ( )
5173 )
5274}
5375
@@ -67,11 +89,12 @@ private class RequireAntiforgeryTokenAttribute extends Attribute {
6789 }
6890}
6991
70- private predicate hasAspNetCoreAntiForgeryMiddleware ( ) {
92+ private predicate hasAspNetCoreAntiForgeryMiddleware ( Compilation compilation ) {
7193 exists ( MethodCall call |
7294 call .getTarget ( )
7395 .hasFullyQualifiedName ( "Microsoft.AspNetCore.Builder" ,
74- "AntiforgeryApplicationBuilderExtensions" , "UseAntiforgery" )
96+ "AntiforgeryApplicationBuilderExtensions" , "UseAntiforgery" ) and
97+ call .getFile ( ) = compilation .getAFileCompiled ( )
7598 )
7699}
77100
@@ -106,7 +129,12 @@ private RequireAntiforgeryTokenAttribute getEffectiveRequireAntiforgeryTokenAttr
106129class MvcControllerPostMethod extends Method {
107130 private Controller controller ;
108131
109- MvcControllerPostMethod ( ) { controller .getAPostActionMethod ( ) = this }
132+ MvcControllerPostMethod ( ) {
133+ controller .getAPostActionMethod ( ) = this and
134+ exists ( Compilation compilation | compilation .getAFileCompiled ( ) = this .getFile ( ) |
135+ not hasGlobalWebMvcAntiforgeryFilter ( compilation )
136+ )
137+ }
110138
111139 predicate hasValidateAntiForgeryAttribute ( ) {
112140 this .getAnAttribute ( ) instanceof ValidateAntiForgeryTokenAttribute or
@@ -116,10 +144,13 @@ class MvcControllerPostMethod extends Method {
116144
117145class AspNetCoreControllerPostMethod extends Method {
118146 private AspNetCore:: MicrosoftAspNetCoreMvcController controller ;
147+ private Compilation compilation ;
119148
120149 AspNetCoreControllerPostMethod ( ) {
121150 controller .getAnActionMethod ( ) = this and
122- this .getAnAttribute ( ) instanceof AspNetCore:: MicrosoftAspNetCoreMvcHttpPostAttribute
151+ this .getAnAttribute ( ) instanceof AspNetCore:: MicrosoftAspNetCoreMvcHttpPostAttribute and
152+ compilation .getAFileCompiled ( ) = this .getFile ( ) and
153+ not hasGlobalAspNetMvcAntiForgeryFilter ( compilation )
123154 }
124155
125156 predicate hasValidateAntiForgeryAttribute ( ) {
@@ -128,7 +159,7 @@ class AspNetCoreControllerPostMethod extends Method {
128159 }
129160
130161 predicate hasRequireAntiForgeryAttribute ( ) {
131- hasAspNetCoreAntiForgeryMiddleware ( ) and
162+ hasAspNetCoreAntiForgeryMiddleware ( compilation ) and
132163 (
133164 getEffectiveRequireAntiforgeryTokenAttributeOnMethod ( this ) .requiresValidation ( )
134165 or
@@ -157,7 +188,7 @@ Element getAValidatedElement() {
157188 or
158189 any ( AspNetCore:: ValidateAntiForgeryAttribute a ) .getTarget ( ) = result
159190 or
160- hasAspNetCoreAntiForgeryMiddleware ( ) and
191+ hasAspNetCoreAntiForgeryMiddleware ( _ ) and
161192 any ( RequireAntiforgeryTokenAttribute a | a .requiresValidation ( ) ) .getTarget ( ) = result
162193}
163194
@@ -167,9 +198,7 @@ where
167198 // Verify that validate anti forgery token attributes are used somewhere within this project, to
168199 // avoid reporting false positives on projects that use an alternative approach to mitigate CSRF
169200 // issues.
170- exists ( getAValidatedElement ( ) ) and
171- // Also ignore cases where a global anti forgery filter is in use.
172- not hasGlobalAntiForgeryFilter ( )
201+ exists ( getAValidatedElement ( ) )
173202select postMethod ,
174203 "Method '" + postMethod .getName ( ) +
175204 "' handles a POST request without performing CSRF token validation."
0 commit comments