2010年8月30日星期一

正確應付ASP.NET 4.0的Request Validation

這個錯誤,我幾乎肯定每一個寫ASP.NET的人都會遇過 :
從客戶端(xxx)中檢測到有潛在危險的Request.Form 值。 說明: 請求驗証過程檢測到有潛在危險的客戶端輸入值,對請求的處理已經中止。...

若上網搜尋解決方法,有半數的答案都是叫你在Page Detective把validateRequest設成"false",Ajax CallBack的話可能會叫你在web.config加入<httpRuntime requestValidationMode="2.0" />就了事。

ASP.NET 4.0的Request Validation由以往2.0時的*.aspx層面擴大至web service (*.asmx)和http handler(*.ashx)層面 (請參考ASP.NET 4 Breaking Changes)。其實既然MS提供全面的防止跨網站(XSS)指令碼攻擊,我們何必把它關掉,如果你想你的網站安全,就必須在Client-Side和Server-Side下功夫。

在設計ASP.NET頁期間,大家都會知道如Button Control都會有OnClick和OnClientClick事件,但如果用上jQueryUI這類純HTML Element的話,大家自然會加上runat="Server",然後掛上Event Handler (如btnSave_OnClick),例如jQueryUI的Button:
<button id="btnSave" runat="server" type="button" OnServerClick="btnSave_Click">
<span>Save</span>
</button>
大家都明白 :
上述Button中的OnServerClick等於ASP.NET原生的Button Control的OnClick ;同樣地OnClick亦等於OnClientClick。

兩者可以並存,而且亦因為會先觸發OnClick的事件,之後再觸發OnServerClick,所以要避免出現Request Validation的錯誤,正確做法就是Post Form前,先用JavaScript把String做一HTML Encode,然後再Post至Server,才是正確的做法。

JavaScript的HTML Encode和Decode,簡單的可以用Replace方法,但我就使用PHPJS的方法,PHPJS中有兩個方法, htmlentities()html_entity_decode(),就是給你做Encode和Decode之用。

假設我有一個TextBox叫txtTitle,一個Button叫btnSave的話,那實際做法就是:
<script type="text/javascript">
$(document).ready(function () {
HtmlDecode();
});

function HtmlEncode() {
html = $('#txtTitle').val();
$('#txtTitle').val(htmlentities(html));

}
function HtmlDecode() {
s = $('#txtTitle').val();
$('#txtTitle').val(html_entity_decode(s));

}
</script>
<asp:TextBox ID="txtTitle" runat="server" MaxLength="100" Width="400" ClientIDMode="Static"></asp:TextBox>
<button id="btnSave" clientidmode="Static" runat="server" type="button" onclick="HtmlEncode();" onserverclick="btnSave_Click">
<span>Save</span>
</button>
這就會在PostBack前,先把txtTitle.Text做一次Encode,那就可以避免出現問題。

上述的程序其實已經做了Encode,所以Server那邊是否需要再做一次HttpUtility.HtmlEncode()呢,我就覺得看你是否對PHPJS或你自定義的方法是否信任,我就安全為上,寫入Database時都會再做一次HttpUtility.HtmlEncode()

沒有留言:

發佈留言