ASP.NET MVC 3里面客户端输入验证的改动

最近在用ASP.NET MVC 3,在通过TinyMCE HTML编辑器,向服务器端输入HTML代码时,收到了下面这个错误信息:

异常详细信息: System.Web.HttpRequestValidationException: 从客户端(test="<a>adfasdf</a>")中检测到有潜在危险的 Request.Form 值。

很明显,这是ASP.NET为了阻止跨站脚本攻击所实现的防御措施,然而在我的情况下,我的确需要ASP.NET临时关闭这个检查机制,因为这个时候我需要保存原始的HTML文本。在网上搜了一下,发现很多人的解决方案有点粗暴,要么是直接将整个站点的HTML跨站攻击检测机制禁止掉:

  1. web.config文件里,添加上<httpRuntime requestValidationMode="2.0" />
  2. 然后再<pages>节设置validateRequest="false" 禁用请求验证。

安全一点的,也是把整个页面的检测机制禁止掉—即通过在webform页面的Page指令禁用请求验证,或在MVCController上加上[ValidateInput(false)]属性。下面这个razor语法的页面就可以让你重现这个问题:


代码
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    
<title>Sample Page</title>
<script src="@Url.Content("~/Scripts/jquery-1.4.2.min.js")" type="text/javascript"></script>
    
<script type="text/javascript" src="@Url.Content("~/Scripts/tinymce/tiny_mce.js")"></script>
    
<script type="text/javascript" src="@Url.Content("~/Scripts/tinymce/jquery.tinymce.js")"></script>
    
<script language="javascript" type="text/javascript">
        $(document).ready(
function () {
            $(
'#test').tinymce({
                mode: 
"textareas",
                theme: 
"simple"
            });
        });
    
</script>
</head>

<body>
  
<form method="post" action="">
    
<label for="test">测试</label>
    
<textarea name="test" id="test">
    
</textarea>
    
<br />
    
<input type="submit" value="提交" />
  
</form>
  
<br />
  @if ( IsPost ) {
      
<div>@Request["test"]</div>
  }
</body>
</html>


 

MVC 3里,请求验证以及集成到HttpModule这一层了,也就是说,即使你用上面那两个方法,有可能还是禁用不了请求验证。这是因为上面两个方法是在处理Page的时候才有效,而HttpModulePage接收到请求之前就已经执行请求验证了。在MVC 3里,你可以告诉请求验证程序对一个字段忽略请求验证,但依然对其他字段执行请求验证。通过下面这条语句就可以指明你希望跳过验证的字段了—参数就是表单里输入控件的name属性值:


@{    
    var text 
= Request.Unvalidated().Form["test"];
}


另外,请注意Unvalidated这个函数,你只有在安装了WebMatrix Beta2以及ASP.NET MVC 3 RC后才有。

 

装好WebMatrix Beta 2,再次访问网页,你就可以看到在test文本框里输入的html字符串可以正常通过验证,但是在其他文本框输入的html字符串则不能通过验证。

 

但是,接下来又有另外一个问题,当你回显HTML字符串的时候,它并没有跟你想象的那样作为HTML代码插入,而被当作了普通文本输出,如下图:

 

这是因为,在MVC 3Razor引擎里,默认情况下,所有的字符串都会先被转义以后才能输出,也就是说,下面这段代码:

<div>text</div>

 

实际上是被Razor引擎替换成下面的代码:

 

<div>@Server.EncodeHtml(text)</div>

 

如果你需要修改这个行为,应该将代码改成下面这样:

 

var wrapper = new HtmlString(text);
<div>@wrapper</div>

 

下面是完整的代码(注意,你需要安装了WebMatrix Beta2以及ASP.NET MVC 3 RC才能顺利编译):

代码
@{    
    var text = Request.Unvalidated().Form["test"];
}
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    
<title>Sample Page</title>
    
<script src="/Scripts/jquery-1.4.2.min.js" type="text/javascript"></script>
    
<script type="text/javascript" src="/Scripts/tinymce/tiny_mce.js"></script>
    
<script type="text/javascript" src="/Scripts/tinymce/jquery.tinymce.js"></script>
    
<script language="javascript" type="text/javascript">
        $(document).ready(
function () {
            $(
'#test').tinymce({
                mode: 
"textareas",
                theme: 
"simple"
            });

        });
    
</script>
</head>

<body>
  
<form method="post" action="">
    
<label for="test">测试</label>
    
<textarea name="test" id="test">
    
</textarea>
    
<br />
    
<input type="submit" value="提交" />
  
</form>

  
<br />
  @if ( IsPost ) {
      var wrapper = new HtmlString(text);
      
<div>@wrapper</div>
  }
</body>
</html>


 

 

 

标签: NET, ASP NET
posted @ 2010-11-17 17:10 donjuan 阅读(2748) 评论(7) 编辑 收藏

 回复 引用 查看   
#1楼2010-11-18 09:17 | 阿不      
Unvalidated这个函数是在System.Web.WebPages.dll里面,只要引用这个程序集就可以了。
 回复 引用 查看   
#2楼2010-11-18 09:39 | 小刚qq      
WebMatrix 是干嘛的?
 回复 引用 查看   
#3楼[楼主]2010-11-18 09:42 | donjuan      
@小刚qq
WebMatrix是轻量级的ASP.NET编程工具,是免费的,里面自带了SQL CE, IIS Express。基本上用它,你就可以不用Visual Studio写ASP.NET程序了。

 回复 引用 查看   
#4楼2010-12-23 11:11 | 深邃的背影      
我用MVC3 RC+CKeditor
在config中添加了<pages validateRequest="false"></pages>和<httpRuntime requestValidationMode="2.0" />
也在action上添加了[ValidateInput(false)]
还是不行,报错内容为:从客户端(...)中检测到有潜在危险的Request.Form

 回复 引用 查看   
#5楼[楼主]2010-12-23 11:34 | donjuan      
@深邃的背影
那你尝试一下文章里介绍的Request.Unvalidated().Form["test"];,其中test是CKeditor控件的name属性。

 回复 引用 查看   
#6楼2011-04-21 17:54 | 为了生活所以热爱      
我用了上面那个方法还是没用
 回复 引用 查看   
#7楼[楼主]2011-04-21 23:04 | donjuan      
@为了生活所以热爱
奇怪了,我自己的程序就一直用这个方案啊。难道是升级到ASP.NET MVC 3正式版有变化?

公告

昵称:donjuan
园龄:3年
粉丝:49
关注:7
<2010年11月>
31123456
78910111213
14151617181920
21222324252627
2829301234
567891011