iT邦幫忙

2021 iThome 鐵人賽

DAY 3
1
Security

從以卵擊石到堅若磐石之 Web API 安全性全攻略系列 第 3

Day03-入口管制(二)

前言

昨天在講格式驗證的時候有提到 Node.js 的 validator 跟 Go 的 govalidator 有很多好用的功能可以用,像是幫你驗證 isEmail()isMobilePhone() 之類的,但萬一你要的功能沒有在裡面呢?譬如說你想要驗證的格式是台灣自來水公司的水號、或是公司自訂的產品序號等等,這時就需要出動 regular expression 了,而今天就是要來說說在寫 regex 時有哪些該注意的地方

Regular Expression

怕有人太久沒用已經快忘記 regex 的語法XD,這邊簡單回顧一下:regex 是可以用來比對字串是不是符合某個 pattern 的工具,譬如說手機號碼是十個數字,那我就可以寫 [0-9]{10},而信箱是中間有 @ 的任意字串,那就可以寫成 .+@.+,如果還是想不起來的話我找了一個 Cheat Sheet,看一看應該就會用了~

盡量不要用 +*

首先,因為任何類型的資料一定都有他的適當長度,所以應該用更確切的長度範圍來做限制而不是用 +*

譬如說上面信箱 .+@.+ 的例子,你的程式應該不可能接受 a@b 這麼短的信箱吧,反之當然也不可能接受長到一萬字的信箱,所以你至少應該把它改成 .{2,50}@.{5,50} 這個比較合理的範圍

那為什麼要這麼講究範圍呢?因為爆長或爆短的資料通常都不會是正常的資料,比較可能是攻擊者刻意造出來試探的。如果這些資料不幸進到資料庫可能會導致預期外的錯誤

盡量不要用 .

除了不要用 +* 之外,最好也不要濫用 . 來匹配任意字元,因為絕大部分情況你想要的都不是任意字元,而是數字(\d)、英數字(\w)、或者範圍更大的非空白字元(\S)

如果像上面舉的例子直接用 .+@.+ 來驗證信箱的話,可能就會誤把 hello world@gmail.com 存進資料庫,進而導致寄信時奇怪的 bug

沒頭沒尾

很多人在寫 regex 驗證字串時會忘記把頭尾的 ^$ 寫進去,但因為 regex 在匹配時只要有子字串符合就可以了,因此判斷出來的結果會跟原本想的不太一樣

譬如說我想用 \d{5} 來檢查輸入是不是五位數字,是的話就有可能是台灣的郵遞區號,但如果我直接寫 \d{5} 的話可能會不小心接受了更長的字串,必須要寫成 ^\d{5}$ 才行

const badRegex  = /\d{5}/
const goodRegex = /^\d{5}$/

badRegex.test("12345")    // true
badRegex.test("1234567")  // true(明明有七個數字卻被判定為 true)

goodRegex.test("12345")   // true
goodRegex.test("1234567") // false(只允許五個數字所以判定為 false)

小結

因為各個語言都有 validator 這種 library,所以一般來說在做 input validation 不太會需要手刻 regular expression,只需要呼叫別人寫好的 isEmail()isDate() 就好了

但因為還是有少數情況需要自己寫 regex,所以這時候就得小心謹慎一點,才不會一個不小心就讓怪怪的資料進到資料庫(我就曾經這樣過XD),到時候再要清理就真的很麻煩~


上一篇
Day02-入口管制(一)
下一篇
Day04-入口管制(三)
系列文
從以卵擊石到堅若磐石之 Web API 安全性全攻略30

尚未有邦友留言

立即登入留言