Antiforgery Token for web Api Purposes

Karab0

Member
Joined
Dec 15, 2016
Messages
12
Good Day

Please excuse me for the small snippets of code. I hope you will get bigger picture despite that.

I am using an odata rest service running on asp net web api.
I use a knockout-js model with which has a submit method which post it's property to the the service. To avoid Cross Site Request Forgery I have come up with this little scheme. So I would just like to know how dangerous is this setup based on the AntiforgeryTokenCheatAttribute and how I am planning on using it withing my java script
JavaScript:
Model.submit = function()
{
    let data = ko.mapping.ToJS(this);
    data['_RequestVerificationToken'] = $.cookie('ForgeryToken');
    $.post('odata/Model', data);
}

C#:
 public class AntiForgeryTokenCheatAttribute: IResultFilter
    {
        const string CookieName = "ForgeryToken";
        public void OnResultExecuted(ResultExecutedContext filterContext)
        {
            var cookies = filterContext.HttpContext.Response.Cookies;
            var antiforgery = cookies[AntiForgeryConfig.CookieName];
            if (cookies.AllKeys.Contains(CookieName))
            {
                var old = cookies[CookieName];
                old.Value = antiforgery.Value;
                filterContext.HttpContext.Response.Cookies.Set(old);
            }
            else
            {
                var available = new HttpCookie("ForgeryToken");
                available.HttpOnly = false;
                available.Value = antiforgery.Value;
                filterContext.HttpContext.Response.Cookies.Add(available);
            }

        }

        public void OnResultExecuting(ResultExecutingContext filterContext)
        {
            throw new NotImplementedException();
        }
    }

Please note adding the antiforgery hidden element will not work for my purposes. Since the initial submit will send a correct antiforgery token. Then during that request the antiforgery cookie value is updated, but my local copy of
the hidden element is left unchanged then all subsequent submit calls will fail.

Comment will be very much appreciated and any alternatives.

I have decided to add the controller to picture to help make the picture clearer of what I am trying to do.
Code:
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using System.Web.Http.ModelBinding;
using System.Web.Http.OData;
using System.Web.Http.OData.Query;
using System.Web.Http.OData.Routing;
using LIMModule;
using Microsoft.Data.OData;

namespace WMS.Controllers.Api
{
    
    [EnableQuery]
    public class ConsumableItemsController : AbstractLIMODataController
    {
        public ConsumableItemsController(ILIMRepository repository): base(repository)
        {

        }

        // GET: odata/ConsumableItems
        public IQueryable<ConsumableItem> GetConsumableItems()
        {
            return LIMRepository.ConsumbaleItems;
        }

        // GET: odata/ConsumableItems(5)
        public SingleResult<ConsumableItem> GetConsumableItem([FromODataUri] int key)
        {
            return SingleResult.Create<ConsumableItem>(
                LIMRepository.ConsumbaleItems.Where(item => item.ID == key)
                );
        }

        // PUT: odata/ConsumableItems(5)
        public IHttpActionResult Put([FromODataUri] int key, Delta<ConsumableItem> delta)
        {
            
            return StatusCode(HttpStatusCode.NotImplemented);
        }

        // POST: odata/ConsumableItems
        [System.Web.Mvc.ValidateAntiForgeryToken]
        public IHttpActionResult Post(ConsumableItem consumableItem)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }

            // TODO: Add create logic here.
            LIMRepository.Add(consumableItem);
            return Created(consumableItem);
            
        }

        // PATCH: odata/ConsumableItems(5)
        [AcceptVerbs("PATCH", "MERGE")]
        [System.Web.Mvc.ValidateAntiForgeryToken]
        public IHttpActionResult Patch([FromODataUri] int key, Delta<ConsumableItem> delta)
        {
            Validate(delta.GetEntity());

            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }

            // TODO: Get the entity here.
            var consumableItem = LIMRepository.ConsumbaleItems.Where(item => item.ID == key && delta.GetEntity().ID == key).Single();
            delta.Patch(consumableItem);

            // TODO: Save the patched entity.
            LIMRepository.Edit(consumableItem);
            return Updated(consumableItem);
            
        }

        // DELETE: odata/ConsumableItems(5)
        [System.Web.Mvc.ValidateAntiForgeryToken]
        public IHttpActionResult Delete([FromODataUri] int key)
        {
            // TODO: Add delete logic here.
            var consumableItem = LIMRepository.ConsumbaleItems.Where( item => item.ID == key).Single();
            LIMRepository.Delete(consumableItem);
            return StatusCode(HttpStatusCode.NoContent);
            
        }
    }
}
 
Last edited:

_kabal_

Expert Member
Joined
Oct 24, 2005
Messages
4,476
How is your web api secured? Do you use a token or is it just session based?
 

Solarion

Honorary Master
Joined
Nov 14, 2012
Messages
20,940
Also have a session expiry which kills any left over cookies or tokens left behind. Not done web development in several years so don't quote me on that.
 
Top