Wai Yan Hein
Wai Yan Hein

Reputation: 14791

Submitting ASP.NET MVC CSRF token with $http in AngularJS

I am developing an ASP.NET MVC Web Application. I am using AngularJS. But I am having a problem with submitting post form to server because of CSRF validation. First of all, I am new to AngularJS.

In AngularJS, I am submitting form like this on button click event

angular.module('loginApp', ['ui.bootstrap', 'blockUI']).controller('loginController', function ($scope) {

    $scope.loginFormData = { }

    $scope.submitLoginForm = function()
    {
        $http.post("url", $scope.loginFormData, function (response) {

        })
    }
});

At server side, I do CSRF validation to form post

        [HttpPost]
        [AllowAnonymous]
        [ValidateAntiForgeryToken]
        public async Task<JsonResult> Login(LoginViewModel model)
        {
            //Do other stuff
        }

Here is my form HTML:

            @Html.AntiForgeryToken()
            <div class="lock-container">
                <div class="panel panel-default text-center paper-shadow" data-z="0.5">
                    <div class="panel-body">
                        <div class="form-group">
                            <div class="form-control-material">
                                <input class="form-control" ng-model="username" type="text" placeholder="Username">
                                @Html.LabelFor(x => x.UserName)
                            </div>
                        </div>
                        <div class="form-group">
                            <div class="form-control-material">
                                <input class="form-control" ng-model="password" type="password" placeholder="Enter Password">
                                @Html.LabelFor(x=>x.Password)
                            </div>
                        </div>

                        <button ng-click="submitLoginForm()" class="btn btn-primary">Login <i class="fa fa-fw fa-unlock-alt"></i></button>
                    </div>
                </div>
            </div>

Actually it is not a form. I am just submitting data with Ajax basically. You noticed @Html.AntiForgeryToken() at the top. When I inspect in browser, I can see like this.

enter image description here

What I want to do is I want to get that token value and send in the $http post like below.

$http.post("url",{ "_RequestVerificationToken": $scope.csrfToken }, function (response) {

        })

If I send like above, csrf validation will be successful at the server. How can I achieve it it AngularJS?

Upvotes: 0

Views: 1846

Answers (3)

AshanMG
AshanMG

Reputation: 43

In order to csrf validation to be successful at the server, You need to do some modification in your server-side.

you can create a custom filter attribute in your server-side to validate your anti-forgery token.

Create a class and inherited it from ActionFilterAttribute which is provided by System.Web.MVC. Make sure not to use the web API namespaces.

using System;
using System.Web.Helpers;
using System.Web.Mvc;

namespace CustomFilters.Web.Filters
{
    public class MVCAntiForgeryTokenValidatorAttribute : ActionFilterAttribute
    {
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            if (filterContext == null)
            {
                throw new ArgumentNullException("filterContext");
            }

            if (filterContext.HttpContext.Request.HttpMethod != "GET")
            {
                var header = filterContext.HttpContext.Request.Headers.Get("_RequestVerificationToken");

                var cookieName = AntiForgeryConfig.CookieName; // this also same as the _RequestVerificationToken
                var tokenCookie = filterContext.HttpContext.Request.Cookies.Get(cookieName);

                var tokenHeader = string.Empty;
                if (!string.IsNullOrEmpty(headers))
                {
                    tokenHeader = header;
                }

                AntiForgery.Validate(tokenCookie != null ? tokenCookie.Value : null, tokenHeader);
            }

            base.OnActionExecuting(filterContext);
        }
    }
}

Then you need to modify your method using above created custom attribute

[HttpPost]
[AllowAnonymous]
[MVCAntiForgeryTokenValidator]
public async Task<JsonResult> Login(LoginViewModel model)
{
    //Do other stuff
}

Then you are done. when your method got hit by the angularJs service method, before executing the class method. It will validate the anti-forgery token first.

Upvotes: 2

Ufuk Aydın
Ufuk Aydın

Reputation: 158

Add token to FormData

 var formData = new FormData();
    formData.append("__RequestVerificationToken", token);
    formData.append("UserName", $scope.kullaniciAdi);
    formData.append("Password", $scope.sifre);

    $http({
        method: 'POST',
        url: '/Login/Login',
        data: formData,
        transformRequest: angular.identity, 
        headers: { 'Content-Type': undefined }

    }).then(function successCallback(response) {



    }, function errorCallback(response) {

    });

Upvotes: 0

Thanigainathan
Thanigainathan

Reputation: 1547

You can pass those values in headers instead of the body content. This can be done globally for that module. Refer below links.

angular.module('app')
.run(function ($http) {
$http.defaults.headers.common['X-XSRF-Token'] =
    angular.element('input[name="__RequestVerificationToken"]').attr('value');

});

Please refer this link

AngularJS Web Api AntiForgeryToken CSRF

https://www.asp.net/web-api/overview/security/preventing-cross-site-request-forgery-csrf-attacks

Upvotes: 0

Related Questions