SQL Injection
SQL Injection 駭客的填字遊戲
意思是駭客可以在輸入資料時,用一些奇怪的方式(惡意字串)竄改 SQL 語法,以偷取、假冒別人資料或刪除資料庫,例如以下輸入就可以成功登入別人帳號:
- 登入時輸入
- 帳號: ‘ or 1=1 –
- 密碼: (甚至不用輸入)
// 接收輸入的 SQL
SELECT * FROM users HWERE user='' or 1=1 --' AND pwd =''; // => 永遠成立
- SQL 語法中的 -- : 代表註解,所以後面的條件就被忽略
- 因為條件多了 or 1=1,且 pwd 也因為註解被忽略掉,所以 WHERE 條件永遠成立,就可以成功登入帳號了。
- 照理來說會登入第一個篩選到的帳號
解決方法: Prepare Statement
Prepare Statement 做的就是幫我們處理 SQL 跳脫這件事
步驟:
- 把要放的參數都改成問號
- 其實就是 SQL query 換種寫法,拿到資料後的操作是差不多
- 要注意的是 bind_param() 的第一個參數,有幾個參數就要寫幾個字元,字元依照參數的資料類型而定
- string => s
- int => i
<?php
$stmt = $conn->prepare("SELECT * FROM users WHERE username=? and pwd=?"); // => 把參數換成 ?
$stmt->bind_param('ss', $username, $password); // => 替換成準備好的參數
$stmt->execute(); // => 執行 query 語法
$result = $stmt->getResult(); // => 執行結果
if ($result->num_rows > 0) {
$row = $result->fetch_assoc(); // => 撈資料
}
?>
XSS ( Cross-Site-Scripting )
跟 SQL Injection 一樣,本質也是讓使用者「 輸入的資料」 變成「 程式的一部分 」
利用 input 欄位可以輸入內容的特性,只要使用者輸入特別的 JS 語法,且網頁有 輸出此內容 的時候,就可以竄改網頁或竊取資料。
XSS 漏洞分為幾種類型:
儲存型 XSS ( Stored )
- 網址列看不出問題
- 最常見的例子就是網站留言板或是訊息,因為使用者可以留任何訊息。
- 存在 DB 裡,所以每個使用者打開都會看到被修改的內容
- 殺傷力最大
<input type="text" placeholder="輸入內容"> // 網站的輸入欄位
<p>文字文字文字</p> // => 理論上的正常輸出
<script>alert("XSS攻擊測試");</script> // 駭客輸入的惡意碼
<p><script>alert("XSS攻擊測試");</script></p> // => 駭客輸入後的不正常輸出
反射型 XSS ( Reflected )
- 把惡意程式藏在網址列裡,放在 GET 參數傳遞
- 必須誘導使用者點到假連結才有用
- 但網址列看起來會很可疑,可用短網址或特殊編碼魚目混珠
如果網頁是在網址上用參數判斷狀態: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
- 頁面上有使用到 .html() 或 .innerHTML() 的語法,就可能直接放 JS 語法
- 跟前兩種 XSS 不一樣,此漏洞要在前端檢查
- 最好都改成 .innerText()=> 只會輸出純文字
要在哪裡檢查?輸入 or 輸出
檢查有無惡意碼的時機,可以分為在「輸入之前」跟「輸出之前」,一般建議是無論如何、輸出端的檢查一定要做!
輸入驗證:
因為 XSS 有太多漏洞可以鑽: HTML, JavaScript, CSS, XML, URL,要很完整對輸入做防範非常困難。
例如刪除所有 <script>
、 onerror 及其他可以執行 JS 的字串,但設黑名單也不是一個理想的方式,因為有太多種變形可以換,白名單是比較推薦的作法,只是要寫的完整也是非常麻煩。
輸出驗證:
- 使用跳脫字元 escape
- 如果「 輸出內容 」使用者可以操作,絕對不能輸出原碼( 未經處理 )
- 把內容轉譯成純文字,而不是程式碼
// php 跳脫字元的內建函式 htmlspecialchars
echo htmlspecialchars($str, ENT_QUOTES, 'utf-8')
// 輸出時需要 encoding
& --> &
< --> <
> --> >
" --> "
' --> '
/ --> /