Как разрешить отправку тегов HTML в текстовое поле в asp.net?

Во-первых, я хочу, чтобы все знали, что я использую движок aspx, а не движок Razor.

У меня есть таблица в форме. Одно из моих текстовых полей содержит теги html, например

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

Когда я иду, чтобы построить его, он дает мне ошибку, которая говорит:

От клиента (QuestionAnswer="...ics Phone:<br/>814-888-9999<br...") было обнаружено потенциально опасное значение Request.Form.

Я попробовал запрос проверки = ложь, но это не сработало.

Мне жаль, что я не добавил свой html-код, чтобы вы могли его посмотреть. Я поднимаю вопрос, где я могу его отредактировать, если это необходимо.

 <%@ 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>

person Yusuf    schedule 26.07.2012    source источник


Ответы (6)


перед отправкой страницы вам нужно html-кодировать значение текстового поля с помощью window.escape(...)

Если вам нужен неэкранированный текст на стороне сервера, используйте метод HttpUtility.UrlDecode(...).

очень быстрый образец:

<%@ 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>

Внесите эти изменения в свой код:

<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>
person Mesh    schedule 26.07.2012

Украсьте действие вашего контроллера атрибутом [ValidateInput]:

[ValidateInput(false)]
[HttpPost]
public ActionResult Foo(MyViewModel model)
{
    ...
}
person Darin Dimitrov    schedule 26.07.2012
comment
-1: Хотя это правильный ответ, он не очень хороший. Я не думаю, что это хорошая идея — предлагать пользователям слепо отключать проверку. Вместо этого они должны определить, почему проверка не работает, а затем найти решение, которое не просто отключит важный механизм безопасности. Предложения, подобные предоставленным Тедом Спенсом и Адриан - хорошее начало. - person Kevin Babcock; 26.07.2012
comment
@KevinBabcock, важный механизм безопасности? Я смеюсь над этим. Не могли бы вы объяснить, что такого важного в этой валидации? Также вы отключаете проверку только для этого конкретного действия. В ASP.NET MVC 3 можно добиться еще более тонкой логики, украсив свойства модели представления атрибутом [AllowHtml]. Какой смысл использовать javascript, чтобы избежать пользовательского ввода перед отправкой? - person Darin Dimitrov; 26.07.2012
comment
Какой смысл использовать кодирование пользовательского ввода перед его отправкой на сервер? Ознакомьтесь с правилом #2 предотвращения XSS. Очевидно, что это только первая линия защиты, и входные данные также должны проверяться на сервере. - person Kevin Babcock; 26.07.2012
comment
@KevinBabcock, предотвращение XSS не должно выполняться при публикации на сервере, что здесь делает OP. Это следует сделать, когда вы позже будете отображать эти введенные пользователем данные в представлении. Например, реляционные базы данных мало заботятся о XSS. Они могут хранить любые необработанные данные, которые вы им подбрасываете. Все, что вам нужно сделать, если вы хотите иметь возможность отправлять данные, содержащие теги HTML, на страницу ASP.NET, все, что вам нужно сделать, это отключить паршивую функцию проверки с помощью атрибута ValidateInput или (как я сказал) в ASP.NET MVC 3 вы также можете использовать атрибут [AllowHtml] для отдельных свойств. - person Darin Dimitrov; 26.07.2012
comment
Согласен с аргументом предотвращения XSS. Хотя лично я предпочитаю очищать ввод и сохранять закодированные данные в моей БД, а не рассматривать все входные данные, сохраненные в БД, как подозрительные. В любом случае важно обеспечить последовательное использование соответствующей политики во всем приложении. - person Kevin Babcock; 26.07.2012
comment
Это старо, но @DarinDimitrov прав, я знаю, как проверить свои собственные входные данные, здесь я специально хочу, чтобы HTML был разрешен - как говорится в заголовке. - person Scott Selby; 30.11.2014
comment
@DarinDimitrov, [AllowHtml] отлично работает! К сведению других, не забудьте включить в свою модель использование System.Web.Mvc. - person GunWanderer; 14.09.2017

Клиентский JavaScript:

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

Сервер:

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

Я бы предложил использовать HTML-редактор AjaxControlToolkit. Я реализую это сейчас. Если ваше текстовое поле многострочное и достаточно большое для размещения HTML, почему бы просто не перенести его в редактор HTML. Ваш пользователь тоже будет счастливее.

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

person Laki Politis    schedule 22.03.2013

Использование html в текстовом поле не является хорошей практикой, возможно, используйте разрывы строк (Environment.NewLine) или \r\n вместо br ? Справочник по .NET

Пример (на С#):

textBox1.Multiline = true;
textBox1.Text = "test" + Environment.NewLine + "test2";
person XhkUnlimit    schedule 26.07.2012
comment
Я могу использовать это в текстовом поле //n или /r? - person Yusuf; 26.07.2012
comment
Я поставил \n в текстовое поле, это не сработало. Мне тоже ошибку не выдавало. он только что ввел\n, так что теперь это похоже на \n814-888-9999 - person Yusuf; 26.07.2012
comment
@Yusuf, если тип текстового поля многострочный, так и есть! Используйте text1.text= test + \r\n + test2; - person XhkUnlimit; 26.07.2012
comment
Извините, я поменял местами \n и \r, это \r\n, чтобы работало. Измените freqQuestionsUser.questionAnswer, и все должно быть в порядке. - person XhkUnlimit; 26.07.2012

Я выбрал немного другой подход. Я хотел широко использовать текстовые поля html в своем приложении. Я сделал пользовательский элемент управления, который позволит избежать редактирования javascript каждый раз, когда я добавляю новый элемент управления. Весь мой контроль очень индивидуален, но сердце обработки html показано ниже.

В разметке UserControl есть простой javascript для экранирования и отмены экранирования текстового поля.

<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>

Код позади отвечает за экранирование элементов управления перед обратным сообщением с помощью RegisterOnSubmitStatement и их отмену с помощью RegisterStartupScript после обратного сообщения.

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;
    }
}

Теперь мы можем использовать его где угодно при установке EscapeHtmlOnPostback="True".

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

Обратите внимание: когда мы получаем доступ к Txt_HtmlTextBox.Text во время обратной публикации, он уже будет для нас экранирован.

person clamchoda    schedule 12.01.2021