HiddenField陷阱

1. 我放在HiddenField里的值呢?

通常作为客户端脚本与服务器端代码沟通桥梁之一的HiddenField控件,其实有一个小小的"陷阱"。如下面的代码片段:

Code


后台代码片段:

Code


HiddenField控件hdLastSelectedId位于被禁用的WebControl内部,因而呈现出来的HTML标记类似如下:

<div id="thePanel" disabled="disabled"> 
    
<input type="hidden" name="hdLastSelectedId" id="hdLastSelectedId" value="17" /> 
</div>


浏览器在处理表单提交时,对于处于disabled的标记内或标示了disabled的所有input控件,将不会生成表单参数名称值对。也就是说,如果没有其他的状态恢复机制,标记为disabled的区域内的input值将会丢失。因此,上面的代码中的按钮点击事件将输出空字符串。而如果将上述HiddenField控件换成TextBox控件,则可以正常输出“17”。

ASP.net因为ViewState机制的存在,使得如TextBox等一些控件的值可以从ViewState中恢复,而HiddenField有些不一样,看下面的代码(Reflector HiddenField的代码)

protected internal override void OnPreRender(EventArgs e) 

   
base.OnPreRender(e); 
   
if (!this.SaveValueViewState) 
    { 
       
this.ViewState.SetItemDirty("Value", false); 
    } 
}


而:

Code


也就是说默认情况下,仅在上面加粗的代码处的条件成立时,HiddenField的值才会被保存至ViewState,才有可能在回送时得到恢复。
因此,如果有像上面例子中HiddenField控件的应用场景(其实应该尽量避免),要想在回送后成功获取HiddenField的值,可以为HiddenField添加上ValueChanged事件。

2. Enabled,Disabled以及ReadOnly

WebControl.Enabled=false与HtmlControl.Disabled=true在很多时候容易混淆,其实两者有较大的区别。WebControl.Enabled=false一般将影响该Web控件的服务器端行为,以及客户端呈现,并且会将WebControl的所有子控件Enabled属性设为false。而HtmlControl.Disabled=true一般仅影响客户端呈现,且并不随控件层次传递。

MSDN:http://msdn.microsoft.com/zh-cn/library/system.web.ui.webcontrols.webcontrol.enabled.aspx
            http://msdn.microsoft.com/zh-cn/library/system.web.ui.htmlcontrols.htmlcontrol.disabled(VS.80).aspx

对于表单中的字段,上面两种情况在客户端最终产生的效果是一样的,即让浏览器在提交表单时忽略掉标记为disabled的表单字段。而即使是标记为disabled的字段,如果在客户端被修改为可用,且窜改了字段的值,则服务器端仍然会接受新提交的值,并不会做状态的校验,因此很容易被恶意用户伪造表单进行攻击。

如果是想让TextBox控件的值不能被修改,不是将其Enabled=false,而应该使用ReadOnly=true。这将使得TextBox在恢复状态时忽略掉客户端提交的表单中对应的字段值而只从ViewState中恢复。此外如果启用了ViewState加密,那么这样的表单字段才应该算是比较安全的。

HiddenField控件比较特殊,既没有Enabled属性,也没有ReadOnly属性,也无法使用内置的验证控件。原因可能很简单,因为它不需要UI呈现。但是因为这些原因,HiddenField是一个比较危险的控件,而在实际开发中往往有滥用的倾向,总以为Hidden了就谁也看不见。很多时候我们可以不用它而使用别的替代方式,比如直接使用ViewState(在性能允许的情况下最好启用ViewState加密)。或者至少确保提交的值在服务器端一定进行校验。具体依应用而定,这里就不讨论了。

posted @ 2009-10-21 23:41  ASeign  阅读(2174)  评论(3编辑  收藏  举报