+
+Web applications that use tokens to prevent cross-site request forgery
+(CSRF) should validate the tokens for all Http POST requests.
+
+Although login and authentication methods are not vulnerable to traditional
+CSRF attacks, they still need to be protected with a token or other mitigation.
+This because an unprotected login page can be used by an attacker to force a
+login using an account controlled by the attacker. Subsequent requests to the
+site are then made using this account, without the user being aware that this is
+the case. This can result in the user associating private information with the
+attacker-controlled account.
+
+
+
+The appropriate attribute should be added to this method to ensure the
+anti-forgery token is validated when this action method is called. If using the
+MVC-provided anti-forgery framework this will be the
+[ValidateAntiForgeryToken]
attribute.
+
+Alternatively, you may consider including a global filter that applies token
+validation to all POST requests.
+
+
+
+
+In the following example an ASP.NET MVC Controller
is using the
+[ValidateAntiForgeryToken]
attribute to mitigate against CSRF attacks.
+It has been applied correctly to the UpdateDetails
method. However,
+this attribute has not been applied to the Login
method. This should
+be fixed by adding this attribute.
+
+
+
+
+Wikipedia: Cross-Site Request Forgery.
+Microsoft Docs: XSRF/CSRF Prevention in ASP.NET MVC and Web Pages.
+
+
diff --git a/csharp/CWE-352/MissingAntiForgeryTokenValidationAspNetCore.ql b/csharp/CWE-352/MissingAntiForgeryTokenValidationAspNetCore.ql
new file mode 100644
index 00000000000..3ac5fd10695
--- /dev/null
+++ b/csharp/CWE-352/MissingAntiForgeryTokenValidationAspNetCore.ql
@@ -0,0 +1,180 @@
+/**
+ * @name Missing cross-site request forgery token validation
+ * @description Handling a POST request without verifying that the request came from the user
+ * allows a malicious attacker to submit a request on behalf of the user.
+ * @kind problem
+ * @problem.severity error
+ * @security-severity 8.8
+ * @precision high
+ * @id cs/web/missing-token-validation-aspnetcore
+ * @tags security
+ * external/cwe/cwe-352
+ */
+
+import csharp
+import semmle.code.csharp.frameworks.system.Web
+import semmle.code.csharp.frameworks.system.web.Helpers as Helpers
+import semmle.code.csharp.frameworks.system.web.Mvc as Mvc
+import semmle.code.csharp.frameworks.microsoft.AspNetCore as AspNetCore
+
+class AntiForgeryClass extends Class {
+ AntiForgeryClass() {
+ this instanceof Helpers::AntiForgeryClass or
+ this instanceof AspNetCore::AntiForgeryClass
+ }
+
+ /** Gets the `Validate` method. */
+ Method getValidateMethod() {
+ result = this.(Helpers::AntiForgeryClass).getValidateMethod() or
+ result = this.(AspNetCore::AntiForgeryClass).getValidateMethod()
+ }
+}
+
+class ValidateAntiForgeryTokenAttribute extends Attribute {
+ ValidateAntiForgeryTokenAttribute() {
+ this instanceof Mvc::ValidateAntiForgeryTokenAttribute or
+ this instanceof AspNetCore::ValidateAntiForgeryAttribute
+ }
+}
+
+class Controller extends Class {
+ Controller() {
+ this instanceof Mvc::Controller
+ or this instanceof AspNetCore::MicrosoftAspNetCoreMvcController
+ }
+
+ Method getAPostActionMethod() {
+ result = this.(Mvc::Controller).getAPostActionMethod() or
+ exists(Method method|
+ method = this.(AspNetCore::MicrosoftAspNetCoreMvcController).getAnActionMethod()
+ and method.getAnAttribute() instanceof AspNetCore::MicrosoftAspNetCoreMvcHttpPostAttribute
+ and result = method
+ )
+ }
+}
+
+/** An `AuthorizationFilter` that calls the `AntiForgery.Validate` method. */
+class AntiForgeryAuthorizationFilter extends Mvc::AuthorizationFilter {
+ AntiForgeryAuthorizationFilter() {
+ getOnAuthorizationMethod().calls*(any(AntiForgeryClass a).getValidateMethod())
+ }
+}
+
+class AutoValidateAntiForgeryTokenFilter extends Expr {
+ AutoValidateAntiForgeryTokenFilter() {
+ exists(MethodCall addControllers, LambdaExpr lambda, ParameterAccess options, PropertyCall filters, MethodCall add |
+ // "AddMvc", "AddControllersWithViews", "AddMvcCore", "AddControllers", "AddRazorPages", so generalised to "Add*" to future-proof
+ addControllers.getTarget().getName().matches("Add%") and
+ addControllers.getArgument(1) = lambda and
+ lambda.getAParameter().getAnAccess() = options and
+ filters.getQualifier() = options and
+ filters.getTarget().getName() = "get_Filters" and
+ add.getQualifier() = filters and
+ add.getTarget().getUndecoratedName() = "Add" and
+ this = add and
+ (
+ // new AutoValidateAntiforgeryTokenAttribute()
+ exists(ObjectCreation obj |
+ add.getArgument(0) = obj and
+ obj.getType() instanceof AutoValidateAntiforgeryTokenAttributeType
+ )
+ or
+ // typeof(AutoValidateAntiforgeryTokenAttribute)
+ exists(TypeAccess access |
+ add.getArgument(0).(TypeofExpr).getAChild() = access and
+ access.getType() instanceof AutoValidateAntiforgeryTokenAttributeType
+ )
+ or
+ // Add