Каждый раз, когда пользователь отправляет что-то, содержащее <
или >
на странице моего веб-приложения, я получаю это исключение.
Я не хочу вдаваться в дискуссию о умности бросать исключение или разбивать все веб-приложение, потому что кто-то вводил символ в текстовое поле, но я ищу элегантный способ справиться с этим.
Отслеживание исключения и отображение
Произошла ошибка, вернитесь назад и снова введите всю форму, но на этот раз не используйте <
не кажется мне достаточно профессиональным.
Отключение проверки после публикации (validateRequest="false"
), безусловно, позволит избежать этой ошибки, но это сделает страницу уязвимой для ряда атак.
В идеале: когда сообщение с обратной связью содержит символы с ограниченным HTML, это опубликованное значение в коллекции Form будет автоматически закодировано HTML.
Таким образом, свойство .Text
моего текстового поля будет something & lt; html & gt;
Есть ли способ сделать это из обработчика?
Я думаю, что вы атакуете его с неправильного угла, пытаясь закодировать все опубликованные данные.
Обратите внимание, что "<
" также может поступать из других внешних источников, таких как поле базы данных, конфигурация, файл, фид и т.д.
Кроме того, "<
" не является по своей сути опасным. Это опасно только в определенном контексте: при написании строк, которые не были закодированы для вывода 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:
Пример С#:
[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"
<system.web>
.
Для 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, чтобы убедиться, что регулярное выражение действительно или нет. Поскольку регулярные выражения могут содержать что-то, что выглядит как script, я применил вышеуказанный код - регулярное выражение все еще проверяется, если оно действительно или нет, но не содержит скриптов или 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) {
...
}
validateRequest="false"
не было необходимости, только requestValidationMode="2.0"
Вы можете поймать эту ошибку в 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
Вы можете кодировать текст в текстовом поле HTML, но, к сожалению, это не остановит исключение. По моему опыту нет пути, и вы должны отключить проверку страницы. Делая это, вы говорите: "Я буду осторожен, я обещаю".
Для MVC игнорируйте проверку ввода, добавив
[ValidateInput (ложь)]
над каждым действием в контроллере.
Пожалуйста, имейте в виду, что некоторые элементы управления .NET автоматически кодируют HTML-код. Например, установка свойства .Text в элементе управления TextBox будет автоматически кодировать его. Это специально означает преобразование <
в <
, >
в >
и &
в &
. Поэтому будьте осторожны с этим...
myTextBox.Text = Server.HtmlEncode(myStringFromDatabase); // Pseudo code
Однако свойство .Text для HyperLink, Literal и Label не будет кодировать HTML файлы, поэтому wraping Server.HtmlEncode(); вокруг чего-либо, установленного в этих свойствах, является обязательным, если вы хотите, чтобы <script> window.location = "http://www.google.com"; </script>
не выводился на вашу страницу и впоследствии выполнялся.
Сделайте немного экспериментов, чтобы увидеть, что закодировано, а что нет.
Ответ на этот вопрос прост:
var varname = Request.Unvalidated["parameter_name"];
Это приведет к отключению проверки для конкретного запроса.
В файле web.config в тегах вставьте элемент httpRuntime с атрибутом requestValidationMode = "2.0". Также добавьте в элемент pages атрибут validateRequest = "false".
Пример:
<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... yuck.
<%@ 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;
}
}
В 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();
}
}
Если вы используете фреймворк 4.0, то запись в файле web.config(< pages validateRequest = "false" /" > )
<configuration>
<system.web>
<pages validateRequest="false" />
</system.web>
</configuration>
Если вы используете фреймворк 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, так что просто добавьте rest = > EnableEventValidation="false"
% >
Я рекомендую не делать этого.
Я думаю, вы могли бы сделать это в модуле; но это оставляет некоторые вопросы; что, если вы хотите сохранить вход в базу данных? Внезапно, потому что вы сохраняете закодированные данные в базе данных, вы в конечном итоге доверяете им, что, вероятно, является плохой идеей. В идеале вы сохраняете необработанные незарегистрированные данные в базе данных и в кодировке каждый раз.
Отключение защиты на уровне страницы и последующее кодирование - лучший вариант.
Вместо использования Server.HtmlEncode вы должны посмотреть более новую, более полную анти-XSS-библиотеку из команды Microsoft ACE.
Другие решения здесь приятны, однако немного королевской боли в тылу приходится применять [AllowHtml] к каждому свойству модели, особенно если у вас более 100 моделей на сайте с приличным размером.
Если мне нравится, вы хотите отключить эту функцию (IMHO довольно бессмысленную) с сайта, вы можете переопределить метод 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(), вы не должны использовать эту функцию.
Причина
ASP.NET по умолчанию проверяет все элементы управления входами для потенциально опасного содержимого, которое может привести к межсайтовому скриптингу (XSS) и SQL-инъекции. Таким образом, он запрещает такое содержимое, бросая вышеуказанное исключение. По умолчанию рекомендуется разрешить эту проверку при каждой обратной передаче.
Решение
Во многих случаях вам нужно отправить HTML-контент на свою страницу через Rich TextBoxes или Rich Text Editors. В этом случае вы можете избежать этого исключения, установив тег ValidateRequest в директиве @Page
равным false.
<%@ Page Language="C#" AutoEventWireup="true" ValidateRequest = "false" %>
Это отключит проверку запросов на страницу, на которую установлен флаг ValidateRequest, на значение false. Если вы хотите отключить это, проверьте всю свою веб-приложение; вам нужно установить его в false в разделе web.config < system.web >
<pages validateRequest ="false" />
Для платформ .NET 4.0 или выше вам также необходимо добавить следующую строку в разделе < system.web > , чтобы сделать вышеприведенную работу.
<httpRuntime requestValidationMode = "2.0" />
Вот оно. Надеюсь, это поможет вам избавиться от вышеуказанной проблемы.
Ссылка на: Ошибка ASP.Net: потенциально опасное значение Request.Form было обнаружено у клиента
Я нашел решение, которое использует JavaScript для кодирования данных, которое декодируется в .NET(и не требует jQuery).
Добавьте в свой заголовок следующую функцию 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).
Я передаю имя роли методу предоставления пользователям этой роли, а запрос на отправку $.ajax
терпел неудачу...
Я сделал это, чтобы решить проблему:
Вместо
data: { roleName: '@Model.RoleName', users: users }
Сделайте это
data: { roleName: '@Html.Raw(@Model.RoleName)', users: users }
@Html.Raw
сделал трюк.
Я получил имя роли как значение HTML roleName="Cadastro bás"
. Это значение с объектом HTML á
блокировалось ASP.NET MVC. Теперь я получаю значение параметра roleName
так, как должно быть: roleName="Cadastro Básico"
и механизм ASP.NET MVC больше не будет блокировать запрос.
Отключите проверку страницы, если вам действительно нужны специальные символы, например, >
<
и т.д. Затем убедитесь, что когда пользовательский ввод отображается, данные кодируются в HTML.
Существует уязвимость безопасности при проверке страницы, поэтому ее можно обойти. Также не следует полагаться только на проверку страницы.
Вы также можете использовать функцию JavaScript escape (string) для замены специальных символов. Затем серверная серверная серверная служба URLDecode (строка), чтобы вернуть его обратно.
Таким образом, вам не нужно отключать проверку ввода, и другим программистам будет понятно, что строка может содержать содержимое HTML.
Я закончил с использованием 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"]
должен работать.
Ни один из предложений не работал у меня. Я вообще не хотел отключать эту функцию для всего веб-сайта, потому что 99% времени я не хочу, чтобы мои пользователи размещали HTML на веб-формах. Я просто создал свою собственную работу вокруг метода, так как я единственный, кто использует это конкретное приложение. Я конвертирую вход в HTML в код позади и вставляю его в свою базу данных.
Если вы просто хотите сказать своим пользователям, что < и > не должны использоваться НО, вы не хотите, чтобы вся форма обрабатывалась/отправлялась назад (и теряла все входные данные), прежде чем вы могли бы просто не помещать валидатор вокруг поля для экранирования для этих (и, возможно, других потенциально опасных)?
Пока это только "<" и " > " (а не только двойные кавычки), и вы используете их в контексте типа < input value = "this"/ > , вы в безопасности (в то время как для <textarea> this </textarea> , вы были бы уязвимы, конечно). Это может упростить вашу ситуацию, но для ничего больше использовать одно из других опубликованных решений.
Вы можете автоматически закодировать поле 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();
}
}
Вам следует использовать метод Server.HtmlEncode для защиты вашего сайта от опасного ввода.
Как указано в моем комментарии к 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);
}
}
Для тех, кто не использует привязку к модели, кто извлекает каждый параметр из Request.Form, которые уверены, что входной текст не причинит никакого вреда, есть другой способ. Не отличное решение, но оно выполнит эту работу.
С клиентской стороны, закодируйте его как uri, затем отправьте его.
например:
encodeURI($("#MsgBody").val());
Со стороны сервера, примите его и расшифруйте его как uri.
например:
var temp = HttpUtility.UrlDecode(HttpContext.Current.Request.Form["MsgBody"]);
Я знаю, что этот вопрос касается публикации формы, но я хотел бы добавить некоторые подробности для людей, которые получили эту ошибку при других обстоятельствах. Это также может происходить на обработчике, используемом для реализации веб-службы.
Предположим, что ваш веб-клиент отправляет запросы 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. Это показывает, что, хотя эти две коллекции кажутся почти идентичными, один получает данные запроса через проверки безопасности, а другой - нет.
В.Net 4.0 и далее, что является обычным случаем, установите следующий параметр в system.web
<system.web>
<httpRuntime requestValidationMode="2.0" />
И последнее, но не менее важное: обратите внимание, что элементы управления привязкой 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; }
}
'
Значение Label1.Text
: '
Значение TextBox2.Text
: &#39;
<script>alert('attack!');</script>
Значение Label1.Text
: <script>alert('attack!');</script>
Значение TextBox2.Text
: <script>alert('attack!');</script>
Для тех из нас, кто все еще застрял в веб-формах, я нашел следующее решение, которое позволяет отключить проверку только в одном поле! (Я бы не хотел отключать его для всей страницы.)
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
, и он должен разрешить все символы (это идеально подходит для полей пароля!)
в моем случае, используя asp: Textbox control (Asp.net 4.5), вместо установки всей страницы для validateRequest="false"
я использовал
<asp:TextBox runat="server" ID="mainTextBox"
ValidateRequestMode="Disabled"
></asp:TextBox>
в текстовом поле, которое вызвало исключение.
Решение
Мне не нравится отключать проверку сообщений (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>
Я вижу, что об этом много написано... и я не видел этого. Это было доступно с.NET Framework 4.5
Параметр ValidateRequestMode для элемента управления - отличный вариант. Таким образом, другие элементы управления на странице все еще защищены. Изменений в web.config не требуется.
protected void Page_Load(object sender, EventArgs e)
{
txtMachKey.ValidateRequestMode = ValidateRequestMode.Disabled;
}
Используйте Server.HtmlEncode("yourtext");
Попробуйте
Server.Encode
и
Server.HtmlDecode
при отправке и получении.