前言
本文為《現代 PHP》一書的學習筆記。
環境
- Windows 10
- Wnmp 3.1.0
良好習慣
PHP 語言仍然包含了許多過時的工具,一不小心,有可能使用了這些工具做出效能差且不安全的應用程式。
所以必須要知道那些工具可以使用,哪些必須忽略。
消毒、驗證及跳脫
永遠不要相信任何來源不明的資料,一些外部的來源如下:
$_GET
$_POST
$_REQUEST
$_COOKIE
$argv
php://stdin
file_get_contents()
- 遠端資料庫
- 遠端 API
- 來自客戶端的資料
所有上述的外部資料來源都有可能是攻擊的源頭。
消毒使用者輸入
假如網頁允許使用 HTML
下評論,在原始設定中,沒有任何東西會阻止使用者在評論中使用不合理的 <script>
標籤,例如:
1 | <p> |
如果沒有消毒這個評論,惡意的程式碼將會被注入到資料庫中。
HTML
可以利用 htmlentities()
函式,將 HTML
的特殊字元消毒成對應的 HTML
代表字元,這個函式會將字串轉化成對應用程式儲存層較安全的型態。
範例 5-1:以 htmlentities()
函式消毒使用者輸入
1 | $input = '<p><script>alert("You won the Nigerian lottery!");</script></p>'; |
htmlentities()
函式的第一個參數是字串、第二個參數是ENT_QUOTES
,告訴函式要將單引號進行編碼、第三個參數指定了使用者輸入的字元集。
SQL 查詢
未經處理的 SQL
查詢使得懷有惡意的人可以入侵並且破壞資料庫。
範例 5-2:不良的 SQL 查詢
1 | $sql = sprintf( |
如果有人發送以下的 HTTP
請求到此 PHP 腳本,每個使用者的密碼都會被設定為 abc
,因為很多 SQL
資料庫把「--
」視為是註解的開頭。
Method | URL | Key | Value |
---|---|---|---|
POST | /user?id=1 | password | abc”;– |
使用個人資料
PHP 提供了 filter_var()
和 filter_input()
函式來消毒不同形式的使用者輸入,如:電子郵件位址、URL
編碼字串、整數、浮點數、HTML
字元、URL
和指定的 ASCII
字元範圍。
範例 5-3:消毒使用者輸入中的電子郵件位址
1 | $email = '[email protected]'; |
範例 5-4:消毒使用者輸入中的國際字元
1 | $string = "\nIñtërnâtiônàlizætiøn\t"; |
驗證使用者輸入
與消毒不同的是,驗證並不會對使用者輸入中不合法的資料進行去除,驗證只是確認輸入資料是否達到預期。
使用 filter_var()
函式搭配任何 FILTER_VALIDATE_*
旗標來驗證使用者輸入。
範例 5-5:驗證電子郵件位址
1 | $input = '[email protected]'; |
filter_var()
函式如果驗證成功,會回傳被驗證的値,否則會回傳false
。
不過 filter_var()
函式並沒有辦法驗證所有東西,以下元件可以補足:
跳脫使用者輸出
當要把資料輸出到網頁或是 API 響應時,跳脫輸出讓應用程式多增加一層防護。
如同前面提到的,可以用 PHP 的htmlentities()
函式跳脫輸出。
1 | $output = '<p><script>alert("NSA backdoor installed");</script>'; |
參考資料
- Josh Lockhart(2015)。現代 PHP。台北市:碁峯資訊。