天天看點

雲客Drupal源碼分析之網絡攻擊與防禦措施

本系列即将講解表單API,那是重要的使用者互動元件,在此前有必要講解一些系統安全相關的問題,為後續的表單API主題打下基礎。

同源政策:

同源政策是浏覽器的一個基本安全規則,限制了不同源的頁面間腳本的互相操作,當協定、域名、端口三者都相同時被認為是相同的源,否則是跨源,簡單點說就是一個頁面中的腳本想去操作或通路另外一個源中的頁面,是不允許的,關于同源政策網絡上有很多資料,這裡僅列出一些重要内容:

1、頁面中的連結,重定向和表單送出是不會受到同源政策限制的。

2、跨域資源的引入是可以的,比如這些标簽<script src="..."></script>,<img>,<link>,<iframe>等,但是js不能讀寫加載的内容。

3、<script>加載的javascript腳本,不論檔案是儲存在哪裡,不論是否同源,一旦被加載那麼就預設和目前文檔同源。

随着web發展,跨源需求越來越多,是以有了跨源通路的規則:

1、在伺服器端主要的有CORS(Cross-Origin Resource Sharing),W3C标準,見以下資料:

   https://www.w3.org/TR/cors/

   https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_COR

2、在浏覽器端有HTML5的postMessage方法

3、其他方法,如:降域 document.domain、JSONP跨域、window.name、location.hash、片段識别符、同源代理伺服器等

跨站腳本攻擊XSS(Cross Site Scripting):

在同源政策中講了<script>可以跨域引用腳本,引用後預設和文檔同源,腳本又有着強大的能力,這個是引起XSS攻擊的根本原因,我們來看一個列子說明它:

如果www.a.com/a.html頁面中通過以下代碼:

<script type="text/javascript" src="http://www.b.com/b.js"></script>

加載了其他源的js腳本,那麼b.js能夠通路a.html的cookie(注意:cookie往往包含會話id,那是使用者身份的根本依據),也能向www.a.com發送POST/GET等請求,且請求會附帶cookie資料,b.js還能向http://www.b.com 或其他源發送POST/GET等請求,但此時不會附帶a.html的cookie,不過b.js能夠以get或post的方式将a.html的cookie發送出去,假如網站過濾不嚴格,讓惡意攻擊者能夠送出script腳本标簽向頁面中插入js,那麼當其他使用者通路這個含有惡意js的頁面時,js就可以将使用者cookie發送給惡意攻擊者,如果cookie含有會話id,那麼惡意攻擊者就成功盜取了使用者的身份,這就是XSS攻擊。

明白了XSS原理,那麼在drupal中,表單送出時,切不可随便授予使用者可用任意HTML标簽的權限

在上面的列子中b.js雖然能夠向www.a.com以外的其他源發送請求,且請求也能真實到達伺服器,但伺服器傳回的資料浏覽器卻不允許b.js通路,因為這違反了同源政策,浏覽器控制台會出現提示,如下:

火狐:

已攔截跨源請求:同源政策禁止讀取位于 http://www.b.com/index.php 的遠端資源。(原因:CORS 頭缺少 'Access-Control-Allow-Origin')。

chrome:

XMLHttpRequest cannot load http://www.b.com/index.php. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://www.a.com' is therefore not allowed access.

Edge:

SEC7120: 在 Access-Control-Allow-Origin 标頭中未找到源 http://www.a.com。

如你所見,這些浏覽器均提到了“Access-Control-Allow-Origin”,這個就是同源政策一節中提到的CORS的作用,詳見其連結。

如果伺服器傳回的響應頭允許本域通路,那麼浏覽器将不會攔截資料,js可以順利通路到。

在伺服器端可以這樣設定以允許:

header("Access-Control-Allow-Origin: *");

多個域名之間用逗号分隔,表示對所示域名提供跨域通路權限,"*"表示允許所有域名的跨域通路。

CSRF(Cross-site request forgery)跨站請求僞造:

同樣我們以列子來說明,使用者在www.a.com/a.html登入,浏覽器将儲存有此頁面的cookie資料,這是登入憑證,然後使用者通路www.b.com/b.html,頁面b.html中的js有能力向www.a.com/a.html發送POST/GET等請求,此時a.html會收到請求但該請求不會附帶任何cookie資料,這沒有什麼問題,b站盜用不了使用者身份,但是換做表單就不一樣了,如果在b.html中構造送出到www.a.com/a.html的表單,然後讓使用者點選送出,那麼a.html收到的請求将會附帶使用者原來在www.a.com/a.html中的cookie資料,這意味着b站可以欺騙使用者,讓其并不知道這個表單的真實用途,誘使使用者點選向A站發出一個請求,該請求因為攜帶了合法身份(cookie資料包含了會話id)是以伺服器當做正常請求,執行相關事務,将這完全當做使用者的行為,然而實際情況卻是b站冒用了使用者的身份,執行了使用者不知情的操作,這就是CSRF,顧名思義垮站請求僞造。

由于同源政策的原因,攻擊者不能擷取到請求傳回的資料,是以CSRF針對的是能産生副作用的請求,按照HTTP協定規範GET請求不應當産生副作用,是以攻擊重點就是POST等請求上了,攻擊目标就是産生副作用,換句話說就是要在網站中做些改動。

CSRF攻擊是在攻擊者不能擷取使用者cookie的情況下發生的(得益于同源政策),如果能夠擷取使用者cookie,比如前文的XSS攻擊,那麼無需多此一舉,直接冒充使用者去操作就行了,是以要防止CSRF那麼隻需要基于cookie進行再次驗證表單即可,詳細的做法是要求表單送出時必須同時送出一個由cookie中資料運算得出的憑據,通常稱為token,如果表單是網站自身産生的那麼生成token沒有什麼問題,如果表單是攻擊者構造的,因為其不知道cookie是以無法算出token來,也就不能送出token了,進而網站拒絕執行請求。

在實際中token往往是一個隐藏的表單輸入,如:

<input name="form_token" value="yVYhnvKQD84L6vOVH7rOUcZA4XXxZIK_bFw1YNmGou4" type="hidden">

用以産生token的原資料稱為CSRF token seed(CSRF令牌種子),她未必儲存在cookie中,往往儲存在會話中,但會話基本是依賴cookie的,本質上是由cookie提供安全保護。

drupal跨站請求僞造令牌:

drupal為了防止CSRF攻擊,在表單中都設定了CSRF token ,她由該服務産生:

服務id:csrf_token

類:Drupal\Core\Access\CsrfTokenGenerator

該服務用以産生CSRF token 的種子由會話中繼資料包提供,擷取方法:

$metadataBag = \Drupal::service("session")->getMetadataBag();

見本系列會話進階篇,為了更加安全,在産生CSRF token 時還加入了系統私鑰、配置中的哈希鹽

這裡有個很贊的地方:Token是字元串,但Token在比較時,drupal卻沒有因為性能原因使用正常字元串比較,而是用特殊方式,要求在固定時間内比較完成,見:

\Drupal\Component\Utility\Crypt::hashEquals

這是為了避免時序攻擊,這種攻擊手法是很進階的,管中窺豹可見一斑,由此可見drupal在安全上是非常嚴謹的,不難看出為什麼美國白宮選擇她做官網。

常見網絡攻擊方式:

除以上的XSS和CSRF外,以下是雲客的一些經驗,如果要深入了解請自行查找相關資料

SQL注入攻擊:

這是最常見的攻擊,占比接近一半,這是由于sql語句中的使用者資料過濾不嚴,導緻使用者資料篡改查詢,不過在drupal中是使用PDO,大多數時候是使用查詢建構類,資料以參數傳入,這樣做除了提高性能之外還在底層自動過濾,安全風險減低很多,不過如果不是使用查詢建構類而是直接書寫sql查詢時仍然要靠使用者過濾資料

用戶端攻擊:

如果使用者浏覽器被安裝惡意插件那麼使用者請求可以被任意更改,是以永遠不要相信用戶端的資料,伺服器一定要嚴格檢查資料,惡意使用者還可以使用CURL或自行編寫程式直接通過http協定和伺服器通訊,是以背景開發人員不應該假想用戶端就是浏覽器,不能依靠浏覽器提供的安全機制。

網絡監聽:

在内網可以運作ARP抓包工具或者在擷取網關(路由器)權限後直接記錄使用者資料,這樣可以得到使用者cookie,冒用使用者身份,作為防範:伺服器程式可以檢查會話id具備的特征,如該會話來自的浏覽器代理标志等,為了防止監聽盡可能使用HTTPS協定

拒絕服務攻擊:

這類攻擊最難處理,攻擊者會在通路量很大的網站或多台主機上釋出<script>,<img>,<link>,<iframe>等内容,指向目标網站,或直接在殭屍電腦伺服器上發起對目标伺服器的大量通路,導緻目标伺服器超過負載無響應,防範是在伺服器層面進行來源分析,這類軟體有很多。

OS指令注入:

通過web程式非法執行作業系統命名,隻要能調用到Shell函數的地方就存在風險,比如MAIL函數等,如非必要應該在php中禁用調用作業系統指令或程式的函數,限制web程式的權限

HTTP首部注入攻擊:

是指在響應頭中插入換行,添加任意http首部或主體的一種攻擊,這是直接操作HTTP協定,可以重定向使用者到陷阱頁面,也叫響應截斷,如果需要使用者資料來設定響應頭,那麼需要嚴格檢查

目錄周遊:

如果使用者能送出路徑資訊需要小心“../”

遠端檔案包含漏洞:

在php中include或require包含遠端檔案功能最好關閉,不過在php5.2之後預設是關閉的

檔案名替換:

使用者上傳檔案時盡量使用與時間有關的哈希值儲存,避免惡意使用者構造檔案名替換正常使用者的檔案

web程式特征分析:

有些公開知名程式會有一定的特征,如帝國cms的管理頁或留言闆是以“e/”作為字首的,當惡意使用者發現某程式有安全漏洞時會在網際網路上大量掃描它的特征,然後知道哪些網站用了它,再發起攻擊,這種攻擊可以擷取大量殭屍電腦,是以我們應該屏蔽自己程式的特征,及時更新程式,在drupal中預設頁面或http頭都有drupal字樣。

錯誤提示:

在錯誤提示中不能給出對惡意使用者任何有價值的資訊,生産站點嚴禁調試模式。

會話固定:

網站不應該讓使用者指定會話id,且當使用者提權後(比如登入)應該重新生成會話id

dns攻擊:

   網站盡量選用技術可靠的dns服務商,一旦dns伺服器被入侵,網站和使用者基本是束手無策,輕者不能通路,重者攻擊者可以僞裝或代理目标網站,使用者在不知情的情況下洩露資訊

垃圾資訊:

這沒有什麼技術含量,但卻很危險,攻擊者經常釋出非法内容,借用監管之手足以讓站點關閉,目前的詞法分析還很初級,人工智能還挺遠,防範基本靠人工,是以建網站得用心管網站,資訊送出要設定驗證碼,防止機器人,注冊最好用手機驗證碼阻止不良使用者,這需要資金和精力,如果雲客想建一個站點,那麼這是首要考慮的攻擊問題。

補充:

1、js通過document.cookie就能讀取到cookie内容(往往包括會話id)

2、在cookie中設定httponly後(php中setcookie函數最後一個參數為真),js将讀取不到内容,該功能部分老舊浏覽器可能不支援,是以當不需要頁面通路cookie時為了安全盡量設定她

3、明白CSRF後,應該知道洩露網頁源代碼也是不夠安全的,那可能包含了CSRF token,如果CSRF token seed(CSRF令牌種子)沒有變化那麼CSRF token将保持不變

4、盡量采用HTTPS,在非加密的http協定中cookie以明文傳輸,通過網絡監聽可以盜用使用者的網站身份

5、在系統開發時重要場合應該要求輸入原密碼,比如修改密碼等,作為身份盜用的補救措施

我是雲客,【雲遊天下,做客四方】,聯系方式見首頁,歡迎轉載,但須注明出處

繼續閱讀