PHP網站常見的安全漏洞及防範措施

PHP網站常見的安全漏洞及防禦措施

注: 拿電商系統來舉例 (框架:Laravel5.*)

1.SQL注入漏洞

SQL注入是最古老、最流行同樣也是危害最大的漏洞之一,該漏洞從核心來說就是:將 【未經過濾】 的用戶輸入拼接到SQL語句中。

舉個例子:

 $product = DB::select("select * from products where id = '".$_GET['id']."'");

這個時候用戶提交的 id 如果是 1 and 1 = 2,那麼最終被執行的 SQL 就是:

 select * from products where id = 1 and 1 = 2

很明顯這個 SQL 查出來的結果必然爲空,那麼頁面就會顯示該商品不存在。

但僅僅是這樣感覺好像沒有什麼危害,那這個時候攻擊者提交的 id 參數變成了:

 1 and exists (select * from admins where name = 'admin')

執行的 SQL 就變成了:

 select * from products where id = 1 and exists (select * from admins where name = 'admin')

假如攻擊者看到了正常的商品頁面,那就說明這個網站存在一個名爲 admin 的管理員。接着請求:

 1 and exists (select * from admins where name = 'admin' and len(password) = 32)

這樣根據頁面是否展示商品信息就能判斷出 admin 這個管理員在數據庫中的密碼是否爲 32 位。這樣就可以一步一步來驗證出管理員的密碼。現在有很多自動化的 SQL 注入軟件,可以用很短的時間就把管理員的數據查詢出來。

在 PHP 的項目裏要避免 SQL 注入需要兩個條件:

  1. 使用 Prepared Statement + 參數綁定
  2. 絕對不手動拼接 SQL

Prepared Statement 簡單來說就是把要執行的 SQL 與 SQL 裏的參數分開,還是以上面的查詢商品爲例,Prepared Statement 就是:

 select * from products where id = ?

然後再傳入參數:1 and 1 = 1,這個時候數據庫會嚴格地去查找對應 ID = 1 and 1 = 1 的商品,而不是把 and 1 = 1 當做查詢條件,所以即使 1 = 1 成立,數據庫仍然返回空。

在 Laravel 裏所有的 SQL 查詢都是 Prepared Statement 模式,因此只要我們的代碼中沒有出現類似下方的代碼,就不會存在 SQL 注入的風險:

$product = DB::select("select * from products where id = '".$_GET['id']."'");

2.XSS漏洞

XSS 是與 SQL 注入齊名的漏洞,也可以用一句話來描述其核心:將未經過濾的用戶輸入原樣輸出到網頁中。

例如用戶把以下內容作爲收貨地址提交:

 <script>alert(123)</script>

而如果我們在後臺原樣輸出這個收貨地址,就會觸發網頁 JS 代碼,彈出一個 123 的提示框。

例如在用戶輸入信息保存到數據庫中,並在之後輸出到了頁面中:

  • 用戶暱稱
  • 收貨地址的所有字段
  • 下單時的備註字段
  • 商品評價字段
  • 申請退款理由

在Laravel中要輸出文本有兩種方式:{{ $str }}{!! $str !!},前者等同於 echo htmlspecialchars($str) 而後者則是 echo $str,htmlspecialchars() 函數默認會把 <>&" 這個 4 個字符分別轉義成 <、&lgt;、& 和 ",因此我們只要保證我們一直在用 {{ }} 來輸出就沒有問題;

3.CSRF跨站請求僞造漏洞

CSRF 漏洞的危害程度不低於 XSS,但是遠沒有 XSS 那樣出名。一句話描述就是:利用用戶的身份認證信息在用戶當前已登錄的 Web 應用程序上執行非用戶本意的操作。

舉個例子,假如 一個網站 退出登錄的請求方式和路由是 Get /logout,那麼惡意用戶只要在 該網站中 的帖子裏插入一張圖片,圖片的 SRC 是 https://domain/logout,那麼任何訪問這個帖子的用戶都會被強制退出,因爲瀏覽器在請求這個 URL 之前並不知道這個 URL 是不是一張真的圖片,那麼就會帶着當前用戶的 Cookie 用 Get 方式去請求這個退出頁面,也就導致當前用戶被強制退出。

那麼是不是把請求方式改成 Post 就沒有問題了呢?確實無法通過圖片的方式來觸發,但是惡意用戶可以在其他站點構造一個頁面,內容如下:

<form action="https://domain/logout" method="post" id="form"></form>
<script>document.gentElementById('form').submit();</script>

然後惡意用戶誘導正常的用戶去訪問這個頁面(比如這個惡意用戶在 該網站 的頭條裏分享了這個頁面並取了一個很有誘惑的標題《教你如何實現升職加薪》,相信會有很多人訪問),那麼訪問了這個頁面的用戶就會被強制退出 。

如果一個銀行網站的轉賬功能有 CSRF 漏洞,那麼惡意用戶就可以通過 CSRF 漏洞來盜取其他用戶的資金。

根據上面所說的原理,不難發現要避免 CSRF 攻擊需要兩個條件:

  1. 敏感操作不能用 Get 請求方式;
  2. 對於非 Get 的請求方式,需要校驗請求中的 token 字段,這個字段值對每個用戶每次登錄都是不一樣的。

對於 Laravel 項目來說已經內置了 CSRF 的防禦手段,我們在寫前端表單時都需要寫一個 <input type="hidden" name="_token" value="{{ csrf_token() }}"> 來提交 CSRF Token,因此我們的項目不會有 CSRF 攻擊的風險。

發佈了14 篇原創文章 · 獲贊 20 · 訪問量 3352
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章