A potentially dangerous Request.Form value was detected from the client

Viewed 1102308

Every time a user posts something containing < or > in a page in my web application, I get this exception thrown.

I don't want to go into the discussion about the smartness of throwing an exception or crashing an entire web application because somebody entered a character in a text box, but I am looking for an elegant way to handle this.

Trapping the exception and showing

An error has occurred please go back and re-type your entire form again, but this time please do not use <

doesn't seem professional enough to me.

Disabling post validation (validateRequest="false") will definitely avoid this error, but it will leave the page vulnerable to a number of attacks.

Ideally: When a post back occurs containing HTML restricted characters, that posted value in the Form collection will be automatically HTML encoded. So the .Text property of my text-box will be something & lt; html & gt;

Is there a way I can do this from a handler?

47 Answers

I think you are attacking it from the wrong angle by trying to encode all posted data.

Note that a "<" could also come from other outside sources, like a database field, a configuration, a file, a feed and so on.

Furthermore, "<" is not inherently dangerous. It's only dangerous in a specific context: when writing strings that haven't been encoded to HTML output (because of XSS).

In other contexts different sub-strings are dangerous, for example, if you write an user-provided URL into a link, the sub-string "javascript:" may be dangerous. The single quote character on the other hand is dangerous when interpolating strings in SQL queries, but perfectly safe if it is a part of a name submitted from a form or read from a database field.

The bottom line is: you can't filter random input for dangerous characters, because any character may be dangerous under the right circumstances. You should encode at the point where some specific characters may become dangerous because they cross into a different sub-language where they have special meaning. When you write a string to HTML, you should encode characters that have special meaning in HTML, using Server.HtmlEncode. If you pass a string to a dynamic SQL statement, you should encode different characters (or better, let the framework do it for you by using prepared statements or the like)..

When you are sure you HTML-encode everywhere you pass strings to HTML, then set ValidateRequest="false" in the <%@ Page ... %> directive in your .aspx file(s).

In .NET 4 you may need to do a little more. Sometimes it's necessary to also add <httpRuntime requestValidationMode="2.0" /> to web.config (reference).

You can HTML encode text box content, but unfortunately that won't stop the exception from happening. In my experience there is no way around, and you have to disable page validation. By doing that you're saying: "I'll be careful, I promise."

Please bear in mind that some .NET controls will automatically HTML encode the output. For instance, setting the .Text property on a TextBox control will automatically encode it. That specifically means converting < into &lt;, > into &gt; and & into &amp;. So be wary of doing this...

myTextBox.Text = Server.HtmlEncode(myStringFromDatabase); // Pseudo code

However, the .Text property for HyperLink, Literal and Label won't HTML encode things, so wrapping Server.HtmlEncode(); around anything being set on these properties is a must if you want to prevent <script> window.location = "http://www.google.com"; </script> from being output into your page and subsequently executed.

Do a little experimenting to see what gets encoded and what doesn't.

In the web.config file, within the tags, insert the httpRuntime element with the attribute requestValidationMode="2.0". Also add the validateRequest="false" attribute in the pages element.

Example:

<configuration>
  <system.web>
   <httpRuntime requestValidationMode="2.0" />
  </system.web>
  <pages validateRequest="false">
  </pages>
</configuration>

If you don't want to disable ValidateRequest you need to implement a JavaScript function in order to avoid the exception. It is not the best option, but it works.

function AlphanumericValidation(evt)
{
    var charCode = (evt.charCode) ? evt.charCode : ((evt.keyCode) ? evt.keyCode :
        ((evt.which) ? evt.which : 0));

    // User type Enter key
    if (charCode == 13)
    {
        // Do something, set controls focus or do anything
        return false;
    }

    // User can not type non alphanumeric characters
    if ( (charCode <  48)                     ||
         (charCode > 122)                     ||
         ((charCode > 57) && (charCode < 65)) ||
         ((charCode > 90) && (charCode < 97))
       )
    {
        // Show a message or do something
        return false;
    }
}

Then in code behind, on the PageLoad event, add the attribute to your control with the next code:

Me.TextBox1.Attributes.Add("OnKeyPress", "return AlphanumericValidation(event);")

I guess you could do it in a module; but that leaves open some questions; what if you want to save the input to a database? Suddenly because you're saving encoded data to the database you end up trusting input from it which is probably a bad idea. Ideally you store raw unencoded data in the database and the encode every time.

Disabling the protection on a per page level and then encoding each time is a better option.

Rather than using Server.HtmlEncode you should look at the newer, more complete Anti-XSS library from the Microsoft ACE team.

The other solutions here are nice, however it's a bit of a royal pain in the rear to have to apply [AllowHtml] to every single Model property, especially if you have over 100 models on a decent sized site.

If like me, you want to turn this (IMHO pretty pointless) feature off site wide you can override the Execute() method in your base controller (if you don't already have a base controller I suggest you make one, they can be pretty useful for applying common functionality).

    protected override void Execute(RequestContext requestContext)
    {
        // Disable requestion validation (security) across the whole site
        ValidateRequest = false;
        base.Execute(requestContext);
    }

Just make sure that you are HTML encoding everything that is pumped out to the views that came from user input (it's default behaviour in ASP.NET MVC 3 with Razor anyway, so unless for some bizarre reason you are using Html.Raw() you shouldn't require this feature.

As long as these are only "<" and ">" (and not the double quote itself) characters and you're using them in context like <input value="this" />, you're safe (while for <textarea>this one</textarea> you would be vulnerable of course). That may simplify your situation, but for anything more use one of other posted solutions.

If you're just looking to tell your users that < and > are not to be used BUT, you don't want the entire form processed/posted back (and lose all the input) before-hand could you not simply put in a validator around the field to screen for those (and maybe other potentially dangerous) characters?

For those who are not using model binding, who are extracting each parameter from the Request.Form, who are sure the input text will cause no harm, there is another way. Not a great solution but it will do the job.

From client side, encode it as uri then send it.
e.g:

encodeURIComponent($("#MsgBody").val());  

From server side, accept it and decode it as uri.
e.g:

string temp = !string.IsNullOrEmpty(HttpContext.Current.Request.Form["MsgBody"]) ?
System.Web.HttpUtility.UrlDecode(HttpContext.Current.Request.Form["MsgBody"]) : 
null;  

or

string temp = !string.IsNullOrEmpty(HttpContext.Current.Request.Form["MsgBody"]) ?
System.Uri.UnescapeDataString(HttpContext.Current.Request.Form["MsgBody"]) : 
null; 

please look for the differences between UrlDecode and UnescapeDataString

in my case, using asp:Textbox control (Asp.net 4.5), instead of setting the all page for validateRequest="false" i used

<asp:TextBox runat="server" ID="mainTextBox"
            ValidateRequestMode="Disabled"
 ></asp:TextBox>

on the Textbox that caused the exception.

You should use the Server.HtmlEncode method to protect your site from dangerous input.

More info here

I know this question is about form posting, but I would like to add some details for people who received this error on others circumstances. It could also occur on a handler used to implement a web service.

Suppose your web client sends POST or PUT requests using ajax and sends either json or xml text or raw data (a file content) to your web service. Because your web service does not need to get any information from a Content-Type header, your JavaScript code did not set this header to your ajax request. But if you do not set this header on a POST/PUT ajax request, Safari may add this header: "Content-Type: application/x-www-form-urlencoded". I observed that on Safari 6 on iPhone, but others Safari versions/OS or Chrome may do the same. So when receiving this Content-Type header some part of .NET Framework assume the request body data structure corresponds to an html form posting while it does not and rose an HttpRequestValidationException exception. First thing to do is obviously to always set Content-Type header to anything but a form MIME type on a POST/PUT ajax request even it is useless to your web service.

I also discovered this detail:
On these circumstances, the HttpRequestValidationException exception is rose when your code tries to access HttpRequest.Params collection. But surprisingly, this exception is not rose when it accesses HttpRequest.ServerVariables collection. This shows that while these two collections seem to be nearly identical, one accesses request data through security checks and the other one does not.

Last but not least, please note ASP.NET Data Binding controls automatically encode values during data binding. This changes the default behavior of all ASP.NET controls (TextBox, Label etc) contained in the ItemTemplate. The following sample demonstrates (ValidateRequest is set to false):

aspx

<%@ Page Language="C#" ValidateRequest="false" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="WebApplication17._Default" %> <html> <body>
    <form runat="server">
        <asp:FormView ID="FormView1" runat="server" ItemType="WebApplication17.S" SelectMethod="FormView1_GetItem">
            <ItemTemplate>
                <asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
                <asp:Button ID="Button1" runat="server" Text="Button" OnClick="Button1_Click" />
                <asp:Label ID="Label1" runat="server" Text="<%#: Item.Text %>"></asp:Label>
                <asp:TextBox ID="TextBox2" runat="server" Text="<%#: Item.Text %>"></asp:TextBox>
            </ItemTemplate>
        </asp:FormView>
    </form> 

code behind

public partial class _Default : Page
{
    S s = new S();

    protected void Button1_Click(object sender, EventArgs e)
    {
        s.Text = ((TextBox)FormView1.FindControl("TextBox1")).Text;
        FormView1.DataBind();
    }

    public S FormView1_GetItem(int? id)
    {
        return s;
    }
}

public class S
{
    public string Text { get; set; }
}
  1. Case submit value: &#39;

Label1.Text value: &#39;

TextBox2.Text value: &amp;#39;

  1. Case submit value: <script>alert('attack!');</script>

Label1.Text value: <script>alert('attack!');</script>

TextBox2.Text value: &lt;script&gt;alert(&#39;attack!&#39;);&lt;/script&gt;

How to fix this issue for AjaxExtControls in ASP.NET 4.6.2:

We had the same problem with AjaxExtControls rich text editor. This issue started right after upgrading from .NET 2.0 to .NET 4.5. I looked at all SOF answers but could not find a solution that does not compromise with the security provided by .NET 4.5.

Fix 1(Not Recommended as it can degrade application security) : I tested after changing this attribute in requestValidationMode = "2.0 and it worked but I was concerned about the security features. So this is fix is like degrading the security for entire application.

Fix 2 (Recommended): Since this issue was only occurring with one of AjaxExtControl, I was finally able to solve this issue using the simple code below:

editorID.value = editorID.value.replace(/>/g, "&gt;");
editorID.value = editorID.value.replace(/</g, "&lt;");

This code is executed on client side (javascript) before sending the request to server. Note that the editorID is not the ID that we have on our html/aspx pages but it is the id of the rich text editor that AjaxExtControl internally uses.

I have a Web Forms application that has had this issue for a text box comments field, where users sometimes pasted email text, and the "<" and ">" characters from email header info would creep in there and throw this exception.

I addressed the issue from another angle... I was already using Ajax Control Toolkit, so I was able to use a FilteredTextBoxExtender to prevent those two characters from entry in the text box. A user copy-pasting text will then get what they were expecting, minus those characters.

<asp:TextBox ID="CommentsTextBox" runat="server" TextMode="MultiLine"></asp:TextBox>
<ajaxToolkit:FilteredTextBoxExtender ID="ftbe" runat="server" TargetControlID="CommentsTextBox" filterMode="InvalidChars" InvalidChars="<>" />

None of the answers worked for me. Then I discovered that if I removed the following code I could get it to work:

//Register action filter via Autofac rather than GlobalFilters to allow dependency injection
builder.RegisterFilterProvider();
builder.RegisterType<OfflineActionFilter>()
    .AsActionFilterFor<Controller>()
    .InstancePerLifetimeScope();

I can only conclude that something in Autofac's RegisterFilterProvider breaks or overrides the validateRequest attribute

Even after adding <httpRuntime requestValidationMode="2.0"> to web.config I still kept getting the error in an application that uses WIF for authentication.
What solved for me was adding <sessionState mode="InProc" cookieless="UseUri"/> inside the <system.web> element.

Related