2012年3月13日 星期二

不會吧!又掛了

[InvalidOperationException: 由於該物件目前的狀態,導致作業無效。]
   System.Web.HttpValueCollection.ThrowIfMaxHttpCollectionKeysExceeded() +2692482
   System.Web.HttpValueCollection.FillFromEncodedBytes(Byte[] bytes, Encoding encoding) +61
   System.Web.HttpRequest.FillInFormCollection() +148

[HttpException (0x80004005): URL 編碼型式資料無效。]
   System.Web.HttpRequest.FillInFormCollection() +206
   System.Web.HttpRequest.get_Form() +68
   System.Web.HttpRequest.get_HasForm() +8743911
   System.Web.UI.Page.GetCollectionBasedOnMethod(Boolean dontReturnNull) +97
   System.Web.UI.Page.DeterminePostBackMode() +63
   System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +133


出現上面錯誤訊息時,正想要設個中斷點來看看到底哪邊發生錯誤,沒想到,連 Page_Load 事件都還沒進去,且遺言也還沒交待清楚,畫面就已經死掉了。

原來,在 2011 年12月,於德國的 Chaos Communication Congress 會議中,有人展示了透過少量的 Http Request 就可以讓網頁站台變得很忙碌,沒多久就可以讓網站忙到無法再回應新的 Http Reguest 請求而達到阻斷服務攻擊(Denial of Service)的效果。

隨後,在保哥的文章中找到一篇相關文章,於其技術摘要說明裡指出:


我們在開發 ASP.NET 網站時通常都會使用 Request.Form 物件來取得透過瀏覽器 POST 過來的資料,而此物件型別為 NameValueCollection 類別,該類別儲存 Key 的方式是透過雜湊運算的方式計算出來的 (hash-table data-structures),主要目的就是為了用極快的速度找到該 Key 的對應資料,不過此類別自行實做了有別於 .NET Framework 內建的雜湊演算法,它會將所有傳入的 Key 都先轉換為大寫,並使用名為 DJBX33X (Dan Bernstein's times 33, XOR) 的雜湊演算法進行計算,這將導致此演算法有機會遭到 Meet-in-the-middle 攻擊。

駭客能利用這個弱點實做出輕易可達成的 雜湊碰撞攻擊 (Hash collision attacks),此類攻擊可透過傳入大量的 POST 資料並且夾帶許多特別計算過的 Key 值,讓這些 Key 值在這些 Hash-table 中產生出相同的雜湊值,如此一來在這個 Hash-table 中就會出現許多擁有相同雜湊值的 Key,這便是「雜湊碰撞」的由來。而這類雜湊碰撞的情況正是 DJBX33X 演算法的致命傷,當一個 NameValueCollection 中存在著過多的「雜湊碰撞」就會導致電腦花上許多時間對該 Hash-table 進行運算,所以會讓 ASP.NET 執行緒花上數十分鐘到數小時的時間來操作相對應的 Key 值,如此一來便會耗盡網站伺服器的 CPU 資源,進而達到阻斷服務的目的。


就在 Chaos Communication Congress 會議之後,微軟很迅速的將這弱點進行了補強,也提供了 windows update 的服務,基本上,只要你的電腦有乖乖接受每個微軟的安全更新,理論上都已經可以避免如上所說的攻擊手法了,只是,微軟做了甚麼補強?

微軟開始重訂了一個遊戲規則。要求大家 Post 到後台的物件項目不可以超過 1000 個。包括以下:


1.<asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
2.<input type="hidden" id="h_field" runat="server">
3.有已挑選值的 DropDownList (如果下拉清單裡面沒有任何資料,則不算)
4.有已挑選值的RadioButton(如果 RadioButton 裡面沒有任何被選取的資料,則不算)
5.有已挑選值的CheckBox(如果 CheckBox 裡面沒有任何被選取的資料,則不算)
6.有已挑選值的ListBox(如果 ListBox 裡面沒有任何被選取的資料,則不算)

自己詳細檢查了一下出錯的那一頁程式,上面的輸入控制項的確玲郎滿目啊!!

不過,剛開始對於微軟這種補強方法,還真的有點失落,心裡滴咕著,這算甚麼補強嘛,是補弱吧~那真的有需要使用到這麼多欄位需求時,難道得跟客戶說:


事實並非如此的。雖然微軟預設只提供上限 1000 ,但如果有更大的需求時,可以在 web.config 裡的 <appSettings> 加上 :

<add key="aspnet:MaxHttpCollectionKeys" value="2500" />

數值 value 可依實際你所想要允許的最大數量來決定。

Denial of Service 攻擊,的確是一種很難克服的難題。就算你的程式本身沒有問題,還是很有機會被攻擊,更何況被有心人士找到漏洞呢。相信日後這種攻擊手法,會越來越常見。這次微軟非常迅速的發佈更新,讓所有的 .Net 網站可以降低被攻擊的機率,真的值得讚賞。只是,我並沒有因此而得到特別的喜悅。因為我是接到來電說:「paladin,快來看,你的系統當掉了!」。


參考:

01:ASP.NET 發現重大資安弱點影響範圍涵蓋 ASP.NET 1.1 ~ 4.0
02:具有大量表單金鑰、檔案或 JSON 裝載成員的 ASP.NET 請求失敗,並產生例外狀況
03:ASP.NET Security Update Shipping Thursday, Dec 29th

2012年3月7日 星期三

自動調整 iframe 高度


以前使用 iframe 時,總是無可避免當 iframe 裡的資料過長時,就得透過 scroll bar 來捲動,如果刻意將 iframe 的高度設很高,則又擔心有些時候會太浪費網頁版面,如果能夠讓 iframe 依據內容而調整高度,似乎是個比較有彈性的作法。


關於這個想法,在網路上找到兩種類似的作法。


一、Lost-In-Code
在這個網站,提供了一個方便你外掛的 javascript,jquery.autoheight.js。日後只需要將 iframe 的 class 設定為 『autoHeight』,就能夠自動調整 iframe 的高度了。雖然他取名為 jquery,但仔細去觀察 jquery.autoheight.js 這隻程式,裡面並沒有用到 jquery 的語法。作者雖然在他的網頁上註明要引用 jquery 函式庫,但我發現,不引用也是可以的。但實際操作上,自己有遇到一個問題,就是去點選瀏覽器右上方的「最大化/往下還原」時,因為不會重算父親的高度而因此破功。所以自己再加上 $(window).resize() 去重算就可以解決。也因為如此,我還是把 jquery 引用進去好了。


    <script src="Scripts/jquery-1.4.1.min.js" type="text/javascript"></script>
    <script src="Scripts/jquery.autoheight.js" type="text/javascript"></script>
    <script>
        $(function () {
            //攔 resize 事件,並呼叫 jquery.autoheight.js 的 doIframe() 方法
            $(window).resize(function () {               
                doIframe();                
            });
        });
    </script>

<body>
    <form id="form1" runat="server">
    <div>
    <div class="dean_ch">這是父親頁面</div>
    以下是 iframe <br />
    <iframe width="100%" src="FrameA.aspx"  scrolling="auto" frameborder="0"  class="autoHeight" id="ifA"></iframe>    
    </div>
    </form>
</body>

另外 『91』與 『梅問題』 也針對這方法做了介紹,可以參考。


二、Phine Solutions
這個方式適用於每個 iframe,自己去控制呼叫者(父親)所設定的高度。此外,為了處理「最大化/往下還原」的問題,也加上 $(window).resize() 的處理。

    <script src="Scripts/jquery-1.4.1.min.js" type="text/javascript"></script>
    <script>
        function DoAdjHeight() {
            var theFrame = $("iframe", parent.document.body);
            theFrame.each(function () {
                $(this).height($(document.body).height() + 35);
            });
        }
        $(function () {

            DoAdjHeight();

            $(window).resize(function () {
                DoAdjHeight();
            });


        });
    </script>



以上兩種方法,發現它們都會在程式裡面加上一個特別數字 35,似乎是一種最適切的高度位置吧!自己曾經刻意將瀏覽器的縮放比例任意變大變小,的確在有些情況,上述的兩種方式也會突然冒出 scroll bar ,但這種特殊的操作行為,或許可以當成例外,畢竟會這樣使用的人不多;但果真要去處理的話,可能就要去調整這特別的數字。目前,我將他設定為100,幾乎任何縮放比例都可以顯示正常。所以這地方,如果有需要時才去調整這參數會比較適當。

測試程式下載 】
於測試程式中,TestA.aspx 是使用 Lost-In-Code 的方法,而 TestB.aspx 則是使用 Phine Solutions。



參考:
01:http://www.lost-in-code.com/programming/jquery-auto-iframe-height/ (lost-in-code)
02:http://www.dotblogs.com.tw/hatelove/archive/2010/08/12/javascript-iframe-autoheight.aspx (91)
03:http://www.phinesolutions.com/use-jquery-to-adjust-the-iframe-height.html (Phine Solutions)
04:http://www.minwt.com/?p=2425

2012年2月23日 星期四

javascript 上的 reverse()


字串的反轉,在 SQL、C# 使用 Reverse 就可以輕鬆完成。但同樣的需求發生在 javascript 上,卻有點不一樣。在 javascript 裡,並非不支援 Reverse,而是 Reverse 的對象不是字串,而是陣列。所以在使用上,就不能直接呼叫使用,必須稍微做些調整。

看了網路上所介紹到方法,大約可分成兩類:

第一種:透過迴圈方式,將字串由後往前抓一遍
String.prototype.reverse = function() {
    var s = "";
    var i = this.length;
    while (i>0) {
        s += this.substring(i-1,i);
        i--;
    }
    return s;
}

var s="paladin";
alert(s.reverse());
 

第二種:把字串轉成陣列,並將陣列反轉後再組成字串
String.prototype.reverse=function(){return this.split("").reverse().join("");}

var s="paladin";
alert(s.reverse());

個人還蠻喜歡第二種寫法,太簡潔了。日後只需要用:


alert("paladin".split('').reverse().join(''));

就可以把名字倒過來寫了。

此外,還有一個很少使用到的 html 標籤 <bdo>,它可以不透過 javascript 就直接將字串反轉,甚至 <bdo> 標籤裡頭所包含的物件呈現順序也是可以自行設定為由右至左或由左至右,只需去設定 dir 屬性即可(rtl:由右至左,ltr:由左至右)。
<div><bdo dir="rtl">paladin <img alt="1" /> <img alt="2" /></bdo></div>
參考:
01:Reverse-a-txet
02:How do you reverse a string in place in JavaScript?
03:HTML <bdo> Tag

2012年2月20日 星期一

讓 GridView 具有簡單又不失專業的 EmptyDataTemplate


使用 GridView 時,如果它的資料來源沒資料時,顯示個「找不到、0筆資料...」類的訊息,似乎可以讓使用者很清楚的區別。這個功能只需要在 <EmptyDataTemplate>做些訊息的設定即可。但如果是希望即使沒資料,也必須讓 GridView 的 Header 都顯示出來,或是有自訂的樣式時,那要怎麼處理呢?

我在 sidesofmarch 的「Cleaning up the GridView’s EmptyDataTemplate (damn those tables!)」發現了作者的怒吼,認為與其花很多時間在研究 <EmptyDataTemplate>,不如簡單地去判斷是否資料來源有資料,如果沒有,則隱藏目前的 GridView,再進一步去顯示自己所要顯示的資訊。

另外也比較了「ListView EmptyDataTemplate - how to use EmptyDataTemplate」這篇文章,透過 CSS 的定義去達成效果,似乎比較符合自己目前的期待,但如果能夠有更簡單一點的作法,會比較漂亮一些。

更仔細點觀察 GridView ,當我有設定 <EmptyDataTemplate> 且資料來源為 0 時,如果 GridView 原先有放了 4 個欄位,則 <EmptyDataTemplate> 會產生一段 HTML Code:

<tr class="Theader"><td colspan="4"></td></tr>

不管日後在  <EmptyDataTemplate> 放任何東西,都會放在 <td colspan="4"> 裡面,如此就會讓我原先已經套好視覺的 GrideView 顯得與既有的其它 GridView 看起來就會有點不一樣,有點怪,有點壞。

不過,我發現,如果在 <EmptyDataTemplate> 設定一個自訂的 <tr>:

<tr><th>上傳文件</th><th>上傳日期</th><th>說明</th><th>建檔人</th></tr>

,則所產生出來的 HTML,就會有兩個 <tr>,也就是:

<tr><td colspan="4"></td></tr>
<tr><th>上傳文件</th><th>上傳日期</th><th>說明</th><th>建檔人</th></tr>





這樣子的效果,除了第一個 <tr>會讓畫面很突兀外,基本上都已經滿足我的需求了。為了讓第一個 <tr>在畫面上消失,我試著使用 jQuery 把它隱藏起來。

在  <EmptyDataTemplate> 裡,我放入:
<tr class="tr_empty"><th>上傳文件</th><th>上傳日期</th><th>說明</th><th>建檔人</th></tr>


jQuery 則是:
<script>
    $(function () {

        $(".tr_empty").each(function () {

            $(this).parent().find("tr").first().hide();

        });

    });

</script>


這段 jQuery,是在頁面上搜尋所有有定義 class name 為 tr_empty 的物件,往上找到他的父親,<tbody>,再從 <tbody> 裡面往下搜尋第一個 <tr>,並將其隱藏。

這樣就可以將第一個 <tr>隱藏,只剩下我所要呈現的第二個 <tr>

參考:
01:Cleaning up the GridView’s EmptyDataTemplate (damn those tables!)
02:ListView EmptyDataTemplate - how to use EmptyDataTemplate

2012年2月17日 星期五

讓頁尾永遠放在下面

一般來說,網頁的頁首應該要擺最上面,頁尾要擺最下面,中間則是放些比較正經的內容。但如果某個頁面實在乏善可陳,就容易出現頁尾下方空出一大片空白的現象,如何把頁尾永遠放到最下面,真的只是「面子」問題,單純就是看得比較順眼就是了。


在「jQuery教學-重現DIV區塊高度100%的夢想」提到了 autoheight.js ,會透過 jQuery 去計算扣掉頁首、頁尾後需要擴展的內文高度,實際練習後發現非常簡單,真不愧為作者所號稱的懶人包。

使用時,記得將 jQuery 以及  autoheight.js 引用:


 
<script src="Scripts/jquery-1.6.4.min.js" type="text/javascript"></script>
<script src="Scripts/autoheight.js" type="text/javascript"></script>

在網頁的排版上,將頁首、內文、Footer 分別各放在一個 Div 裡,參考一下作者所提供的類別定義:


  • none="ture"->直接取得實際高度,排除所有CSS的設,如:border、margin、padding等。
  • _height="none"->扣除高度。
  • _height="auto"->高度100%
所以我的頁面上,大至會有以下安排:
   <div _height="none"> 頁首
   <div _height="auto"> 內文
   <div _height="none"> 頁尾

如此便可以簡單達成頁首、頁尾分別擺放在網頁的上面以及下面。

參考:梅問題:jQuery教學-重現DIV區塊高度100%的夢想

備份下載 :autoheight.js

2012年2月15日 星期三

福禍相依

《韓非‧解老》解釋福與禍的關係時說:「人有禍則心畏懼,心畏懼則行端直,行端直則思慮熟,思慮熟則明事理。」反之,「人有福則富貴至,富貴至則衣食美,衣食美則驕心生,驕心生則行邪僻而動棄理」。

因此,人活在世界上,要經常保持警覺狀態,如老子所說:「保此道者不欲盈。夫唯不盈,故能敝而新成。」常常讓自己處在不圓滿的狀態中,就會自我要求,繼續成長。不管遇到壞事還是好事,都要看長遠一點。順利的時候,要提醒自己居安思危;倒楣的時候,也千萬不要灰心喪氣。

舉一個千年前吳越的故事來說明。吳王夫差的爸爸名為闔閭,他在對越國的一場戰役中,受到勾踐的突擊而傷重不治。臨死前,召喚夫差於榻前對他說:「你會忘了勾踐殺父的仇怨嗎?」夫差回答:「誓不敢忘!」待夫差即位後,他命令大臣,每天早朝時,都要提醒他三次:「夫差,你忘了勾踐的殺父之仇了嗎?」。然後夫差就會馬上回答:「誓不敢忘,父仇不共戴天!」。

夫差每天都要這樣砥礪自己、提醒自己,於是做到了: 「人有禍則心畏懼,心畏懼則行端直,行端直則思慮熟,思慮熟則明事理。

果然夫差的努力並沒有白費,在下一場的吳越 PK 戰中,夫差大敗勾踐,逼得勾踐不只讓越國成為吳國的屬國,還自願到吳國當奴僕。自此開始,勾踐開始不斷地把金銀財寶、絕世美女,一車一車載往吳國的王宮中。夫差自從報仇之後,每天上朝時,也就免了「你會忘了勾踐殺父的仇怨嗎?」的劇碼,開始享受越國所提供的大量美女與金銀財寶了。

沒多久,「人有福則富貴至,富貴至則衣食美,衣食美則驕心生,驕心生則行邪僻而動棄理」就開始靈驗了。夫差開始因貪戀美色而多日不上班,老臣伍子胥嘮叨久了,更因此而開始加深這對君臣間的裂痕,最後伍子胥竟被夫差賜死。

在此同時,勾踐也開始模仿夫差早先的勵志作法。史記記載著:「吳既赦越,越王勾踐返國,乃苦身焦思,置膽於坐,坐臥即仰膽,飲食亦嚐膽也」,開始了所謂的「臥薪嘗膽」的生活。「人有禍則心畏懼,心畏懼則行端直,行端直則思慮熟,思慮熟則明事理。」這句話的力量,又再次被體現了,只是這次已從夫差換成勾踐。


參考:

01:原來老子這樣說
02:千秋商祖范蠡

踩到 AjaxControlToolkit 3.5 的地雷


今天開開心的下載了最新版的 AjaxControlToolkit 4.0,也把它整合到我的 VS2010,想測測 Tab 功能。但腦筋突然閃過「User 那邊只有 .Net 3.5 的環境」,就只好再回去下載 AjaxControlToolkit 3.5。

我將 VS2010 的環境調整為 .net framework 3.5 ,也同時將  AjaxControlToolkit 3.5 加入了參考,但執行時,卻跑了錯誤出來。

AjaxControlToolkit requires ASP.NET Ajax 4.0 scripts. Ensure the correct version of the scripts are referenced. If you are using an ASP.NET ScriptManager, switch to the ToolkitScriptManager in AjaxControlToolkit.dll.

真是奇怪了,明明就下載 AjaxControlToolkit 3.5 的版本,卻要求我要用 4.0 ,這樣對嗎?仔細消化了這一段錯誤訊息,終於瞭解了他想要描述甚麼。不過這突然讓我反省到,自己所寫的系統發出錯誤訊息時,往往只是「系統發生錯誤,請聯絡 XXX」。相較之下,人家已經比我詳細多了。

原來我在使用 AjaxControlToolkit 所提供的元件時,依例都會在頁面最上面擺放一個 <asp:scriptmanager id="ScriptManager1" runat="server"> </asp:scriptmanager>,但是這個錯誤訊息,是叫我不要使用 ScriptManager ,改成用 ToolkitScriptManager。問題是,要怎麼改才對呢? 原來,是要改成以下方式:

<asp:toolkitscriptmanager id="ScriptManager1" runat="server"></asp:toolkitscriptmanager>

如此修改後,程式就可以正常執行了。另外,In 91 有說章立民老師文章中提及的「為了讓JavaScript檔案能夠先壓縮再下載,以便提昇下載效率並降低請求(Request)次數,請大家在設計ASP.NET AJAX網頁時,應該盡量使用ToolkitScriptManager來取代ScriptManager。」,倒是意外的發現。

參考:http://www.dotblogs.com.tw/hatelove/archive/2009/02/17/7211.aspx