Yakim shu Hi, 這是我擴充腦內海馬體的地方。

[第十二週] 資訊安全 - 常見攻擊:XSS、SQL Injection

SQL Injection

以下是填帳號密碼的欄位,接收到開發者預期的正常輸入,再根據使用者的輸入去撈資料。

[ 正常輸入 ]

// 接收輸入的 SQL
SELECT * FROM users WHERE user='123' AND pwd='456';

而 SQL Injection 的本質就是把「 輸入的惡意資料」 變成「 程式的一部分 」

意思是駭客可以在輸入資料時,用一些奇怪的方式(惡意字串)竄改 SQL 語法,以偷取、假冒別人資料或刪除資料庫,例如以下輸入就可以成功登入別人帳號:

[ SQL Injection ]

// 接收輸入的 SQL
SELECT * FROM users HWERE user='' or 1=1 --' AND pwd =''; // => 永遠成立

解決方法: Prepare Statement

Prepare Statement 做的就是幫我們處理 SQL 跳脫這件事

步驟:

<?php
$stat = $conn->prepare("SELECT * FROM users WHERE username=? and pwd=?"); // => 把參數換成 ?
$stat->bind_param('ss', $username, $password); // => 替換成準備好的參數
$stat->execute(); // => 執行 query 語法
$result = $stat->getResult(); // => 執行結果
if ($result->num_rows > 0) {
    $row = $result->fetch_assoc(); // => 撈資料
}
?>

XSS ( Cross-Site-Scripting )

在別人網站執行 Javascript

跟 SQL Injection 一樣,本質也是讓使用者「 輸入的資料」 變成「 程式的一部分 」

利用 input 欄位可以輸入內容的特性,只要使用者輸入特別的 JS 語法,且網頁有 輸出此內容 的時候,就可以竄改網頁或竊取資料。

XSS 漏洞分為幾種類型:

儲存型 XSS ( Stored )

<input type="text" placeholder="輸入內容"> // 輸入欄位
<script>alert("XSS攻擊測試");</script> // 輸入惡意碼

<p>文字文字文字</p> // => 正常輸出
<p><script>alert("XSS攻擊測試");</script></p> // => 不正常輸出,且每個使用者都會中標

反射型 XSS ( Reflected )

如果網頁是在網址上用參數判斷狀態:login.php?status='登入失敗',且輸出錯誤訊息的方式是 直接把 value 印在網頁上,那麼只要把 value 換成 js 語法就可以攻擊成功

// 網頁程式
if (isset($_GET['status']) && !empty($_GET['status'])) {
    echo $_GET['status'];
}

// 網址列
http://www.example.com?status='新增成功'  => 印出新增成功
http://www.example.com?status=<script>alert(1)</script>  => 執行惡意程式

DOM 型 XSS


所以要是能注入 JS 能幹嘛?

最常見的是偷 cookie 資料:

<img src="" onerror="sendRequest('document.cookie')">
// src 讀取失敗,執行 onerror
// sendRequest() => 只是拿來說明可以送 request 到自己 Server,單純舉例用

要在哪裡檢查?輸入 or 輸出

檢查有無惡意碼的時機,可以分為在「輸入之前」跟「輸出之前」,一般建議是無論如何、輸出端的檢查一定要做!

輸入驗證:

因為 XSS 有太多漏洞可以鑽: HTML, JavaScript, CSS, XML, URL,要很完整對輸入做防範非常困難。

例如刪除所有 <script>onerror 及其他可以執行 JS 的字串,但設黑名單也不是一個理想的方式,因為有太多種變形可以換,白名單是比較推薦的作法,只是要寫的完整也是非常麻煩。

輸出驗證:

使用跳脫字元 escape

// php 跳脫字元的內建函式 htmlspecialchars
echo htmlspecialchars($str, ENT_QUOTES, 'utf-8')
// 輸出時需要 encoding
& --> &amp;
< --> &lt;
> --> &gt;
" --> &quot;
' --> &#x27;     
/ --> &#x2F;

參考資料:


常見疑問

應該在哪裡做 escape ?

哪些地方要做 prepare statement ?


( 以上內容大部分是 程式導師實驗計畫第三期 的學習筆記,如有錯誤歡迎糾正,非常感謝 🤓 )