使用 Regular Expression 驗證密碼:使用 JavaScript 的陷阱

我在前年有寫過一篇【 使用 Regular Expression 驗證密碼 】文章,當時撰寫的技巧完全是針對 .NET 提供的 Regular Expression 而寫,雖然我的文章在標籤的地方有特別提到 .NET,但還是有人將文章裡提供的 Regular Expression 直接抄去給 JavaScript 使用,結果當然是養出一堆莫名其妙的臭蟲(Bug)。

我在當時的文章中採用的 .NET Regular Expression 的右合樣(英文稱為 Lookahead 或稱為 Positive Lookahead ),該功能其實在所有瀏覽器都有支援,但是邪惡的 IE5 , IE6 , IE7 卻實做出錯誤的樣式比對規則。至於 Regular Expression 的左合樣 (Negative Lookbehind) 則是在任何瀏覽器的 JavaScript 都不支援。

當時文章的範例語法如下:

^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{6,30}$

而我自己設計了一個 JavaScript 單元測試案例,共有 44 個 Test Case 去測試一個較簡單的樣式,終於研究出 IE7 以下版本對於右合樣的處理行為!

如下樣式,用來比對測試的字串是否符合:至少一個小寫字母、一個數字,且最少 5 個字元以上!

^(?=.*[a-z])(?=.*\d).{5,}$

首先,這個樣式在 IE 8 , Firefox 3.6 , Google Chrome 皆可正確比對,我另外利用 IETester 測試了 IE5 , IE6 , IE7 等不同瀏覽器版本,得到的結果不太一樣,其測試結果如下:

IE8 ,Firefox 3, Chrome 3/4 IE5, IE5.5, IE6, IE7
1. Testing 12345 Failed
2. Testing abcde Failed

3. Testing a1 Failed
4. Testing a12 Failed
5. Testing a123 Failed
6. Testing a1234 OK
7. Testing a12345 OK
8. Testing a123456 OK

9. Testing ab1 Failed
10. Testing ab12 Failed
11. Testing ab123 OK
12. Testing ab1234 OK
13. Testing ab12345 OK
14. Testing ab123456 OK

15. Testing abc1 Failed
16. Testing abc12 OK
17. Testing abc123 OK
18. Testing abc1234 OK
19. Testing abc12345 OK
20. Testing abc123456 OK

21. Testing 1a Failed
22. Testing 1ab Failed
23. Testing 1abc Failed
24. Testing 1abcd OK
25. Testing 1abcde OK
26. Testing 1abcdef OK

27. Testing 12a Failed
28. Testing 12ab Failed
29. Testing 12abc OK
30. Testing 12abcd OK
31. Testing 12abcde OK
32. Testing 12abcdef OK

33. Testing 123a Failed
34. Testing 123ab OK
35. Testing 123abc OK
36. Testing 123abcd OK
37. Testing 123abcde OK
38. Testing 123abcdef OK

39. Testing 123a Failed
40. Testing 123a1 OK
41. Testing 123a1b OK
42. Testing 123a1b2 OK
43. Testing 123a1b2c OK
44. Testing 123a1b2c3 OK
1. Testing 12345 Failed
2. Testing abcde Failed

3. Testing a1 Failed
4. Testing a12 Failed
5. Testing a123 Failed
6. Testing a1234 Failed
7. Testing a12345 OK
8. Testing a123456 OK

9. Testing ab1 Failed
10. Testing ab12 Failed
11. Testing ab123 Failed
12. Testing ab1234 Failed
13. Testing ab12345 OK
14. Testing ab123456 OK

15. Testing abc1 Failed
16. Testing abc12 Failed
17. Testing abc123 Failed
18. Testing abc1234 Failed
19. Testing abc12345 OK
20. Testing abc123456 OK

21. Testing 1a Failed
22. Testing 1ab Failed
23. Testing 1abc Failed
24. Testing 1abcd Failed
25. Testing 1abcde OK
26. Testing 1abcdef OK

27. Testing 12a Failed
28. Testing 12ab Failed
29. Testing 12abc Failed
30. Testing 12abcd Failed
31. Testing 12abcde OK
32. Testing 12abcdef OK

33. Testing 123a Failed
34. Testing 123ab Failed
35. Testing 123abc Failed
36. Testing 123abcd Failed
37. Testing 123abcde OK
38. Testing 123abcdef OK

39. Testing 123a Failed
40. Testing 123a1 Failed
41. Testing 123a1b Failed
42. Testing 123a1b2 Failed
43. Testing 123a1b2c OK
44. Testing 123a1b2c3 OK


因為右、左合樣的寬度永遠為零,所以照理說處理上述樣式時 (?=.*[a-z])(?=.*\d) 樣式不應該佔用任何比對的空間,但是在 IE5, IE6, IE7 卻會佔用,因而導致樣式處理發生邏輯不正確的情況!

拿上述測試案例的 abc1234 來說,它先比對 (?=.*[a-z]) 樣式,發現沒比對到,便跳至 (?=.*\d) 樣式比對,這個樣式比對後便把 .* (即 abc 部分) 的比對給吃掉了,也就是之後的 .{5,} 樣式不會再比對 abc 這三個字元,所以光是比對 1234  就會因為不足 5 個字元而發生樣式比對失敗!

拿上述測試案例的 abc12345 來說,它先比對 (?=.*[a-z]) 樣式,發現沒比對到,便跳至 (?=.*\d) 樣式比對,這個樣式比對後便把 .* (即 abc 部分) 的比對給吃掉了,也就是之後的 .{5,} 樣式不會再比對 abc 這三個字元,接著再比對 12345  就會因為符合至少 5 個字元的樣式要求而比對成功!

另外,我也利用 Browsershots 網站幫我額外測試另外 46 個在 Windows 平台上不同種類、版本的瀏覽器,以及 56 個跨平台各主要瀏覽器,我不得不說在大多數唸的出名字的瀏覽器中只有 IE 有這種邏輯錯誤的狀況 ( 當然我們還是要給 IE8 鼓鼓掌 )。

所以若有人要在 JavaScript 中實做 Regular Expression 必須特別特別小心,否則寫出了 Bug 還不自知,孰知這個 Bug 不是開發人員的錯,但客戶總是怪我們對吧!遇到這種瀏覽器的 Bug 真是如同天色暗了、天空陰了、空氣涼了這樣的感覺。

各位有興趣也可以自行測試看看,以下是測試網頁:

再次聲明:Regular Expression 是學一次用一輩子的技能,我認為是任何程式設計師必學的技能之一。

相關連結

  

此文章由 will 發表於 2010/3/8 上午 02:17:01

永久連結 | 評論 (0) | 此文章的RSSRSS comment feed |

分類: JavaScript | Web

標籤: , ,

收藏:

你想要花 17 個小時從領域專家學會 JavaScript 嗎?

學習 JavaScript 除了看書外,我之前也看了好幾則線上的 JavaScript 影片,收穫非常大,之前也在我的噗浪上分享了一些心得,想不到在網路上看到有人將這些 JavaScript 專家錄製的影片做了個整理,其中好幾則影片就是我之前看過的,這些演講者都是 JS 界的大師,有心想學好 JavaScript 的人不可不看!

這個由 Andrew Burgess 整理的文章 ( 17 Hours of JavaScript from the Masters ) 其實已經非常完整,我寫這篇文章其實就是想提醒各位有這個連結,這裡所列出的都是非常好的學習資源,像是 Douglas Crockford, John Resig, Peter-Paul Koch, Nicolas C. Zakas 都是在 JavaScript 領域非常專精的專家,透過專家的對 JavaScript 各個環節解說的觀點可以讓你對 JavaScript 的理解更上一層樓。

相關連結

  

此文章由 will 發表於 2009/12/21 下午 11:58:57

永久連結 | 評論 (4) | 此文章的RSSRSS comment feed |

分類: JavaScript

標籤:

收藏:

如何自動取得所有前端 JavaScript 錯誤以提升網站品質

我們每個案子都會用許多錯誤追蹤的機制確保網站品質,但還是不時會讓客戶發現有些功能無法操作,而這些問題大多出在 JavaScript 錯誤,由於一些老舊的瀏覽器或不同瀏覽器特性不同的關係,難免會有不小心寫錯的時候,為了能有效追蹤這些不易察覺的錯誤,我們會利用 JavaScript 追蹤 JavaScript 錯誤!

這個需求透過 jQuery 來做最方便了,透過 error(fn) 事件即可達成此一目標:

$(window).error(function(msg, url, line){
jQuery.post("/js_error_log.ashx", { msg: msg, url: url, line: line });
});

透過這個技巧即可有效獲得即時的前端資訊,看你要儲存到資料庫、EventLog、File、或郵寄出來都可以,不過唯一要小心的地方是當錯誤非常多時,這個錯誤追蹤的量可能會非常大,這時要特別注意程式的寫法,不要因為前端的錯誤槁掛了你的伺服器,而且有查到錯誤就要立即處理,降低錯誤發生的次數與提升網站品質。

相關連結

  

此文章由 will 發表於 2009/12/7 下午 12:08:01

永久連結 | 評論 (5) | 此文章的RSSRSS comment feed |

分類: Tips | JavaScript | Web

標籤: , ,

收藏:

設定 Cookie 時可善用 HttpOnly 特性減低網站安全風險(XSS)

Cookie hijacking 是個很常見的 XSS 攻擊手法,大多是利用網站既有的 XSS 漏洞並透過 JavaScript 取得 documnet.cookie 資料,而 documnet.cookie 就包含所有你在該網頁所有可用的 Cookie 資料,但若你的網站程式在設定 Cookie 的時候有特別加上 HttpOnly 屬性,就可以進一步避免該頁的 Cookie 被 JavaScript 存取,也可保護使用者的 Cookie 不會偷走。

以下是 ASP.NET 的程式範例:

// Create an HttpOnly cookie.
HttpCookie myHttpOnlyCookie = new HttpCookie("LastVisit", DateTime.Now.ToString());

// Setting the HttpOnly value to true, makes
// this cookie accessible only to ASP.NET.

myHttpOnlyCookie.HttpOnly = true;
myHttpOnlyCookie.Name = "MyHttpOnlyCookie";
Response.AppendCookie(myHttpOnlyCookie);

由於 HttpOnly 是 W3C 的標準配備,所以不止 ASP.NET 可以運用這個技巧,其他程式語言要利用 HttpOnly 時只要在 Set-Cookie 的 Header 最後面加上 ; HttpOnly 即可套用完成,如下圖示:

image

所以你的網站在使用 Cookie 時如果確定該 Cookie 不會或不需要被 Browser 端的 JavaScript 使用,建議都加上 HttpOnly 屬性,以免當真的有一天你的網站不小心出現了 XSS 弱點時不會傷及無辜用戶。

雖然套用 HttpOnly 屬性可以有效防堵 Cookie 被劫走(Hijacking),但這並不代表使用 HttpOnly 就是安全的!因為如果你的網站還是有 XSS 風險,還是很有機會讓駭客利用 XHR 代客操作,所以就算駭客不取得 Cookie 也可以達成攻擊的手段。

另外,由於 Cookie 一樣會透過 HTTP 在網路上傳輸,被半路攔截的機會還是有的,建議使用 SSL 保護網路封包的傳輸,避免資料遭攔截。

我的 解釋 Cookie 的特性 文章有解釋 Cookie 的特性,不甚了解的人建議可閱讀一番,Cookie 基本上有兩種類型:Persistent Cookie 與 Session Cookie,而 HttpOnly 可套用在任何 Cookie 類型上,唯一的差別僅在於可不可以由 JavaScript, Silverlight 或 Flash 等前端程式存取而已!

相關連結

  

此文章由 will 發表於 2009/11/26 下午 12:13:48

永久連結 | 評論 (0) | 此文章的RSSRSS comment feed |

分類: Web | JavaScript | ASP.NET | Security

標籤: , , ,

收藏:

在 Web 2.0 時代必須重視 JavaScript/JSON Hijacking 攻擊

ASP.NET MVC 2.0 Preview 2 開始 JsonResult 已經被修改成只能在 HTTP POST 的時候回應,像我們經常使用 jQuery$.getJSON 就不能再用了,我從 ASP.NET MVC 2.0 Preview 2 Release Note 得知 JSON Hijacking 之後就持續追蹤下去,覺得這是個非常值得注意的安全問題。

前陣子 Twitter 就被發現了一個 JSON Hijacking 漏洞,可以讓使用者在進入惡意網站後被取得你所有在 Twitter 的好友清單。建議有在使用 JSON 或動態下載 JavaScript 的網站都應該特別注意!

我看了好幾篇文章,不過都是英文的,解釋的非常清楚,相關資訊請參考「相關連結」。以下我列出幾個中文的文章供各位參考:

要避免這個問題,最簡單的作法就是『不要透過 HTTP GET 送出 JSON 資料』,雖然 jQuery 沒有內建 $.postJSON 方法,但卻非常容易實做,且在官網的 jQuery.post 文件有提供一個簡單的範例如下:

$.postJSON = function(url, data, callback) {
$.post(url, data, callback, "json");
};

相關連結

  

此文章由 will 發表於 2009/11/13 下午 11:55:00

永久連結 | 評論 (3) | 此文章的RSSRSS comment feed |

分類: .Net | ASP.NET MVC | JavaScript | Security | Web

標籤: , , , , ,

收藏: