От клиента было обнаружено потенциально опасное значение Request.Form

Каждый раз, когда пользователь публикует что-то, содержащее < или же > на странице в моем веб-приложении я получаю это исключение.

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

Отслеживание исключения и отображение

Произошла ошибка. Вернитесь и введите заново всю форму, но на этот раз не используйте <

не кажется мне достаточно профессиональным.

Отключение проверки сообщений (validateRequest="false") определенно избежит этой ошибки, но сделает страницу уязвимой для ряда атак.

В идеале: когда происходит обратная запись, содержащая символы с ограничением HTML, это опубликованное значение в коллекции Form будет автоматически кодироваться в формате HTML. Итак .Text свойство моего текстового поля будет something & lt; html & gt;

Есть ли способ, которым я могу сделать это из обработчика?

48 ответов

Решение

Я думаю, что вы атакуете его с неправильной точки зрения, пытаясь закодировать все опубликованные данные.

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

Более того, "<"по сути не опасен. Он опасен только в определенном контексте: при написании строк, которые не были закодированы в вывод HTML (из-за XSS).

В других контекстах разные подстроки опасны, например, если вы пишете предоставленный пользователем URL в ссылку, подстрока "javascript:"может быть опасным. Символ одинарной кавычки, с другой стороны, опасен при интерполяции строк в запросах SQL, но совершенно безопасен, если он является частью имени, переданного из формы или прочитанного из поля базы данных.

Суть в том, что вы не можете отфильтровать случайный ввод для опасных символов, потому что любой символ может быть опасным при правильных обстоятельствах. Вы должны кодировать в точке, где некоторые конкретные символы могут стать опасными, потому что они переходят на другой язык, где они имеют особое значение. Когда вы пишете строку в HTML, вы должны кодировать символы, которые имеют особое значение в HTML, используя Server.HtmlEncode. Если вы передаете строку в динамический оператор SQL, вы должны кодировать разные символы (или, лучше, позвольте платформе сделать это за вас, используя подготовленные операторы или тому подобное)..

Если вы уверены, что HTML-кодирование везде, вы передаете строки в HTML, затем установите validateRequest="false" в <%@ Page ... %> директива в вашем .aspx файл (ы).

В.NET 4 вам может потребоваться сделать немного больше. Иногда необходимо также добавить <httpRuntime requestValidationMode="2.0" /> на web.config ( ссылка).

Существует другое решение этой ошибки, если вы используете ASP.NET MVC:

Образец C#:

[HttpPost, ValidateInput(false)]
public ActionResult Edit(FormCollection collection)
{
    // ...
}

Образец Visual Basic:

<AcceptVerbs(HttpVerbs.Post), ValidateInput(False)> _
Function Edit(ByVal collection As FormCollection) As ActionResult
    ...
End Function

В ASP.NET MVC (начиная с версии 3) вы можете добавить AllowHtml приписать свойство вашей модели.

Это позволяет запросу включать разметку HTML во время привязки модели, пропуская проверку запроса для свойства.

[AllowHtml]
public string Description { get; set; }

Если вы используете.NET 4.0, убедитесь, что вы добавили это в файл web.config внутри <system.web> теги:

<httpRuntime requestValidationMode="2.0" />

В.NET 2.0 проверка запроса применяется только к aspx Запросы. В.NET 4.0 это было расширено, чтобы включить все запросы. Вы можете вернуться только к выполнению проверки XSS при обработке .aspx указав:

requestValidationMode="2.0"

Вы можете полностью отключить проверку запроса, указав:

validateRequest="false"

В ASP.NET 4.0 можно разрешить разметку в качестве входных данных для определенных страниц, а не для всего сайта, поместив все это в <location> элемент. Это обеспечит безопасность всех остальных ваших страниц. Вам НЕ нужно ставить ValidateRequest="false" на вашей странице.aspx.

<configuration>
...
  <location path="MyFolder/.aspx">
    <system.web>
      <pages validateRequest="false" />
      <httpRuntime requestValidationMode="2.0" />
    </system.web>
  </location>
...
</configuration>

Безопаснее управлять этим внутри вашего web.config, потому что на уровне сайта вы можете видеть, какие страницы допускают разметку в качестве входных данных.

Вам все еще нужно программно проверять ввод на страницах, где проверка запроса отключена.

Предыдущие ответы были хорошими, но никто не сказал, как исключить проверку одного поля для инъекций HTML/JavaScript. Я не знаю о предыдущих версиях, но в MVC3 Beta вы можете сделать это:

[HttpPost, ValidateInput(true, Exclude = "YourFieldName")]
public virtual ActionResult Edit(int id, FormCollection collection)
{
    ...
}

Это все еще проверяет все поля, кроме исключенного. Хорошая вещь об этом состоит в том, что ваши атрибуты проверки все еще проверяют поле, но вы просто не получаете исключение "потенциально опасное значение Request.Form было обнаружено из клиента".

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

В ASP.NET MVC вам нужно установить requestValidationMode="2.0" и validateRequest="false" в web.config и применить атрибут ValidateInput к вашему действию контроллера:

<httpRuntime requestValidationMode="2.0"/>

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

а также

[Post, ValidateInput(false)]
public ActionResult Edit(string message) {
    ...
}

Вы можете кодировать текстовое поле HTML, но, к сожалению, это не остановит исключение. По моему опыту нет никакого пути, и вы должны отключить проверку страницы. Делая это, вы говорите: "Я буду осторожен, я обещаю".

Ответ на этот вопрос прост:

var varname = Request.Unvalidated["parameter_name"];

Это отключило бы проверку для конкретного запроса.

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

    void Application_Error(object sender, EventArgs e)
    {
        Exception ex = Server.GetLastError();

        if (ex is HttpRequestValidationException)
        {
            Response.Clear();
            Response.StatusCode = 200;
            Response.Write(@"[html]");
            Response.End();
        }
    }

Перенаправление на другую страницу также кажется разумным ответом на исключение.

http://www.romsteady.net/blog/2007/06/how-to-catch-httprequestvalidationexcep.html

Для MVC проигнорируйте проверку ввода, добавив

[ValidateInput(ложь)]

над каждым действием в контроллере.

Помните, что некоторые элементы управления.NET будут автоматически кодировать HTML-код. Например, установка свойства.Text в элементе управления TextBox автоматически закодирует его. Это конкретно означает преобразование < в &lt;, > в &gt; а также & в &amp;, Так что будьте осторожны с этим...

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

Однако свойство.Text для HyperLink, Literal и Label не будет кодировать HTML-объекты, поэтому оборачиваем Server.HtmlEncode(); все, что установлено в этих свойствах, является обязательным, если вы хотите предотвратить <script> window.location = "http://www.google.com"; </script> от вывода на вашу страницу и последующего исполнения.

Сделайте небольшой эксперимент, чтобы увидеть, что кодируется, а что нет.

В файле web.config в тегах вставьте элемент httpRuntime с атрибутом requestValidationMode="2.0". Также добавьте атрибут validateRequest="false" в элементе pages.

Пример:

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

Если вы не хотите отключать ValidateRequest, вам нужно реализовать функцию JavaScript, чтобы избежать исключения. Это не лучший вариант, но он работает.

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

Затем в коде позади, в событии PageLoad, добавьте атрибут к вашему элементу управления со следующим кодом:

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

Кажется, никто еще не упомянул ниже, но это решает проблему для меня. И прежде чем кто-нибудь скажет: да, это Visual Basic... хм.

<%@ Page Language="vb" AutoEventWireup="false" CodeBehind="Example.aspx.vb" Inherits="Example.Example" **ValidateRequest="false"** %>

Я не знаю, есть ли минусы, но для меня это сработало потрясающе.

Другое решение:

protected void Application_Start()
{
    ...
    RequestValidator.Current = new MyRequestValidator();
}

public class MyRequestValidator: RequestValidator
{
    protected override bool IsValidRequestString(HttpContext context, string value, RequestValidationSource requestValidationSource, string collectionKey, out int validationFailureIndex)
    {
        bool result = base.IsValidRequestString(context, value, requestValidationSource, collectionKey, out validationFailureIndex);

        if (!result)
        {
            // Write your validation here
            if (requestValidationSource == RequestValidationSource.Form ||
                requestValidationSource == RequestValidationSource.QueryString)

                return true; // Suppress error message
        }
        return result;
    }
}

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

Отключение защиты на уровне страницы и последующее кодирование каждый раз является лучшим вариантом.

Вместо использования Server.HtmlEncode вы должны взглянуть на более новую, более полную библиотеку Anti-XSS от команды Microsoft ACE.

Если вы используете framework 4.0, тогда запись в web.config ()

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

Если вы используете framework 4.5, тогда запись в web.config (requestValidationMode="2.0")

<system.web>
    <compilation debug="true" targetFramework="4.5" />
    <httpRuntime targetFramework="4.5" requestValidationMode="2.0"/>
</system.web>

Если вы хотите только одну страницу, то в вашем aspx-файле вы должны поставить первую строку так:

<%@ Page EnableEventValidation="false" %>

если у вас уже есть что-то вроде <% @ Page, просто добавьте остальные => EnableEventValidation="false" %>

Я рекомендую не делать этого.

В ASP.NET вы можете перехватить исключение и что-то с ним сделать, например, отобразить дружеское сообщение или перенаправить на другую страницу... Также существует возможность, что вы можете самостоятельно выполнить проверку...

Показать дружеское сообщение:

protected override void OnError(EventArgs e)
{
    base.OnError(e);
    var ex = Server.GetLastError().GetBaseException();
    if (ex is System.Web.HttpRequestValidationException)
    {
        Response.Clear();
        Response.Write("Invalid characters."); //  Response.Write(HttpUtility.HtmlEncode(ex.Message));
        Response.StatusCode = 200;
        Response.End();
    }
}

Я нашел решение, которое использует JavaScript для кодирования данных, которое декодируется в.NET (и не требует jQuery).

  • Сделайте текстовое поле элементом HTML (например, textarea) вместо элемента ASP.
  • Добавьте скрытое поле.
  • Добавьте следующую функцию JavaScript в свой заголовок.

    function boo () {targetText = document.getElementById ("HiddenField1"); sourceText = document.getElementById ("userbox"); targetText.value = escape (sourceText.innerText); }

В вашей текстовой области включите onchange, который вызывает boo():

<textarea id="userbox"  onchange="boo();"></textarea>

Наконец, в.NET используйте

string val = Server.UrlDecode(HiddenField1.Value);

Я знаю, что это односторонний подход - если вам нужен двусторонний подход, вам придется проявить творческий подход, но это дает решение, если вы не можете редактировать файл web.config.

Вот пример, который я (MC9000) придумал и использую через jQuery:

$(document).ready(function () {

    $("#txtHTML").change(function () {
        var currentText = $("#txtHTML").text();
        currentText = escape(currentText); // Escapes the HTML including quotations, etc
        $("#hidHTML").val(currentText); // Set the hidden field
    });

    // Intercept the postback
    $("#btnMyPostbackButton").click(function () {
        $("#txtHTML").val(""); // Clear the textarea before POSTing
                               // If you don't clear it, it will give you
                               // the error due to the HTML in the textarea.
        return true; // Post back
    });


});

И разметка:

<asp:HiddenField ID="hidHTML" runat="server" />
<textarea id="txtHTML"></textarea>
<asp:Button ID="btnMyPostbackButton" runat="server" Text="Post Form" />

Это прекрасно работает. Если хакер попытается отправить сообщение в обход JavaScript, он просто увидит ошибку. Вы также можете сохранить все эти данные, закодированные в базе данных, затем удалить их (на стороне сервера), проанализировать и проверить на наличие атак, прежде чем отображать их в другом месте.

причина

ASP.NET по умолчанию проверяет все элементы управления вводом на предмет потенциально небезопасного содержимого, которое может привести к межсайтовому скриптингу (XSS) и инъекциям SQL. Таким образом, он запрещает такой контент, выбрасывая вышеуказанное исключение. По умолчанию рекомендуется разрешить эту проверку при каждой обратной передаче.

Решение

Во многих случаях вам нужно отправить HTML-контент на вашу страницу через Rich TextBoxes или Rich Text Editors. В этом случае вы можете избежать этого исключения, установив тег ValidateRequest в @Page Директива ложная.

<%@ Page Language="C#" AutoEventWireup="true" ValidateRequest = "false" %>

Это отключит проверку запросов для страницы, для которой вы установили флаг ValidateRequest в значение false. Если вы хотите отключить это, проверьте в вашем веб-приложении; вам нужно будет установить значение false в вашем разделе web.config

<pages validateRequest ="false" />

Для платформ.NET 4.0 или более поздней версии вам также необходимо добавить следующую строку в раздел , чтобы вышеуказанная работа работала.

<httpRuntime requestValidationMode = "2.0" />

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

Ссылка: ASP.Net Ошибка: потенциально опасное значение Request.Form было обнаружено от клиента

Другие решения здесь хороши, однако, задним ходом немного неудобно применять [AllowHtml] к каждому отдельному свойству Model, особенно если у вас есть более 100 моделей на сайте приличного размера.

Если, как и я, вы хотите отключить эту (ИМХО довольно бессмысленную) функцию для всего сайта, вы можете переопределить метод Execute() в вашем базовом контроллере (если у вас еще нет базового контроллера, я предлагаю сделать его, они могут быть довольно полезно для применения общего функционала).

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

Просто убедитесь, что вы HTML кодируете все, что выкачивается в представления, полученные из пользовательского ввода (это поведение по умолчанию в ASP.NET MVC 3 с Razor в любом случае, поэтому, если по какой-то причудливой причине вы не используете Html.Raw(), вы не должен требовать эту функцию.

Отключите проверку страницы, если вам действительно нужны специальные символы, такие как, >,, <и т. д. Затем убедитесь, что при отображении пользовательского ввода данные кодируются в формате HTML.

Существует уязвимость безопасности при проверке страницы, поэтому ее можно обойти. Также на валидацию страницы не следует полагаться исключительно.

См.: http://web.archive.org/web/20080913071637/http://www.procheckup.com:80/PDFs/bypassing-dot-NET-ValidateRequest.pdf

Вы также можете использовать функцию escape(string) в JavaScript для замены специальных символов. Затем на стороне сервера использовать сервер. URLDecode (строка), чтобы переключить его обратно.

Таким образом, вам не нужно отключать проверку ввода, и другим программистам будет понятнее, что строка может иметь HTML-содержимое.

Я тоже получал эту ошибку.

В моем случае пользователь ввел акцентированный символ á в имени роли (в отношении поставщика членства ASP.NET).

Я передаю имя роли в метод, чтобы предоставить пользователям эту роль и $.ajax почтовый запрос с треском провалился...

Я сделал это, чтобы решить проблему:

Вместо

data: { roleName: '@Model.RoleName', users: users }

Сделай это

data: { roleName: '@Html.Raw(@Model.RoleName)', users: users }

@Html.Raw сделал трюк.

Я получал имя роли как значение HTML roleName="Cadastro b&#225;s", Это значение с сущностью HTML &#225; был заблокирован ASP.NET MVC. Теперь я получаю roleName Значение параметра так и должно быть: roleName="Cadastro Básico" и механизм ASP.NET MVC больше не будет блокировать запрос.

Я заканчивал тем, что использовал JavaScript перед каждой обратной передачей, чтобы проверить символы, которые вам не нужны, например:

<asp:Button runat="server" ID="saveButton" Text="Save" CssClass="saveButton" OnClientClick="return checkFields()" />

function checkFields() {
    var tbs = new Array();
    tbs = document.getElementsByTagName("input");
    var isValid = true;
    for (i=0; i<tbs.length; i++) {
        if (tbs(i).type == 'text') {
            if (tbs(i).value.indexOf('<') != -1 || tbs(i).value.indexOf('>') != -1) {
                alert('<> symbols not allowed.');
                isValid = false;
            }
        }
    }
    return isValid;
}

Конечно, моя страница - это, в основном, ввод данных, и очень мало элементов, которые выполняют обратную передачу, но, по крайней мере, их данные сохраняются.

Вы можете использовать что-то вроде:

var nvc = Request.Unvalidated().Form;

Потом, nvc["yourKey"] должно сработать.

Для тех, кто не использует привязку модели, кто извлекает каждый параметр из Request.Form, кто уверен, что входной текст не причинит никакого вреда, есть другой способ. Не отличное решение, но оно сделает работу.

Со стороны клиента закодируйте его как uri, а затем отправьте.
например:

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

Со стороны сервера, примите его и расшифруйте как uri.
например:

var temp = HttpUtility.UrlDecode(HttpContext.Current.Request.Form["MsgBody"]);

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

 public class AppModelBinder : DefaultModelBinder
    {
        protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType)
        {
            try
            {
                return base.CreateModel(controllerContext, bindingContext, modelType);
            }
            catch (HttpRequestValidationException e)
            {
                HandleHttpRequestValidationException(bindingContext, e);
                return null; // Encode here
            }
        }
        protected override object GetPropertyValue(ControllerContext controllerContext, ModelBindingContext bindingContext,
            PropertyDescriptor propertyDescriptor, IModelBinder propertyBinder)
        {
            try
            {
                return base.GetPropertyValue(controllerContext, bindingContext, propertyDescriptor, propertyBinder);
            }
            catch (HttpRequestValidationException e)
            {
                HandleHttpRequestValidationException(bindingContext, e);
                return null; // Encode here
            }
        }

        protected void HandleHttpRequestValidationException(ModelBindingContext bindingContext, HttpRequestValidationException ex)
        {
            var valueProviderCollection = bindingContext.ValueProvider as ValueProviderCollection;
            if (valueProviderCollection != null)
            {
                ValueProviderResult valueProviderResult = valueProviderCollection.GetValue(bindingContext.ModelName, skipValidation: true);
                bindingContext.ModelState.SetModelValue(bindingContext.ModelName, valueProviderResult);
            }

            string errorMessage = string.Format(CultureInfo.CurrentCulture, "{0} contains invalid symbols: <, &",
                     bindingContext.ModelMetadata.DisplayName);

            bindingContext.ModelState.AddModelError(bindingContext.ModelName, errorMessage);
        }
    }

В Application_Start:

ModelBinders.Binders.DefaultBinder = new AppModelBinder();

Обратите внимание, что это работает только для полей формы. Опасное значение не передается в модель контроллера, но сохраняется в ModelState и может быть повторно отображено в форме с сообщением об ошибке.

Опасные символы в URL могут быть обработаны следующим образом:

private void Application_Error(object sender, EventArgs e)
{
    Exception exception = Server.GetLastError();
    HttpContext httpContext = HttpContext.Current;

    HttpException httpException = exception as HttpException;
    if (httpException != null)
    {
        RouteData routeData = new RouteData();
        routeData.Values.Add("controller", "Error");
        var httpCode = httpException.GetHttpCode();
        switch (httpCode)
        {
            case (int)HttpStatusCode.BadRequest /* 400 */:
                if (httpException.Message.Contains("Request.Path"))
                {
                    httpContext.Response.Clear();
                    RequestContext requestContext = new RequestContext(new HttpContextWrapper(Context), routeData);
                    requestContext.RouteData.Values["action"] ="InvalidUrl";
                    requestContext.RouteData.Values["controller"] ="Error";
                    IControllerFactory factory = ControllerBuilder.Current.GetControllerFactory();
                    IController controller = factory.CreateController(requestContext, "Error");
                    controller.Execute(requestContext);
                    httpContext.Server.ClearError();
                    Response.StatusCode = (int)HttpStatusCode.BadRequest /* 400 */;
                }
                break;
        }
    }
}

ErrorController:

public class ErrorController : Controller
 {
   public ActionResult InvalidUrl()
   {
      return View();
   }
}   

Пока это только символы "<" и ">" (а не сами символы в двойных кавычках) и вы используете их в контексте, таком как , вы в безопасности (тогда как для