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

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

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

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

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

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

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

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

Есть ли способ сделать это из обработчика?

+1356
17 сент. '08 в 10:58
источник поделиться
43 ответа
  • 1
  • 2

Вы можете автоматически закодировать поле HTML в пользовательском приложении Binding. Мое решение несколько отличается, я помещаю ошибку в 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();
   }
}   
+3
25 февр. '16 в 8:17
источник

Вам следует использовать метод Server.HtmlEncode для защиты вашего сайта от опасного ввода.

Дополнительная информация здесь

+3
17 сент. '08 в 11:21
источник

Как указано в моем комментарии к Sel answer, это наше расширение для персонализатора запроса.

public class SkippableRequestValidator : RequestValidator
{
    protected override bool IsValidRequestString(HttpContext context, string value, RequestValidationSource requestValidationSource, string collectionKey, out int validationFailureIndex)
    {
        if (collectionKey != null && collectionKey.EndsWith("_NoValidation"))
        {
            validationFailureIndex = 0;
            return true;
        }

        return base.IsValidRequestString(context, value, requestValidationSource, collectionKey, out validationFailureIndex);
    }
}
+2
01 мая '14 в 20:04
источник

Для тех из нас, кто все еще застрял в веб-формах, я нашел следующее решение, которое позволяет отключить проверку только в одном поле! (Я бы не хотел отключать его для всей страницы.)

VB.NET:

Public Class UnvalidatedTextBox
    Inherits TextBox
    Protected Overrides Function LoadPostData(postDataKey As String, postCollection As NameValueCollection) As Boolean
        Return MyBase.LoadPostData(postDataKey, System.Web.HttpContext.Current.Request.Unvalidated.Form)
    End Function
End Class

С#:

public class UnvalidatedTextBox : TextBox
{
    protected override bool LoadPostData(string postDataKey, NameValueCollection postCollection)
    {
        return base.LoadPostData(postDataKey, System.Web.HttpContext.Current.Request.Unvalidated.Form);
    }
}

Теперь просто используйте <prefix:UnvalidatedTextBox id="test" runat="server" /> вместо <asp:TextBox, и он должен разрешить все символы (это идеально подходит для полей пароля!)

+1
16 янв. '17 в 14:48
источник

И последнее, но не менее важное: обратите внимание, что элементы управления привязкой ASP.NET Data Data Binding автоматически кодируют значения во время привязки данных. Это изменяет поведение по умолчанию для всех элементов управления ASP.NET(TextBox, Label и т.д.), ItemTemplate в ItemTemplate. Следующий пример демонстрирует (значение ValidateRequest равно 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> 

код за

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. Значение представления аргумента: &#39;

Значение Label1.Text: &#39;

Значение TextBox2.Text: &amp;#39;

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

Значение Label1.Text: <script>alert('attack!');</script>

Значение TextBox2.Text: &lt;script&gt;alert(&#39;attack!&#39;);&lt;/script&gt;

+1
27 янв. '18 в 20:10
источник

В.Net 4.0 и далее, что является обычным случаем, установите следующий параметр в system.web

<system.web>
     <httpRuntime requestValidationMode="2.0" />

+1
15 мар. '18 в 19:16
источник

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

Предположим, что ваш веб-клиент отправляет запросы POST или PUT с помощью ajax и отправляет в ваш веб-сервис либо текстовые файлы json, либо xml, либо необработанные данные (содержимое файла). Поскольку вашему веб-сервису не требуется получать какую-либо информацию из заголовка Content-Type, ваш код JavaScript не задавал этот заголовок для вашего запроса ajax. Но если вы не установите этот заголовок в запросе ajax POST/PUT, Safari может добавить этот заголовок: "Content-Type: application/x-www-form-urlencoded". Я заметил, что на Safari 6 на iPhone, но другие версии Safari/OS или Chrome могут сделать то же самое. Поэтому, получая этот заголовок Content-Type, некоторые части.NET Framework предполагают, что структура данных тела запроса соответствует публикации в виде html-формы, а это не так, и возникает исключение HttpRequestValidationException. Первое, что нужно сделать, - это, очевидно, всегда устанавливать заголовок Content-Type на все, кроме формы MIME, на запрос ajax POST/PUT, даже если это бесполезно для вашего веб-сервиса.

Я также обнаружил эту деталь:
В этих обстоятельствах исключение HttpRequestValidationException увеличивается, когда ваш код пытается получить доступ к коллекции HttpRequest.Params. Но удивительно, что это исключение не увеличивается, когда он обращается к коллекции HttpRequest.ServerVariables. Это показывает, что, хотя эти две коллекции кажутся почти идентичными, один получает данные запроса через проверки безопасности, а другой - нет.

+1
04 мая '18 в 11:43
источник

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

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

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

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

var temp = HttpUtility.UrlDecode(HttpContext.Current.Request.Form["MsgBody"]);
+1
24 июл. '18 в 5:17
источник

в моем случае, используя asp: Textbox control (Asp.net 4.5), вместо установки всей страницы для validateRequest="false" я использовал

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

в текстовом поле, которое вызвало исключение.

0
03 дек. '18 в 8:54
источник

Используйте Server.HtmlEncode("yourtext");

0
19 апр. '16 в 14:27
источник

Я вижу, что об этом много написано... и я не видел этого. Это было доступно с.NET Framework 4.5

Параметр ValidateRequestMode для элемента управления - отличный вариант. Таким образом, другие элементы управления на странице все еще защищены. Изменений в web.config не требуется.

 protected void Page_Load(object sender, EventArgs e)
    {
             txtMachKey.ValidateRequestMode = ValidateRequestMode.Disabled;
    }
0
30 мар. '18 в 14:06
источник

Решение

Мне не нравится отключать проверку сообщений (validateRequest = "false"). С другой стороны, неприемлемо, что приложение вылетает из-за того, что невинный пользователь набирает <x или что-то еще.

Поэтому я написал функцию javascript на стороне клиента (xssCheckValidates), которая делает предварительную проверку. Эта функция вызывается при попытке опубликовать данные формы, например:

<form id="form1" runat="server" onsubmit="return xssCheckValidates();">

Функция довольно проста и может быть улучшена, но она выполняет свою работу.

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

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

Вы можете попробовать это здесь:

    function xssCheckValidates() {
      var valid = true;
      var inp = document.querySelectorAll(
          "input:not(:disabled):not([readonly]):not([type=hidden])" +
          ",textarea:not(:disabled):not([readonly])");
      for (var i = 0; i < inp.length; i++) {
        if (!inp[i].readOnly) {
          if (inp[i].value.indexOf('<') > -1) {
            valid = false;
            break;
          }
          if (inp[i].value.indexOf('&#') > -1) {
            valid = false;
            break;
          }
        }
      }
      if (valid) {
        return true;
      } else {
        alert('In one or more of the text fields, you have typed\r\nthe character "<" or the character sequence "&#".\r\n\r\nThis is unfortunately not allowed since\r\nit can be used in hacking attempts.\r\n\r\nPlease edit the field and try again.');
        return false;
      }
    }
<form onsubmit="return xssCheckValidates();" >
  Try to type < or &# <br/>
  <input type="text" /><br/>
  <textarea></textarea>
  <input type="submit" value="Send" />
</form>
0
03 апр. '18 в 21:44
источник

Попробуйте

Server.Encode

и

Server.HtmlDecode  при отправке и получении.

-1
31 мар. '15 в 10:50
источник
  • 1
  • 2

Посмотрите другие вопросы по меткам или Задайте вопрос