1. 程式人生 > 程式設計 >Web安全概覽

Web安全概覽

前言

介紹一下 Web 端相關的攻擊手法及原理,包括但不限於 前端 後端 運維

本文後端語言將使用PHP,因為經過對比,PHP作為後端程式碼演示,是最顯而易見的。

以及本文介紹的所有攻擊手法都將提供Docker 靶場,方便後續大家自行研究、測試。

此篇文章是由我之前寫的安全文章進行了部分彙總、優化及新增。如果大家比較感興趣,可以去Freebuf Black-Hole看我之前寫的文章。

前端

XSS

XSS本質就是在別人的瀏覽器裡執行你的JavaScript程式碼,其他都是一種輔助手段。

DOM XSS

利用JavaScript操作DOM的特性,來做到攻擊

經常出現的情況:前後端分離架構

很多開發者,都知道不到萬不得已不要使用eval

函式,不使用的原因其中一點就是不安全,但是難道不使用eval就不會有安全問題麼?答案是否定的。

見下面的程式碼:

<script>
  window.open(new URL(location.hash.slice(1)).href)
</script>複製程式碼

為了更好的說明,我這裡簡單的把作用說明一下:

假設當前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)。則會成功觸發漏洞。

Docker 靶場

後端

反射XSS

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>

Docker 靶場

儲存型XSS

在反射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) 此方法的編碼規則為:

& 編碼為 &amp;

" 編碼為 &quot;

' 編碼為 &#039;

< 編碼為 &lt;

> 編碼為 &gt;

那即使我們寫入了HTML標籤等程式碼,也會被轉碼,假如我們提交的內容為<script>alert(1)</script>那在資料庫的裡表現就會變成: &lt;script&gt;alert(1)&lt;/script&gt;

那難道沒有辦法繞過去麼?答案當然是可以。

可以看到,這段程式碼不止把內容入庫了,還把使用者的IP也入庫了。那問題就出現了,CLIENT-IPX_FORWARDED_FOR是使用者可控的。只需要安裝 ModHeader 這個瀏覽器外掛即可如圖:

Imgur

修改後,再去重新提交一次,就會發現已經成功入庫了,如圖:

Imgur

Docker 靶場

CSRF

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 or POST or cross-origin GET requests resulting from script 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

這裡沒有說的特別細,我補充了一下,大致意思是說,使用 GETPOST 進行表單提交時,亦或者使用一些 HTML 標籤引起的 GET 請求,如:aimg 等,基本上都會攜帶使用者憑據(Cookies)

Docker 靶場

SSRF

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,來訪問內網資源,因為訪問資源的是服務端本身,而服務端本身也是可以訪問同區域網的資源的。

Docker 靶場

JSON Hijacking

JSON Hijacking 其實本質和 CSRF 原理一樣

這裡的原理指的是,漏洞產生的原理一樣,還是因為標籤產生的請求,會攜帶使用者憑證

這個攻擊手法和 CSRF 最大的不同,就是 JSON HijackingCSRF 的基礎上,又利用了 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 規範中,如果使用者事先已經登陸過了,再開啟惡意攻擊者發的連結,那麼攻擊者就可以獲取一些本不應該獲取的敏感資訊。

Docker 靶場