1

Im building my own web service on the premise of 2-legged OAuth.

With each authenticated request there will be an included HMAC.

I know it could be done like this:

public ActionResult userInfoExample(string HMAC, string username)
    {
        MyMembership.checkHMAC(HMAC);
        //get user
        return View();
    }

but that is fairly nasty, because HMAC needs to be included in the parameters for every action. Its weakly typed and crap.

I wanted to do something like this:

[AuthorizeHMAC]
    public ActionResult userInfoExample(string username)
    {
        //get user
        return View();
    }

I found this, and it mentioned I should look at Custom Modal Binders, so then I found this and after reading it I am unsure how I could make that work.

My goal is to authenticate (/authorise) using a HMAC that (I assume) is placed in the URL parameters i.e.: http:// www.website.com/foo/bar?username=xxx&hmac=xxxxxxxxx

I would like to know if anyone has any references I can read or a direct solution.
I am also welcome to criticism on my fundamental understanding of API security, or how I am doing things, I am fairly new to this area of

Community
  • 1
  • 1
MrJD
  • 1,879
  • 1
  • 23
  • 40

1 Answers1

1

Check out my code at http://mvcsecurity.codeplex.com/

I do something similar to validate parameters on the page (it is not an HMAC though). Since you will be generating it on the View Im assuming (or passing it to the view) you can check it the same way a similar way I check it in my attribute.

From:


        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            //The hidden form field that contains our hash - for ex. CustomerId is rendered as a hidden input  id="_CustomerIdToken"
            string encryptedPropertyName = string.Format("_{0}Token", _propertyName);

            //grab the token
            string hashToken = filterContext.HttpContext.Request.Form[encryptedPropertyName];

            //The encrypted form data MUST be there. We do not allow empty strings otherwise this could give
            //an attack vector in our filter as a means to bypass checks by simply passing in an empty validation token.
            if (string.IsNullOrEmpty(hashToken))
            {
                throw new MissingFieldException(string.Format("The hidden form field named value {0} was missing. This is created by the Html.AntiModelInjection methods. Ensure the name used on your [ValidateAntiModelInjectionAttribute(\"!HERE!\")] matches the field name used in Html.AntiModelInjection method. If this attribute is used on a controller method that is meant for HttpGet, then the form value would not yet exist. This attribute is meant to be used on controller methods accessed via HttpPost.", encryptedPropertyName));
            }


            //Get the plain text value
            string formValue = filterContext.HttpContext.Request.Form[_propertyName];

            //Plain text must be available to compare.
            if (string.IsNullOrEmpty(formValue))
            {
                throw new MissingFieldException(string.Format("The form value {0} was missing. If this attribute is used on a controller method that is meant for HttpGet, then the form value would not yet exist. This attribute is meant to be used on controller methods accessed via HttpPost.", _propertyName));
            }


            //We cannot encrypt the form value and compare to the previously encrypted form token.
            //Each time you Encrypt() with the MachineKey class even using the same plain text, the end result is difference.
            byte[] plainTextBytes = MachineKey.Decode(hashToken, MachineKeyProtection.Encryption);

            string plainText = Encoding.Unicode.GetString(plainTextBytes);

            //And compare
            if (string.Compare(plainText, formValue , false, CultureInfo.InvariantCulture) != 0)
            {
                throw new HttpAntiModelInjectionException(string.Format("Failed security validation for {0}. It is possible the data was tampered with as the original value used to create the form field does not match the current property value for this field. Ensure if this is a web farm, the machine keys are the same.",_propertyName));
            }


            filterContext.HttpContext.Trace.Write("(Logging Filter)Action Executing: " +
                filterContext.ActionDescriptor.ActionName);

            base.OnActionExecuting(filterContext);
        }

Adam Tuliper
  • 29,982
  • 4
  • 53
  • 71
  • That site is rather confusing. Can you post a snippet of the related code here? ( also I'm on my tablet so I don't have anything to view it) – MrJD Apr 13 '12 at 06:21
  • Source is at: http://mvcsecurity.codeplex.com/SourceControl/changeset/view/13151#149140 relevant section posted above to read the form value in the attribute – Adam Tuliper Apr 13 '12 at 16:34