Каждый раз, когда пользователь публикует что-либо, содержащее <
или содержащее >
страницу в моем веб-приложении, я получаю это исключение.
Я не хочу вдаваться в дискуссию о целесообразности создания исключения или сбоя всего веб-приложения, потому что кто-то ввел символ в текстовое поле, но я ищу элегантный способ справиться с этим.
Отслеживание исключения и отображение
Произошла ошибка. Вернитесь и введите заново всю форму, но на этот раз не используйте <
не кажется мне достаточно профессиональным.
Отключение post validation ( 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 ( ссылка ).
<httpRuntime requestValidationMode="2.0" />
тег местоположения, чтобы избежать потери полезной защиты, обеспечиваемой проверкой с остальной части вашего сайта. [AllowHtml]
на свойстве модели. GlobalFilters.Filters.Add(new ValidateInputAttribute(false));
в Application_Start()
. <pages validateRequest="false" />
in <system.web />
. При этом свойство будет применено ко всем страницам. Вы можете кодировать содержимое текстового поля в формате HTML , но, к сожалению, это не остановит исключение. По моему опыту нет никакого пути, и вы должны отключить проверку страницы. Делая это, вы говорите: «Я буду осторожен, я обещаю».
Вы должны использовать метод Server.HtmlEncode, чтобы защитить ваш сайт от опасного ввода.
Я думаю, вы могли бы сделать это в модуле; но это оставляет открытыми некоторые вопросы; Что делать, если вы хотите сохранить входные данные в базе данных? Внезапно, поскольку вы сохраняете закодированные данные в базе данных, вы в конечном итоге доверяете входным данным, что, вероятно, является плохой идеей. В идеале вы храните необработанные незакодированные данные в базе данных и каждый раз кодируете.
Отключение защиты на уровне страниц и последующее кодирование каждый раз является лучшим вариантом.
Вместо использования Server.HtmlEncode вы должны взглянуть на более новую, более полную библиотеку Anti-XSS от команды Microsoft ACE.
Пока это только символы "<" и ">" (а не сами двойные кавычки), и вы используете их в контексте, например, <input value = " this " />, вы в безопасности (тогда как для <textarea > этот </ textarea> вы бы уязвимы конечно). Это может упростить вашу ситуацию, но для чего-то большего используйте одно из других опубликованных решений.
Отключение проверки страницы , если вам действительно нужны специальные символы , такие как, >
,, <
и т.д. Затем убедитесь , что при отображении пользовательского ввода, данные HTML-кодирования.
Существует уязвимость безопасности при проверке страницы, поэтому ее можно обойти. Также на валидацию страницы нельзя полагаться исключительно.
Если вы просто хотите сказать своим пользователям, что <и> не должны использоваться, НО, вы не хотите, чтобы вся форма обрабатывалась / отправлялась обратно (и теряла весь ввод) заранее, если бы вы не просто вставили валидатор вокруг поля для проверки этих (и, возможно, других потенциально опасных) символов?
Помните, что некоторые элементы управления .NET будут автоматически кодировать HTML-код. Например, установка свойства .Text в элементе управления TextBox автоматически закодирует его. Это, в частности, означает превращение <
в <
, >
в >
и &
в &
. Так что будьте осторожны с этим ...
myTextBox.Text = Server.HtmlEncode(myStringFromDatabase); // Pseudo code
Однако свойство .Text для HyperLink, Literal и Label не будет кодировать HTML-объекты, поэтому оборачиваем Server.HtmlEncode (); все, что установлено в этих свойствах, является обязательным, если вы хотите предотвратить <script> window.location = "http://www.google.com"; </script>
вывод на свою страницу и последующее выполнение.
Сделайте небольшой эксперимент, чтобы увидеть, что кодируется, а что нет.
Если вы не хотите отключать 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);")
Существует другое решение этой ошибки, если вы используете ASP.NET MVC:
- ASP.NET MVC - страницы validateRequest = false не работает?
- Почему ValidateInput (False) не работает?
- ASP.NET MVC RC1, VALIDATEINPUT, ПОТЕНЦИАЛЬНО ОПАСНЫЙ ЗАПРОС И ЯМА
Образец 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
[AllowHtml]
это лучше, чем ValidateInput(false)
, потому что [AllowHtml]
определяется сразу для свойства, то есть поля редактора, и всякий раз, когда оно используется, нет необходимости использовать его для нескольких действий. Что ты предлагаешь? Вы можете поймать эту ошибку в 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
Если вы используете .NET 4.0, убедитесь, что вы добавили это в файл web.config внутри <system.web>
тегов:
<httpRuntime requestValidationMode="2.0" />
В .NET 2.0 проверка aspx
запросов применяется только к запросам. В .NET 4.0 это было расширено, чтобы включить все запросы. Вы можете вернуться к выполнению только проверки XSS при обработке .aspx
, указав:
requestValidationMode="2.0"
Вы можете отключить запрос Validate полностью , указав:
validateRequest="false"
<system.web>
тегов. Предыдущие ответы были хорошими, но никто не сказал, как исключить проверку одного поля для инъекций HTML / JavaScript. Я не знаю о предыдущих версиях, но в MVC3 Beta вы можете сделать это:
[HttpPost, ValidateInput(true, Exclude = "YourFieldName")]
public virtual ActionResult Edit(int id, FormCollection collection)
{
...
}
Это все еще проверяет все поля, кроме исключенного. Хорошая вещь об этом состоит в том, что ваши атрибуты проверки все еще проверяют поле, но вы просто не получаете исключение «потенциально опасное значение Request.Form было обнаружено из клиента».
Я использовал это для проверки правильности выражения. Я сделал свой собственный атрибут ValidationAttribute, чтобы проверить, является ли регулярное выражение допустимым или нет. Поскольку регулярные выражения могут содержать нечто, похожее на скрипт, я применил приведенный выше код - регулярное выражение все еще проверяется, действительно ли оно допустимо или нет, но не в том случае, если оно содержит скрипты или HTML.
[AllowHtml]
свойства модели вместо [ValidateInput]
действия для достижения того же конечного результата. [AllowHtml]
не вариант. Я рекомендую проверить эту статью: weblogs.asp.net/imranbaloch/… , но она тоже несколько устарела и может устареть. В 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"
В ASP.NET MVC (начиная с версии 3) вы можете добавить AllowHtml
атрибут к свойству вашей модели.
Это позволяет запросу включать разметку HTML во время привязки модели, пропуская проверку запроса для свойства.
[AllowHtml]
public string Description { get; set; }
ValidateInput(false)
и AllowHtml
? В чем преимущество одного над другим? Когда бы я хотел использовать AllowHtml
вместо ValidateInput(false)
? Когда бы я хотел использовать ValidateInput(false)
более AllowHtml
? Когда бы я хотел использовать оба? Имеет ли смысл использовать оба? Кажется, никто еще не упомянул ниже, но это решает проблему для меня. И прежде чем кто-нибудь скажет: да, это Visual Basic ... хм.
<%@ Page Language="vb" AutoEventWireup="false" CodeBehind="Example.aspx.vb" Inherits="Example.Example" **ValidateRequest="false"** %>
Я не знаю, есть ли минусы, но для меня это сработало потрясающе.
Вы также можете использовать функцию escape (string) в JavaScript для замены специальных символов. Затем на стороне сервера использовать сервер. URLDecode (строка), чтобы переключить его обратно.
Таким образом, вам не нужно отключать проверку ввода, и другим программистам будет понятнее, что строка может иметь HTML-содержимое.
В файле web.config в тегах вставьте элемент httpRuntime с атрибутом requestValidationMode = "2.0". Также добавьте атрибут validateRequest = "false" в элементе pages.
Пример:
<configuration>
<system.web>
<httpRuntime requestValidationMode="2.0" />
</system.web>
<pages validateRequest="false">
</pages>
</configuration>
Другие решения здесь хороши, однако, задним ходом немного неудобно применять [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 (), вы не должен требовать эту функцию.
В 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 перед каждой обратной передачей, чтобы проверить символы, которые вам не нужны, такие как:
<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;
}
Конечно, моя страница - это, в основном, ввод данных, и очень мало элементов, которые выполняют обратную передачу, но, по крайней мере, их данные сохраняются.
Я тоже получал эту ошибку.
В моем случае пользователь ввел акцентированный символ á
в имени роли (в отношении поставщика членства 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 больше не будет блокировать запрос.
В 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, потому что на уровне сайта вы можете видеть, какие страницы допускают разметку в качестве входных данных.
Вам все еще нужно программно проверять ввод на страницах, где проверка запроса отключена.
Ни одно из предложений не сработало для меня. Я не хотел отключать эту функцию для всего сайта, так как в 99% случаев я не хочу, чтобы мои пользователи размещали HTML на веб-формах. Я только что создал свой метод обхода, так как я единственный, кто использует это конкретное приложение. Я преобразовываю ввод в HTML в коде позади и вставляю его в свою базу данных.
Ответ на этот вопрос прост:
var varname = Request.Unvalidated["parameter_name"];
Это отключило бы проверку для конкретного запроса.
Request
? Вы можете использовать что-то вроде:
var nvc = Request.Unvalidated().Form;
Позже nvc["yourKey"]
должен работать.
Другое решение:
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;
}
}
Для MVC игнорируйте проверку ввода, добавив
[ValidateInput (ложь)]
над каждым действием в контроллере.
Как указано в моем комментарии к ответу Сел , это наше расширение для валидатора пользовательских запросов.
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);
}
}
Я нашел решение, которое использует 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, он просто увидит ошибку. Вы также можете сохранить все эти данные, закодированные в базе данных, затем удалить их (на стороне сервера), проанализировать и проверить на наличие атак, прежде чем отображать их в другом месте.
escape(...)
может занять много времени. В моем случае разметка представляла собой целый (2 МБ) XML-файл. Вы можете спросить: «Почему бы тебе просто не использовать <input type="file"...
и ... я согласен с тобой :)
<httpRuntime requestValidationMode="2.0" />
в web.config