27

First, I want to let everyone know that I am using an aspx engine not a Razor engine.

I have a table within a form. One of my textbox contains html tags like

</br>Phone: </br> 814-888-9999 </br> Email: </br> [email protected].  

When I go to build it it it gives me an error that says:

A potentially dangerous Request.Form value was detected from the client (QuestionAnswer="...ics Phone:<br/>814-888-9999<br...").

I tried the validation request="false" but it did not work.

I am sorry I didn't add my html code for you to look at so far. I am pulling some question up where I can edit it, if need be.

 <%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master"   Inherits="System.Web.Mvc.ViewPage<dynamic>" %>


<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
EditFreqQuestionsUser
</asp:Content>

<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<script type="text/javascript">
$(document).ready(function () {
    $("#freqQuestionsUserUpdateButton").click(function () {
        $("#updateFreqQuestionsUser").submit();
    });
});
</script>
<h2>Edit Freq Questions User </h2>

<%Administrator.AdminProductionServices.FreqQuestionsUser freqQuestionsUser =   ViewBag.freqQuestionsUser != null ? ViewBag.freqQuestionsUser : new   Administrator.AdminProductionServices.FreqQuestionsUser(); %>
<%List<string> UserRoleList = Session["UserRoles"] != null ? (List<string>)Session["UserRoles"] : new List<string>(); %>
<form id="updateFreqQuestionsUser" action="<%=Url.Action("SaveFreqQuestionsUser","Prod")%>" method="post" onsubmit+>
<table> 
    <tr>
        <td colspan="3" class="tableHeader">Freq Questions User Details <input type ="hidden" value="<%=freqQuestionsUser.freqQuestionsUserId%>" name="freqQuestionsUserId"/> </td>
    </tr>
     <tr>
        <td colspan="2" class="label">Question Description:</td>
        <td class="content">
            <input type="text" maxlength="2000" name="QuestionDescription" value="  <%=freqQuestionsUser.questionDescription%>" />
        </td>
    </tr>
     <tr>
        <td colspan="2" class="label">QuestionAnswer:</td>
        <td class="content">
            <input type="text" maxlength="2000" name="QuestionAnswer" value="<%=freqQuestionsUser.questionAnswer%>" />
        </td>
    </tr>
    <tr>
        <td colspan="3" class="tableFooter">
                <br />
                <a id="freqQuestionsUserUpdateButton" href="#" class="regularButton">Save</a>
                <a href="javascript:history.back()" class="regularButton">Cancel</a>
        </td> 
    </tr>
    </table>
      </form>
</asp:Content>

7 Answers 7

32

before the page is submitted you need to html encode the textbox's value, with window.escape(...)

If you need the un-escaped text on the server side then use HttpUtility.UrlDecode(...) method.

very quick sample:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm1.aspx.cs" Inherits="SO.WebForm1" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
    <script>
        function makeSafe() {
            document.getElementById('TextBox1').value = window.escape(document.getElementById('TextBox1').value);
        };

        function makeDangerous() {
            document.getElementById('TextBox1').value = window.unescape(document.getElementById('TextBox1').value);
        }
    </script>
</head>
<body>
    <form id="form1" runat="server" onsubmit="makeSafe();">
    <div>
        <asp:TextBox ID="TextBox1" runat="server" TextMode="MultiLine" Rows="10" ClientIDMode="Static"></asp:TextBox>
    </div>
    <asp:Button ID="Button1" runat="server" Text="Button" />
    </form>


     <script>
         makeDangerous();
    </script>
</body>
</html>

Make these changes to your code:

<script type="text/javascript">
    $(document).ready(function () {
        makeDangerous();
        $("#freqQuestionsUserUpdateButton").click(function () {
            makeSafe();
            $("#updateFreqQuestionsUser").submit();
        });
    });

    // Adding an ID attribute to the inputs you want to validate is simplest
    // Better would be to use document.getElementsByTagName and filter the array on NAME
    // or use a JQUERY select....

    function makeSafe() {
        document.getElementById('QuestionAnswer').value = window.escape(document.getElementById('QuestionAnswer').value);
    };

    // In this case adding the HTML back to a textbox should be 'safe'
    // You should be very wary though when you use it as actual HTML
    // You MUST take steps to ensure the HTML is safe.
    function makeDangerous() {
        document.getElementById('QuestionAnswer').value = window.unescape(document.getElementById('QuestionAnswer').value);
    }
</script>
Sign up to request clarification or add additional context in comments.

1 Comment

In case anyone ends up here from a web search, the window.escape is deprecated, you should use encodeURI instead: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
14

Decorate your controller action with the [ValidateInput] attribute:

[ValidateInput(false)]
[HttpPost]
public ActionResult Foo(MyViewModel model)
{
    ...
}

9 Comments

-1: While this is a valid answer, it's not a good one. I don't think it's a good idea to suggest users should blindly disable validation. Instead, they should determine why validation is failing and then come up with a solution that doesn't just shut off an important security mechanism. Suggestions like those provided by Ted Spence and Adrian are a good place to start.
@KevinBabcock, important security mechanism? I laugh at that. Could you please explain what is so much important about this validation? Also you are disabling validation only for this particular action. In ASP.NET MVC 3 you could achieve even a more fine grained logic by decorating your view model properties with the [AllowHtml] attribute. What's the point of using javascript to escape the user input before submitting?
Seriously? You are arguing that input validation is laughable and unimportant? "Improper neutralization" of user input is listed in first 3 of the top 25 security vulnerabilities in software today. You just told the guy to disable input validation with no explanation at all. No explanation, no alternative, nothing.
What's the point of using encoding user input before submitting it to the server? Check out XSS prevention rule #2. Obviously that's only a first-line defense and input should also be validated on the server.
This is old , but @DarinDimitrov is right on , I know how to validate my own inputs , here I specifically want HTML allowed - like the title says.
|
3

Client JavaScript:

function codificarTags() 
{
     document.getElementById('txtDescripcion').value = document.getElementById('txtDescripcion').value.replace(/</g,'&lt;').replace(/>/g,'&gt;');
}
    
<form id="form1" runat="server" onsubmit="codificarTags();">

Server:

protected void Page_Load(object sender, EventArgs e)
{
     txtDescripcion.Text = txtDescripcion.Text.Replace(@"&lt;", @"<").Replace(@"&gt;", @">");
}

Comments

1

I would suggest using the AjaxControlToolkit's HTML Editor. I'm implementing that now. If you're textbox is multi-line and big enough to accommodate HTML, why not just bump it up to an HTML editor. Your user will be happier too.

http://www.asp.net/ajaxLibrary/AjaxControlToolkitSampleSite/HTMLEditor/HTMLEditor.aspx

Comments

0

Using html in textbox is not a good practice, maybe use linebreaks (Environment.NewLine) or \r\n instead of br ? .NET Reference

Example (in C#) :

textBox1.Multiline = true;
textBox1.Text = "test" + Environment.NewLine + "test2";

4 Comments

I can use that in the text box/ /n or /r?
I put the \n in the text box it didn't work. It did not give me an error either. it just inputted the\n so now its like \n814-888-9999
@Yusuf if the type of the textbox is multiline, it does! Use text1.text= "test" + "\r\n" + "test2";
Sorry,I inversed \n and \r, that's \r\n in order to work. Change freqQuestionsUser.questionAnswer and it should be fine
0

I took a bit of a different approach. I wanted to use html textboxes widely across my application. I made a user control which would avoid editing the javascript every time I added a new control. My entire control is very custom but the heart of the html handling is as seen below.

The UserControl markup has some simple javascript to escape and unescape the textbox.

<script type="text/javascript">

    function UnescapeControl(clientId) {
            $('#' + clientId).val(window.unescape($('#' + clientId).val()));
    }

    function EscapeAllControls() {
       var escapeControList = JSON.parse('<%= new System.Web.Script.Serialization.JavaScriptSerializer().Serialize(EscapeControlList) %>');
       for (var i = 0; i < escapeControList.length; i++) 
           EscapeControl(escapeControList[i]);            
    }

    function EscapeControl(textClientId) {
       document.getElementById(textClientId).value = window.escape(document.getElementById(textClientId).value); 
    }
</script>

<asp:TextBox ID="Txt_SavableText" CssClass="form-control" Width="100%" runat="server" ></asp:TextBox>

The code behind is responsible for escaping the controls before the post back using RegisterOnSubmitStatement and unescaping them using RegisterStartupScript after the post back.

public partial class SavableTextBox : System.Web.UI.UserControl
{

    public List<string> EscapeControlList
    {
        get
        {
            if (Session["STB_EscapeControlList"] == null)
                Session["STB_EscapeControlList"] = new List<string>();
            
            return (List<string>)Session["STB_EscapeControlList"];
        }
        set { Session["STB_EscapeControlList"] = value; }
    }

    

    protected void Page_Load(object sender, EventArgs e)
    {
        if (EscapeHtmlOnPostback && !EscapeControlList.Contains(GetClientId()))
            EscapeControlList.Add(GetClientId());

        // When using a script manager, you should use ScriptManager instead of ClientScript.
        if (EscapeHtmlOnPostback)
            ScriptManager.RegisterStartupScript(this.Page, this.Page.GetType(), "UnescapeControl_" + GetClientId(), "UnescapeControl('" + GetClientId() + "');", true);

        // Ensure we have our escape script called before all post backs containing escapable controls.
        // This is like calling OnClientClick before everything.
        if (EscapeControlList != null && EscapeControlList.Count > 0)
            this.Page.ClientScript.RegisterOnSubmitStatement(this.GetType(), "SaveableTextBoxEscaper", "EscapeAllControls();");
        
    }


   public string Text
    {
        get
        {
            return Txt_SavableText.Text;
        }
        set
        {
            Txt_SavableText.Text = value;
        }
    }

    public string GetClientId()
    {
        return Txt_SavableText.ClientID;
    }
}

Now we can use it anywhere like this while setting EscapeHtmlOnPostback="True".

<%@ Register TagPrefix="STB" TagName="SavableTextBox" Src="~/SavableTextBox.ascx" %>
<STB:SavableTextBox ID="Txt_HtmlTextBox" EscapeHtmlOnPostback="True" runat="server" />

Note, when we access Txt_HtmlTextBox.Text during the post back it will already be escaped for us.

Comments

0

I liked @clamchoda's User Control solution, and played around with it. As he mentioned, his entire control is very custom, and the code reflects a more involved requirement. For something a bit simpler, you might want to consider the following.

Please note that in this version, the text is auto-decoded on PostBack, so your page code doesn't have to (use it just like a standard TextBox control).

The UserControl HTML markup:

<script>
   document.forms[0].addEventListener("submit", function (e){
      let txtBox = document.getElementById('<%= TxtBox.ClientID %>')
      txtBox.value = window.escape(txtBox.value);
   });
</script>

<asp:TextBox ID="TxtBox" runat="server" />

The Code-Behind (in VB, but easily converted to C#):

Public Property Text As String
   Get
      Return TxtBox.Text
   End Get
   Set
      TxtBox.Text = Value
   End Set
End Property

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

   If IsPostBack Then
      TxtBox.Text = Uri.UnescapeDataString(TxtBox.Text)
   End If

End Sub

The above is the bare-bones. To allow for markup in the HTML, I added properties like the following (starting with the most useful ones, and gradually adding others as a given need arose):

Public Property CssClass As String
   Get
      Return TxtBox.CssClass
   End Get
   Set
      TxtBox.CssClass= Value
   End Set
End Property

Public Property StyleMargin() As String
   'Note: use this to set all four margins.
   Get
      Return TxtBox.Style("margin")
   End Get
   Set(ByVal value As String)
      TxtBox.Style.Add("margin", value)
   End Set
End Property

Public Property Width As String
   Get
      Return TxtBox.Width
   End Get
   Set
      TxtBox.Width= Unit.Parse(value)
   End Set
End Property

Finally, against all best practices, to access the full TextBox properties in the code-behind, you can use:

Public ReadOnly Property TxtBoxControl() As TextBox
   '==>   USE RESPONSIBLY !!!   <===
   Get
      Return TxtBox
   End Get
End Property

And as was noted, to use it on a page, you need to register the User Control in the HTML markup:

<%@ Register TagPrefix="STB" TagName="PostBackSafeTextBox" Src="~/PostBackSafeTextBox.ascx" %>

<STB:PostBackSafeTextBox ID="MyTextBoxTxt" runat="server" />

I hope the foregoing is of help to others. That said, the credit must go to @clamchoda who came up with the idea in the first place. Thanks @clamchoda -- it really saved me!

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.