MVC Hidden Field Encryption - How to decrypt more than one Server-side property

Asked

Viewed 344 times

2

Hello I’m developing a web application mvc 5 and in some cases I need to insert in the view fields @Html.Hiddenfor, only I don’t want to show the value to the user if he views the html code, So far so good I was able to encrypt the values that go to the @Html.Hiddenfor controls using the class developed by "Adam Tuliper" [credit to him for that! ], but the fact is that I can’t decorate my Controller-side Action method with more than 1 called Validateantimodelinjection extension("property1") understood ?

Follows the class developed by "Adam Tuliper" very useful!

    public class ValidateAntiModelInjection : ActionFilterAttribute
    {
        /// <summary>
        /// The name of the property we are generating a hash for.
        /// </summary>
        private readonly string _propertyName;

        /// <summary>
        /// 
        /// </summary>
        /// <param name="propertyName">The name of the property from the form to validate against the hidden encrypted form version.</param>
        public ValidateAntiModelInjection(string propertyName)
        {
            _propertyName = propertyName;
            if (string.IsNullOrEmpty(propertyName))
            {
                throw new ArgumentException("O valor propertyName deve ser uma string não vazia.");
            }
        }

        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("O campo de formulário oculto nomeado valor {0} estava faltando. Isto é criado pelos métodos Html.AntiModelInjection. Verifique se o nome usado em seu [ValidateAntiModelInjectionAttribute (\"!AQUI!\")] Corresponde ao nome do campo utilizado no método Html.AntiModelInjection. Se este atributo é utilizado em um método de controlador que se entende por HttpGet, então o valor forma que ainda não existe. Este atributo é para ser utilizado em métodos do controlador acessados 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("O valor de {0} estava faltando. Se este atributo é utilizado em um método de controlador que se entende por HttpGet, então o valor forma que ainda não existe. Este atributo é para ser utilizado em métodos do controlador acessados via HttpPost.", _propertyName));
            }

            //Now hash the 'plain text' version so we can compare to the hash originally created by Html.AntiModelInjectionFor
            string hashedFormValue = FormsAuthentication.HashPasswordForStoringInConfigFile(formValue, "SHA1");

            //And compare
            if (string.Compare(hashedFormValue, hashToken, false, CultureInfo.InvariantCulture) != 0)
            {
                throw new HttpAntiModelInjectionException(string.Format("Validação de segurança falhou para {0}. É possível que os dados foram alterados como o valor original utilizado para criar o campo de formulário não coincide com o valor da propriedade corrente para este campo.", _propertyName));
            }

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

            base.OnActionExecuting(filterContext);
        }  
    }

In short I’m not sure how to change the Extension Builder to accept more Propertys and not just one.

I can’t use

[ValidateAntiModelInjection("property1")]
[ValidateAntiModelInjection("property2")]
public ActionResult (MinhaModelDTO Model) 
{...}

after repeated extension error! but I could use it like this:

[ValidateAntiModelInjection("property1","property2")]
public ActionResult (MinhaModelDTO Model) 
{...}

or something like, don’t you think ? , someone could give the stones way to change the class ?

1 answer

0


I’ll put the code to the second form:

[ValidateAntiModelInjection("property1","property2")]
public ActionResult (MinhaModelDTO Model) 
{...}

Stay like this:

public class ValidateAntiModelInjection : ActionFilterAttribute
{
    /// <summary>
    /// The name of the property we are generating a hash for.
    /// </summary>
    private readonly string[] _properties;

    /// <summary>
    /// 
    /// </summary>
    /// <param name="propertyName">The name of the property from the form to validate against the hidden encrypted form version.</param>
    public ValidateAntiModelInjection(params string[] properties)
    {
        foreach (var property in properties {
            if (string.IsNullOrEmpty(propertyName))
            {
                throw new ArgumentException("O valor propertyName deve ser uma string não vazia.");
            }
        }

        _properties = properties;
    }

    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"
        foreach (var _propertyName in _properties) {
            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("O campo de formulário oculto nomeado valor {0} estava faltando. Isto é criado pelos métodos Html.AntiModelInjection. Verifique se o nome usado em seu [ValidateAntiModelInjectionAttribute (\"!AQUI!\")] Corresponde ao nome do campo utilizado no método Html.AntiModelInjection. Se este atributo é utilizado em um método de controlador que se entende por HttpGet, então o valor forma que ainda não existe. Este atributo é para ser utilizado em métodos do controlador acessados 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("O valor de {0} estava faltando. Se este atributo é utilizado em um método de controlador que se entende por HttpGet, então o valor forma que ainda não existe. Este atributo é para ser utilizado em métodos do controlador acessados via HttpPost.", _propertyName));
            }

            //Now hash the 'plain text' version so we can compare to the hash originally created by Html.AntiModelInjectionFor
            string hashedFormValue = FormsAuthentication.HashPasswordForStoringInConfigFile(formValue, "SHA1");

            //And compare
            if (string.Compare(hashedFormValue, hashToken, false, CultureInfo.InvariantCulture) != 0)
            {
                throw new HttpAntiModelInjectionException(string.Format("Validação de segurança falhou para {0}. É possível que os dados foram alterados como o valor original utilizado para criar o campo de formulário não coincide com o valor da propriedade corrente para este campo.", _propertyName));
            }

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

            base.OnActionExecuting(filterContext);
        }  
    }
}

Browser other questions tagged

You are not signed in. Login or sign up in order to post.