網頁漏洞 XSS (Cross-Site-Scripting) 攻擊 (上) 基礎原理解說

  1. 1. 閱讀本文所需知識
  2. 2. 可能觸發 XSS 的先決條件
  3. 3. 一般使用者操作的HTML
  4. 4. 駭客操作的HTML
  5. 5. 反射型 XSS
  6. 6. 預存型 XSS
  7. 7. 總結

常常聽到有人說網站出現「XSS 漏洞」,那這所謂的 XSS 到底是什麼?其可怕之處又為何?以下,帶你淺談 XSS (跨站運行腳本) 原理及背後齷齪骯髒的技巧。



閱讀本文所需知識

在了解 XSS 之前,建議讀者最好先具備 HTML (超文字標記語言) 的基礎知識,否則可能會出現連範例都看不懂的窘境。


可能觸發 XSS 的先決條件

一般來說,XSS大多發生在「動態網頁」而不是「靜態網頁」,在此簡單解釋一下兩者差異,有興趣了解更深入者自行點選連結觀看。你可以這麼想像動態靜態網頁:

  • 伺服器 (Server)
    • 翻譯:就如同一個「櫃台服務人員」展示著自家的商品,而 用戶端 (Client),就是圍觀的顧客。
    • 原意:顧名思義為提供某特定服務的主機,而 用戶端 (Client) 則是使用這項服務的人。
  • 靜態網頁
    • 翻譯:「服務人員」照著公司的流程介紹自家商品,不與顧客有任何的對話跟交流 (即使顧客提問也不給予回應)。
    • 原意:伺服器 (Server)用戶端 (Client) 單向的展示服務,不接受任何來自 用戶端 (Client) 的請求 (連線請求例外)。
  • 動態網頁
    • 翻譯:「服務人員」在有限的範圍內,回答顧客的提問,或接受展示顧客所要求的內容。
    • 原意:伺服器 (Server) 具有接受及自定義處理封包請求的能力,能與 用戶端 (Client) 擁有雙向的互動。

常見的狀況是 HTML + PHP 或者 HTML + ASP 等,都是在有「網頁後端語言」並且該網站處理封包不當的情況下發生。


一般使用者操作的HTML

以下是一些簡單的HTML標籤,我們模擬輸入名稱的功能。
(特別聲明:此範例單純使用HTML運作,模擬的環境是假設有傳入後端的情況。)

按鈕按下時,會將「使用者輸入」欄位的值傳入後端 PHP,後端再將接收到的值顯示給使用者看,這麼一來就有了雙向互動,同時後台運作是直接抓取接收到的值來顯示,這意味著沒有過濾參數

後端環境雙向互動沒有過濾參數,再看看剛剛所說的觸發條件… 這是一個觸發的好環境啊!


  • 【HTML 頁面 使用者輸入】

    1
    2
    3
    4
    <!-- index.html -->
    <form action="name.php" method="POST">
    <input type="input" name="my_name" value="abc123">
    </form>
  • 【PHP 頁面 顯示傳入值】

    你的名字:

    1
    2
    3
    //name.php
    $name=$_POST['my_name']; //接收參數
    echo "<p>你的名字:".$name."</p>"; //沒過濾直接顯示

我們放大重點來討論,也就是說我們輸入什麼,就會反應在標籤上。
當使用者輸入「def456」則 HTML 標籤會長這樣

1
<p>def456</p>

輸入「ghi789

1
<p>ghi789</p>

注意!上述都是一般使用者的作法,中規中矩的按造設計者的想法去做。
但… 駭客會這麼乖嗎?


駭客操作的HTML

人家常說調皮的小孩是聰明的,有時候換個思路,調皮點,一個漏洞就這麼發現了。
設計者要求這樣做,我就該這樣做嗎?
正常輸入「abc123」如此標籤:

1
<p>abc123</p>

你可以發現標籤內包著我們的語法,包著的是<p>標籤及標籤結尾</p>
那如果今天我們輸入「abc123</p>」呢?

1
<p>abc123</p></p>

你會發現我們所輸入的</p>居然被解釋成標籤結尾了!?
這是否意味著我輸入什麼語法他就執行什麼語法?
那我們將輸入的參數稍做修改,改成具有影響力的語法!
輸入「abc123</p><script>alert(1)</script><p>

1
<p>abc123</p><script>alert(1)</script><p></p>

這則語法中的 alert(1) 是彈出警告視窗,其顯示內容為「1」
(Ps.「alert(1)」這是駭客們最常拿來測試 XSS 的語法)

隨意插入標籤?這麼一來我不就越權了嗎?


反射型 XSS

上述的 XSS 稱為「反射型」,其特點為「僅能自行觸發」,也就是我必須先向 伺服端 (Server) 發送請求,讓它回應給我一個因為該請求而觸發 XSS 的後果,這樣的漏洞不就太沒利用價值了嗎!?因為這意味著,你只能讓自己中招,而無法實質對 伺服端(Server) 產生傷害,或者危害到其他使用者權益,並且網頁將在重整後復原。整體來說該危害程度是許多管理者忽視且不願意花時間去處理的,但他們似乎忘了一個嚴重的問題… 社交工程 (Social Engineering)。(之後會撰寫一篇關於 社交工程 (Social Engineering) 的文章 點我連結)


預存型 XSS

該類型的 XSS 多半與 資料庫 (Database) 有著密切的關聯,上述的反射型是因為伺服端不會去儲存你的攻擊語法,所以不會發生該語法日後被再次觸發的問題,但現在要說的這種「預存型」就不同了。
預存型」顧名思義就是伺服器將語法給紀錄下來了,並且在某些需要輸出紀錄時的場合被再次觸發到。
舉個常見的例子 - 「貼文系統」。以下模擬一個簡易的貼文系統 HTML + PHP + MYSQL

1
2
3
4
5
6
<!-- index.html -->
<form action="post.php" method="POST">
<input type="text" name="title">
<input type="text" name="content">
<input type="submit">
</form>
1
2
3
4
5
6
7
8
9
10
11
12
// post.php
$title=trim($_POST['title']);
$content=trim($_POST['content']);
if(empty($title) || empty($content)) exit();

$connection=mysql_connect("localhost","root","password");
mysql_select_db("post");
$sql = "INSERT INTO `post` (`title`, `content`)
VALUES('$title', '$content');"
if($result = mysql_query($sql, $connection);){
echo "貼文成功!";
}

可以清楚看到 index.html 中所輸入的欄位分別有代表文章標題的「title」及代表文章內容的「content」,並且表單傳送至 post.php 中,在 post.php 裡將標題及內容寫入資料庫。
這時候假設貼文標題打上「abc213</p><script>alert(1)</script><p>」,內容隨意輸入「test」,正常來說此語法將會被成功寫入資料庫存放。

既然是貼文系統,照理來說會有個輸出文章的位置 (不然貼文就沒意義了):

1
2
3
4
5
6
7
8
9
10
// display.php
$connection=mysql_connect("localhost","root","password");
mysql_select_db("post");
$sql = "SELECT * FROM `post`;"
$result = mysql_query($sql, $connection);
if(!$result) exit();
while($row=mysql_fetch_row($result)){
echo $row['title'];
echo $row['content'];
}

就這樣,資料庫裡存放的 html 標籤被輸出並解釋成標籤作用了。
任何只要看得到這篇文章的人,畫面上就會彈出我們所植入的「alert(1)」。

我們僅僅是用「alert()」來測試 XSS 而已,這還算不上是什麼危害,但是有心人士會透過其他語法來達成非法目的,例如可以利用「document.cookie」來獲取你的 Cookie ,很多時候明明沒有在其他地方登入過,電腦也沒有中毒,帳號卻莫名被盜,有可能就是你中了 XSS 。


總結

上述這些這顯然不是設計師希望我們做的,標籤植入越權思路這就是 XSS 的基本原理。
透過與網頁所設計的功能互動,而將標籤透過巧思植入網頁並使其觸發。

而更進階的 XSS 技巧請看下一篇「網頁漏洞 XSS (Cross-Site-Scripting) 攻擊 (下) 進階思路解說」。