本篇主要會介紹常見的網路攻擊,像是 XSS、明文密碼竊取、SQL Injection 以及 CSRF 等,並以 PHP 示範防範的方法:
XSS attack
Problem
如果在畫面上呈現的內容是使用者可以控制的,使用者就可以輸入能被解析的 <script>
或 HTML 標籤來改變網站內容。例如在input
欄位裡面輸入 <script>alert('hack')</script>
。
Solution
利用 PHP 內建的 htmlspecialchars
來跳脫字元
htmlspecialchars($str, ENT_QUOTES);
Plain text password
Problem
明文密碼儲存在資料庫容易被偷走,就算使用加密也可以被駭客解析
Solution
把密碼存成 Hash雜湊,利用 PHP 內建的 hash 雜湊方法在資料庫儲存密碼,雜湊和上述所說的加密的差別在於,雜湊是不可還原的。
使用
password_hash()
將密碼存成雜湊$password = password_hash($_POST['password'], PASSWORD_DEFAULT);
利用
password_verify()
核對密碼$row = $result->fetch_assoc(); if (password_verify($password, $row['password'])) { $_SESSION['username'] = $username; header('Location: index.php'); } else { header('Location: login.php?errorCode=2'); }
加鹽
在儲存密碼時,使用雜湊不使用加密,是因為雜湊是不可逆的,無法逆向還原,而加密是可以解密的,只要加密的密鑰被掌握(為了驗證使用者登入,這個密鑰很有可能就存在 Server 上),就能夠輕鬆的還原出原來的密碼,此外,一旦有任何人類(可能是某個開發人員)知道這個密鑰,也就有可能被拿去做不法使用的風險。
使用雜湊演算法時,雖無法逆向還原,但不同的輸入也有可能生成相同的雜湊碼。也因為這個特性,一些簡單的雜湊方法,還是有可能被有心人士利用。所以如 MD5 等一些簡單的雜湊演算法是不夠安全的,像是 md5hashing 之類的網站上就提供超過 60 種雜湊演算法的破解服務。
為了加強雜湊的安全性,可以利用加鹽方法(Salting),在執行雜湊運算前先加入額外的字串,這樣雜湊碼即使被破解了,也無法得到真實的密碼,但更進一步地,如果駭客還是成功暴力破解了加鹽的字串,一旦成功破解第一組密碼,其他密碼也都暴露了,所以我們需要隨機生成的 Salt 來讓雜湊更安全。如 PHP 提供的 password_hash 方法可以隨機生成處理 Salt,所以即使是開發人員也不會知道每次的 Salt 是什麼,至此我們的密碼儲存又更安全了。
SQL injection
Problem
如果網頁上的 input 是有把值存在資料庫的動作時,駭客就可利用字串拼接的方式來改變原來的 SQL 意思,來改變內容,甚至進一步撈取資料。
隨便亂新增內容
INSERT INTO comments (nickname, content) values ('%s', '%s') ↓ //nickname: a, content: '), ('admin', 'hi' ↓ INSERT INTO comments (nickname, content) values ('a, content: '), ('admin', 'hi')
撈取密碼
INSERT INTO comments (nickname, content) values ('%s', '%s') ↓ // '), ('admin', (SELECT password FROM users WHERE id=40))# INSERT INTO comments (nickname, content) values ('%s', '), ('admin', (SELECT password FROM users WHERE id=40))# )
Solution
Prepared statement
/* $sql = sprintf( "select * from users where username='%s' and password='%s'", $username, $password ); $result = $conn->query($sql); */ $sql = "INSERT INTO nicolakacha_comments(nickname, content, client_ip) VALUES(?, ?, ?)"; $stmt = $conn->prepare($sql); $stmt->bind_param('sss', $nickname, $content); $result = $stmt->execute(); //拿 result 回來 $result = $stmt->get_result();
CSRF
Problem
Cross-site request forgery (CSRF) 是利用各種偽裝的方法偽造一個對目標網站合法的 request 在某個網站 action 內(可能點了一個連結,一張圖片等),因為使用者的瀏覽器自帶有其目標網站驗證身分用的 cookie,所以一旦這個釣魚 action 被觸發,就可以成功讓使用者在不知情的情況下發出 request 給目標網站。
Solution
檢查 Referer
利用 request header 內的 referer 欄位檢查是不是來自合法的 domain,若不是則 reject。
潛在問題:
- 瀏覽器可能不會帶 referer
- 使用者可能關閉自動帶 referer 的功能
- 判定不是合法的程式碼必須要保證沒有 bug
圖形驗證碼、簡訊驗證
每次都要驗證會很麻煩,但會降低使用者體驗
CSRF Token
在 form 裡面隨機產生一個 CSRF token,並將其存在 server 端的 session 裡,按下 submit 的時候就可比對兩者是否一致,若不一致則 reject。
潛在問題:
- 若 server 支援 cross origin 的 request,攻擊者可能會在他的頁面發起 request 來拿到這個 CSRF token
Double Submit Cookie 設置 CSRF Token
因為攻擊者的沒辦法讀寫目標網站的 cookie,而且也不能設置目標網站的 cookie,我們可以使用 Double Submit Cookie 的 CSRF Token,存一個 token 在 Client 端的 cookie 裡,每次 Client 發出 Request 時,就比 form 裡面的 POST 是否也帶有這個 token,就知道是不是真的使用者發出的 Request了。
潛在問題:
https://security.stackexchange.com/questions/59470/double-submit-cookies-vulnerabilities
參考資料:讓我們來談談 CSRF