介紹一下 Web
端相關的攻擊手法及原理,包括但不限於 前端
後端
運維
javascript
本文後端語言將使用PHP
,由於通過對比,PHP
做爲後端代碼演示,是最顯而易見的。php
以及本文介紹的全部攻擊手法都將提供Docker
靶場,方便後續你們自行研究、測試。html
此篇文章是由我以前寫的安全文章進行了部分彙總、優化及添加。若是你們比較感興趣,能夠去Freebuf Black-Hole看我以前寫的文章。前端
XSS
本質就是在別人的瀏覽器裏執行你的JavaScript
代碼,其餘都是一種輔助手段。java
利用JavaScript操做DOM的特性,來作到攻擊git
常常出現的狀況:先後端分離架構github
不少開發者,都知道不到萬不得已不要使用eval
函數,不使用的緣由其中一點就是不安全,可是難道不使用eval
就不會有安全問題麼?答案是否認的。web
見下面的代碼:sql
<script>
window.open(new URL(location.hash.slice(1)).href)
</script>複製代碼
爲了更好的說明,我這裏簡單的把做用說明一下:docker
假設當前url爲
http://baidu.com/#http://360.cn
,那麼location.hash.slice(1)
的結果就是http://360.cn
new URL(url).href
則是會對url進行解析,並取出解析後的url。若是你的url不知足它內部的判斷,則會報錯。
是否是以爲這段代碼沒什麼問題。畢竟有new URL()
這種瀏覽器內置函數幫咱們作了過濾。
OK,那咱們就要去攻破這個函數的判斷。下圖爲URL
接口規範中的列表:
咱們能夠看到hello:world
是符合規範的。並且hello:
正好又是JavaScript
裏的標記
,相似於C語言中的goto
。那咱們更改url爲: http://baidu.com/#javascript:alert(1)
。則會成功觸發漏洞。
DOM XSS
也屬於反射型 XSS
,通常而言統稱都叫反射 XSS
,只有當須要劃分比較細時,纔會分開來。
由於前/後端沒有作好相對應的過濾,致使的問題
常常出現的狀況:MVC架構
由於像MVC
這種架構,實際上是在後端語言中編寫前端代碼,在訪問url的時候,會先由後端根據請求去構造前端頁面,再返回前端源碼到瀏覽器端,而這個過程當中,若是出現了XSS漏洞,又由於後端參與其中,因此咱們通常認爲這是反射型XSS
。
見下面的 PHP 代碼:
<?php
// 關閉瀏覽器的XSS檢測機制
header("X-XSS-Protection: 0;");
$bg = $_GET['bg'];
if (empty($bg)) {
$bg = '999';
}
echo "<div style='width: 120px; height: 120px; background-color:#$bg'>我是一隻小方塊</div>";
?>複製代碼
能夠看到,這段代碼將會獲取url參數中的bg
來獲取背景顏色。乍一看,好像沒什麼問題。可是要知道其中$bg
是可控的。那咱們只須要把裏面的標籤閉合掉就行。見下面:
http://127.0.0.1:8082/?bg=123' onclick='alert(1)
上面的代碼放在bg
參數裏,那代碼就變成了
<div style='width: 120px; height: 120px; background-color:#123' onclick='alert(1)
'>我是一隻小方塊</div>
在反射XSS的基礎上,作了一步 入庫的操做
見下面的代碼:
// 獲取客戶端的IP地址
// 此段代碼來之:https://stackoverflow.com/questions/3003145/how-to-get-the-client-ip-address-in-php
$ipaddress = 'UNKNOWN';
$keys = array('HTTP_CLIENT_IP', 'HTTP_X_FORWARDED_FOR', 'REMOTE_ADDR');
foreach($keys as $k) {
if (isset($_SERVER[$k]) && !empty($_SERVER[$k])) {
$ipaddress = $_SERVER[$k];
break;
}
}
// 獲取內容,並對內容作編碼過濾
$content = htmlspecialchars($_POST['content'], ENT_QUOTES);
$sql = "INSERT INTO xss.message (content, ip) VALUES ('$content', '$ipaddress')";
$conn->query($sql);複製代碼
這段代碼看起來是沒有任何問題的,由於咱們已經對content
參數作了進一步的編碼過濾。
htmlspecialchars(string,ENT_QUOTES)
此方法的編碼規則爲:
&
編碼爲&
"
編碼爲"
'
編碼爲'
<
編碼爲<
>
編碼爲>
那即便咱們寫入了HTML標籤等代碼,也會被轉碼,假如咱們提交的內容爲<script>alert(1)</script>
那在數據庫的裏表現就會變成: <script>alert(1)</script>
那難道沒有辦法繞過去麼?答案固然是能夠。
能夠看到,這段代碼不止把內容入庫了,還把用戶的IP也入庫了。那問題就出現了,CLIENT-IP
、X_FORWARDED_FOR
是用戶可控的。只須要安裝 ModHeader 這個瀏覽器插件便可如圖:
修改後,再去從新提交一次,就會發現已經成功入庫了,如圖:
CSRF能夠理解爲是一種借刀殺人的手法,通常出如今表單提交裏。最多見的是出現的開源項目裏,好比各種CMS。
<form method="post" action="addAdminUser.php">
<div class="input-group">
<label for="username">要添加的管理員帳號: </label>
<input type="input" name="username">
</div>
<div class="input-group">
<label for="password">要添加的管理員密碼: </label>
<input type="password" name="password">
</div>
<div class="input-group">
<button type="submit">添加</button>
</div>
</form>複製代碼
見上面代碼,此代碼存在於管理員後臺裏。用於添加管理員帳號。而且 addAdminUser.php
裏是有對當前用戶的 Cookies
作了校驗,非管理員帳戶不能添加。
可是這個表單裏沒有 驗證碼
、Token
,以及 addAdminUser.php
裏沒有作 referer
來源校驗。
就會出現 CSRF
漏洞。
由於瀏覽器發現你請求了某個資源後,會自動把你未過時的 Cookies
加入到請求頭裏。也就是說,即便是在其餘網站裏,發送了添加管理員的請求,會自動把你登錄後的 Cookies
加入到請求裏,服務端會認爲是你本人觸發的(由於 Cookies
校驗成功)
至於爲何這裏 Cors
沒有起到做用,是由於這種方式,請求後是拿不到任何返回信息的,因此 Cors
並不會攔截。若是你使用 Ajax
來請求,是確定會被攔截掉,由於 Ajax
請求是能夠拿到返回信息,全部會被 Cors
攔截掉。
那除了 form
標籤,還有什麼方法能夠進行攻擊呢?在 w3c cors
規範中,有這麼一句話:
A simple cross-origin request has been defined as congruent with those which may be generated by currently deployed user agents that do not conform to this specification. Simple cross-origin requests generated outside this specification (such as cross-origin form submissions using
GET
orPOST
or cross-originGET
requests resulting fromscript
elements) typically include user credentials, so resources conforming to this specification must always be prepared to expect simple cross-origin requests with credentials.----詳情可見 w3c cors
這裏沒有說的特別細,我補充了一下,大體意思是說,使用 GET
或 POST
進行表單提交時,亦或者使用一些 HTML
標籤引發的 GET
請求,如:a
、img
等,基本上都會攜帶用戶憑據(Cookies)
SSRF
本質其實和 CSRF
相差不大。只是 CSRF
面向的是客戶端的用戶,而 SSRF
面向的是服務端自己。
這種漏洞通常出現於:會訪問並返回用戶可控的資源的功能上。
例如:在線查看網站源碼
、獲取用戶發連接的title
、在線翻譯網頁
等
<script>
// 根據url動態拼接url
function seeCode() {
const url = document.getElementsByTagName('input')[0].value;
location.href = location.origin + location.pathname + '?url=' + url
}
</script>
<input type="text" placeholder="請輸入要查看源代碼的網站 URL"/>
<button onclick="seeCode()">查看</button>
<?php
$url = $_GET['url'];
if ("" == trim($url)) {
return;
}
// 獲取內容
$websiteCode = file_get_contents($url);
// 轉碼後存入 textarea 標籤裏
echo "<textarea>".htmlspecialchars($websiteCode, ENT_QUOTES)."</textarea>";
?>複製代碼
能夠看到,這裏沒有對用戶的輸入作任何的過濾,致使用戶能夠直接輸入http://192.168.1.2
等url,來訪問內網資源,由於訪問資源的是服務端自己,而服務端自己也是能夠訪問同局域網的資源的。
JSON Hijacking
其實本質和 CSRF
原理同樣
這裏的原理指的是,漏洞產生的原理同樣,仍是由於標籤產生的請求,會攜帶用戶憑證
這個攻擊手法和 CSRF
最大的不一樣,就是 JSON Hijacking
在 CSRF
的基礎上,又利用了 JSONP
的特性
<?php
require 'utils.php';
// 用戶認證、並獲取用戶信息
$result = getUserInfo();
if (count($result) != 3) {
echo "";
exit();
}
$fnName = $_GET['callback'];
if ("" == trim($fnName)) {
echo "";
exit();
}
// 輸出爲: getInfo({"name": name, "balance": balance });
echo "$fnName({name: '$result[0]', balance: '$result[2]'})";
?>複製代碼
<script>
function getInfo(data) {
console.log(data); // {"name": name, "balance": balance}
}
</script>
<script src="./json.php?callback=getInfo"></script>複製代碼
若是有惡意攻擊者,寫了一個頁面,而且也在網頁里加入了<script src="http://xxx/json.php?callback=getInfo"></script>
根據上文提到的 w3c cors
規範中,若是用戶事先已經登錄過了,再打開惡意攻擊者發的連接,那麼攻擊者就能夠獲取一些本不該該獲取的敏感信息。