asp.net开发中,经常遇到“从客户端检测到有潜在危险的Request.Form 值”错误提示,很多人给出的解决方案是:
1 <!--web.config文档<system.web>后面加入这一句: <pages validaterequest="false"/> 示例: --> 2 <?xml version="1.0" encoding="gb2312" ?> 3 <configuration> 4 <system.web> 5 <pages validaterequest="false"/> 6 </system.web> 7 </configuration>
1 <%@ page validaterequest="false" language="c#" codebehind="index.aspx.cs" autoeventwireup="false" inherits="mybbs.webform1" %>
其实以上二点的做法都是不正确的,会给程序安全带来风险。
首先出现这个错误的原因是,Asp.Net增加了表单自动检查是否存在XSS(跨站脚本攻击)的功能。当用户提交了非法的字符(如:在线编辑器中的一系列html结构)。出于安全考虑,Asp.Net是直接禁止的,并提示出错。这是ASP.Net提供的一个很重要的安全特性。
不使用默认ASP.Net异常报错信息的程序员们,你们不要禁用validateRequest=false。
正确的做法是在你当前页面添加Page_Error()函数,来捕获所有页面处理过程中发生的而没有处理的异常。然后给用户一个合法的报错信息。
如果当前页面没有Page_Error(),这个异常将会送到Global.asax的Application_Error()来处理。
举例而言,处理这个异常其实只需要很简短的一小段代码就够了。在页面的Code-behind页面中加入这么一段代码:
1 protected void Page_Error(object sender, EventArgs e) 2 3 { 4 5 Exception ex = Server.GetLastError(); 6 7 if (HttpContext.Current.Server.GetLastError() is HttpRequestValidationException) 8 9 { 10 11 HttpContext.Current.Response.Write("请输入合法的字符串【<a href=\"javascript:history.back(0);\">返回</a>】"); 12 13 HttpContext.Current.Server.ClearError(); 14 15 } 16 17 }
这样这个程序就可以截获 HttpRequestValidationException 异常,而且可以按照程序员的意愿返回一个合理的报错信息。
如果页面有富文本编辑器的控件的,那么必然会导致有类的HTML标签提交回来。在这种情况下根据微软的建议,我们应该采取安全上称为“默认禁止,显式允许”的策略。
首先,我们将输入字符串用 HttpUtility.HtmlEncode()来编码,将其中的HTML标签彻底禁止。
1 void submitBtn_Click(object sender, EventArgs e) 2 { 3 4 //将输入字符串编码,这样所有的HTML标签都失效了。 5 6 StringBuilder sb = new StringBuilder(HttpUtility.HtmlEncode(htmlInputTxt.Text)); 7 8 //然后我们选择性的允许<b> 和 <i> 9 10 sb.Replace("<b>", "<b>"); 11 sb.Replace("</b>", "</b>"); 12 sb.Replace("<i>", "<i>"); 13 sb.Replace("</i>", "</i>"); 14 Response.Write(sb.ToString()); 15 16 }
这样我们即允许了部分HTML标签,又禁止了危险的标签。
根据微软提供的建议,我们要慎重允许下列HTML标签,因为这些HTML标签都是有可能导致跨站脚本攻击的。
1 <applet> 2 <body> 3 <embed> 4 <frame> 5 <script> 6 <frameset> 7 <html> 8 <iframe> 9 <img> 10 <style> 11 <layer> 12 <link> 13 <ilayer> 14 <meta> 15 <object>
可能这里最让人不能理解的是<img>。但是,看过下列代码后,就应该明白其危险性了。
1 <img src="javascript:alert('hello');">