每次用户在我的 Web 应用程序的页面中发布包含 <
或 >
的内容时,都会引发此异常。
我不想讨论由于有人在文本框中输入了一个字符而引发异常或使整个 Web 应用程序崩溃的聪明之处,但我正在寻找一种优雅的方式来处理这个问题。
捕获异常并显示
发生错误,请返回并重新输入整个表单,但这次请不要使用 <
对我来说似乎不够专业。
禁用后验证 (validateRequest="false"
) 肯定会避免此错误,但它会使页面容易受到许多攻击。
理想情况下:当回发包含 HTML 受限字符时,表单集合中的发布值将自动进行 HTML 编码。所以我的文本框的 .Text
属性将是 something & lt; html & gt;
有没有办法从处理程序中做到这一点?
<httpRuntime requestValidationMode="2.0" />
放入 web.config
我认为您通过尝试对所有发布的数据进行编码来从错误的角度对其进行攻击。
请注意,“<
”也可能来自其他外部来源,例如数据库字段、配置、文件、提要等。
此外,“<
”本身并不危险。它仅在特定上下文中是危险的:当编写尚未编码为 HTML 输出的字符串时(因为 XSS)。
在其他情况下,不同的子字符串是危险的,例如,如果您将用户提供的 URL 写入链接,则子字符串“javascript:
”可能是危险的。另一方面,单引号字符在 SQL 查询中插入字符串时很危险,但如果它是从表单提交或从数据库字段读取的名称的一部分,则非常安全。
底线是:您不能过滤随机输入的危险字符,因为任何字符在适当的情况下都可能是危险的。您应该在某些特定字符可能变得危险的地方进行编码,因为它们会进入具有特殊含义的不同子语言。将字符串写入 HTML 时,应使用 Server.HtmlEncode 对 HTML 中具有特殊含义的字符进行编码。如果您将字符串传递给动态 SQL 语句,您应该对不同的字符进行编码(或者更好的是,让框架通过使用准备好的语句等来为您完成)..
当您确定在将字符串传递给 HTML 的任何地方都进行了 HTML 编码,然后在 .aspx
文件的 <%@ Page ... %>
指令中设置 ValidateRequest="false"
。
在 .NET 4 中,您可能需要做更多的事情。有时还需要将 <httpRuntime requestValidationMode="2.0" />
添加到 web.config (reference)。
如果您使用的是 ASP.NET MVC,则此错误有不同的解决方案:
ASP.NET MVC – 页面 validateRequest=false 不起作用?
为什么 ValidateInput(False) 不起作用?
ASP.NET MVC RC1,验证输入,一个潜在的危险请求和陷阱
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]
是为属性(即编辑器字段)一次性定义的,并且无论何时使用它都不需要将它用于多个操作。你有什么建议?
在 ASP.NET MVC(从版本 3 开始)中,您可以将 AllowHtml
特性添加到模型的属性中。
它允许请求在模型绑定期间通过跳过对属性的请求验证来包含 HTML 标记。
[AllowHtml]
public string Description { get; set; }
ValidateInput(false)
和 AllowHtml
有什么区别?一个比另一个有什么优势?我什么时候想使用 AllowHtml
而不是 ValidateInput(false)
?我什么时候想使用 ValidateInput(false)
而不是 AllowHtml
?我什么时候想同时使用两者?两者都用有意义吗?
如果您使用的是 .NET 4.0,请确保将其添加到 <system.web>
标记内的 web.config 文件中:
<httpRuntime requestValidationMode="2.0" />
在 .NET 2.0 中,请求验证仅适用于 aspx
请求。在 .NET 4.0 中,这被扩展为包括 所有 请求。您可以在处理 .aspx
时恢复为仅执行 XSS 验证,方法是指定:
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 来查看正则表达式是否有效。由于正则表达式可以包含看起来像脚本的东西,我应用了上面的代码 - 正则表达式仍在检查它是否有效,但如果它包含脚本或 HTML,则不会。
[AllowHtml]
而不是在 Action 上使用 [ValidateInput]
以获得相同的最终结果。
[AllowHtml]
不是一个选项。我建议查看这篇文章:weblogs.asp.net/imranbaloch/…,但它也有些陈旧,可能已经过时了。
在 ASP.NET MVC 中,您需要在 web.config 中设置 requestValidationMode="2.0" 和 validateRequest="false",并将 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"
这个问题的答案很简单:
var varname = Request.Unvalidated["parameter_name"];
这将禁用对特定请求的验证。
Request
读取数据?
您可以在 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,通过添加忽略输入验证
[验证输入(假)]
在Controller中的每个Action之上。
请记住,一些 .NET 控件会自动对输出进行 HTML 编码。例如,在 TextBox 控件上设置 .Text 属性将自动对其进行编码。这具体意味着将 <
转换为 <
,将 >
转换为 >
,将 &
转换为 &
。所以要小心这样做...
myTextBox.Text = Server.HtmlEncode(myStringFromDatabase); // Pseudo code
但是,HyperLink、Literal 和 Label 的 .Text 属性不会对内容进行 HTML 编码,因此需要包装 Server.HtmlEncode();如果您想防止 <script> window.location = "http://www.google.com"; </script>
输出到您的页面并随后执行,则必须围绕在这些属性上设置的任何内容。
做一些实验,看看什么被编码,什么没有。
在 web.config 文件的标记中,插入属性为 requestValidationMode="2.0" 的 httpRuntime 元素。还要在 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);")
另一种解决方案是:
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;
}
}
似乎还没有人提到以下内容,但它为我解决了这个问题。在有人说是之前,它是 Visual Basic ......糟糕。
<%@ Page Language="vb" AutoEventWireup="false" CodeBehind="Example.aspx.vb" Inherits="Example.Example" **ValidateRequest="false"** %>
我不知道是否有任何缺点,但对我来说,这太棒了。
如果您使用的是框架 4.0,那么 web.config 中的条目 (
<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 的内容,那么只需添加其余部分 => 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();
}
}
我想你可以在一个模块中做到这一点;但这留下了一些问题;如果要将输入保存到数据库怎么办?突然,因为您将编码数据保存到数据库中,您最终会信任来自它的输入,这可能是一个坏主意。理想情况下,您将原始未编码数据存储在数据库中,并且每次都进行编码。
在每页级别禁用保护,然后每次编码是更好的选择。
与其使用 Server.HtmlEncode,不如查看 Microsoft ACE 团队提供的更新、更完整的 Anti-XSS library。
我找到了一个使用 JavaScript 对数据进行编码的解决方案,该解决方案在 .NET 中解码(并且不需要 jQuery)。
使文本框成为 HTML 元素(如 textarea)而不是 ASP 元素。
添加隐藏字段。
将以下 JavaScript 函数添加到您的标头。函数 boo() { targetText = document.getElementById("HiddenField1"); sourceText = document.getElementById("userbox"); targetText.value = escape(sourceText.innerText); }
在您的文本区域中,包含一个调用 boo() 的 onchange:
<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(...)
可能需要很长时间。在我的例子中,标记是一个完整的 (2MB) XML 文件。你可能会问,“你为什么不直接使用 <input type="file"...
并且......我同意你的看法 :)
原因
默认情况下,ASP.NET 会针对可能导致 cross-site scripting (XSS) 和 SQL injections 的潜在不安全内容验证所有输入控件。因此,它通过抛出上述异常来禁止此类内容。默认情况下,建议允许在每次回发时进行此检查。
解决方案
在许多情况下,您需要通过富文本框或富文本编辑器将 HTML 内容提交到您的页面。在这种情况下,您可以通过将 @Page
指令中的 ValidateRequest 标记设置为 false 来避免此异常。
<%@ Page Language="C#" AutoEventWireup="true" ValidateRequest = "false" %>
这将禁用对已将 ValidateRequest 标志设置为 false 的页面的请求验证。如果您想禁用此功能,请检查整个 Web 应用程序;您需要在 web.config
<pages validateRequest ="false" />
对于 .NET 4.0 或更高版本的框架,您还需要在
<httpRuntime requestValidationMode = "2.0" />
而已。我希望这可以帮助您摆脱上述问题。
参考:ASP.Net Error: A potentially dangerous Request.Form value was detected from the client
这里的其他解决方案很好,但是必须将 [AllowHtml] 应用于每个 Model 属性,这在后面有点麻烦,特别是如果您在一个相当大的网站上有超过 100 个模型。
如果像我一样,你想在站点范围内关闭这个(恕我直言毫无意义)功能,你可以覆盖基本控制器中的 Execute() 方法(如果你还没有基本控制器,我建议你制作一个,它们可以是对于应用通用功能非常有用)。
protected override void Execute(RequestContext requestContext)
{
// Disable requestion validation (security) across the whole site
ValidateRequest = false;
base.Execute(requestContext);
}
只需确保您对来自用户输入的视图中的所有内容进行 HTML 编码(无论如何,这是带有 Razor 的 ASP.NET MVC 3 中的默认行为,所以除非出于某种奇怪的原因,您正在使用 Html.Raw()不应该需要这个功能。
我也收到了这个错误。
在我的例子中,用户在角色名称中输入了一个重音字符 á
(关于 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) 函数来替换特殊字符。然后服务器端使用 Server.URLDecode(string) 将其切换回来。
这样您就不必关闭输入验证,并且其他程序员会更清楚字符串可能包含 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"]
应该可以工作。
对于那些不使用模型绑定,从 Request.Form 中提取每个参数,确定输入文本不会造成伤害的人,还有另一种方法。不是一个很好的解决方案,但它会完成这项工作。
从客户端,将其编码为 uri 然后发送。例如:
encodeURIComponent($("#MsgBody").val());
从服务器端,接受它并将其解码为 uri。例如:
string temp = !string.IsNullOrEmpty(HttpContext.Current.Request.Form["MsgBody"]) ?
System.Web.HttpUtility.UrlDecode(HttpContext.Current.Request.Form["MsgBody"]) :
null;
或者
string temp = !string.IsNullOrEmpty(HttpContext.Current.Request.Form["MsgBody"]) ?
System.Uri.UnescapeDataString(HttpContext.Current.Request.Form["MsgBody"]) :
null;
请查找 UrlDecode
和 UnescapeDataString
之间的区别
只要这些只是“<”和“>”(而不是双引号本身)字符,并且您在 之类的上下文中使用它们,您就是安全的(而对于 你当然会很脆弱)。这可能会简化您的情况,但要使用其他已发布的解决方案之一。
如果您只是想告诉您的用户不要使用 < 和 >,那么您不希望事先处理/回发整个表单(并丢失所有输入),您可以不简单地放入字段周围的验证器来筛选那些(可能还有其他潜在危险的)字符?
<httpRuntime requestValidationMode="2.0" />
放在位置标记中,以避免破坏站点其余部分的验证提供的有用保护。[AllowHtml]
。Application_Start()
中的GlobalFilters.Filters.Add(new ValidateInputAttribute(false));
。<system.web />
中的<pages validateRequest="false" />
将页面指令添加到 web.config。这样做会将属性应用到所有页面。