• <noscript id="e0iig"><kbd id="e0iig"></kbd></noscript>
  • <td id="e0iig"></td>
  • <option id="e0iig"></option>
  • <noscript id="e0iig"><source id="e0iig"></source></noscript>
  • 前端跨域安全

    前言

    在Web安全中有一條很重要的同源策略,規定了前端安全的基本原則。前端開發中為了能夠在不同頁面中進行數據傳遞,設計了多種跨域的數據傳遞方式,但是數據跨域傳遞在方便了開發的同時也帶來了一些安全問題。

    一、同源策略

    1.1 定義

    同源是一種約定,它定義了從一個源加載的文檔或腳本如何與來自另一個源的資源進行交互,是一個用于隔離潛在惡意文件的重要安全機制,也是瀏覽器最核心最基本的安全功能。

    1.2 源的劃分

    如果兩個頁面的協議、端口、域都相同,則兩個頁面具有相同的源。如下表所示:

    注意:源的劃分中“域“并不是指資源對象所在的域,而是加載資源對象的域。例如a.com通過通過以下代碼

    <script src=http://b.com/b.js></script>

    加載了b.com上的b.js,但是b.js是運行在a.com上的,所以b.js的源是a.com而不是b.com。

    二、window.name

    Windows對象是瀏覽器的窗體,很多時候它不受同源策略的限制,利用這個對象可以實現跨域跨頁面傳遞數據。其中,Windows的name屬性是在一個窗體的生命周期內所有頁面所共享的,每個頁面對window.name都有讀寫的權限,window.name是持久存在一個窗口載入過的所有頁面中的,并不會因新頁面的載入而進行重置。

    比如如下代碼保存為list.html

    打開它之后程序會彈出window.name的值,然后跳轉到http://127.0.0.1/test.html,

    在test.html中的代碼為

    僅僅是一個彈窗,彈出來的window.name值域上一個頁面相同。

    這說明window.name成功的從一個域傳遞到了另外一個域。這個地方怎么進行漏洞利用呢?其中一個思路就是借助這個特性縮短XSS Payload的長度輔助XSS進行攻擊。比如在一個可控的頁面先構造好XSS Payload,如下所示

    <script type="text/javascript">
    window.name = "alert(document.cookie)";
    location.href = "http://www.xssedsite.com/xssed.php";
    </script>

    那么在XSS的漏洞站點只需執行以下代碼即可

    Eval(name);

    極其簡短。window.name的跨域本質上一種瀏覽器的特性,并不是安全漏洞,只是如果使用不當可能會有安全問題。在防御上,當在一個域去接收另一個域的window.name的值的時候要對其進行檢測,此時它相當于一個輸入點,而開發中要堅信任何輸入都是不可信的原則。

    三、postMessage

    postMessage允許每一個Window(包括當前窗口、彈出窗口、iframe等)對象往其他的窗口發送文本消息,從而實現跨窗口消息傳遞,且這個功能不受同源策略影響。postMessage語法如下:

    otherWindow.postMessage(message, targetOrigin, [transfer]);

    • otherWindow:其他窗口的一個引用,比如iframe的contentWindow屬性、執行window.open返回的窗口對象。
    • message:將要發送到其他 window的數據。
    • targetOrigin:通過窗口的origin屬性來指定哪些窗口能接收到消息事件,其值可以是字符串”*”(表示無限制)或者一個URI。
    • transfer :是一串和message 同時傳遞的 Transferable 對象

    發送窗口

    監聽窗口(也就是test.html所在的頁面)

    發送窗口負責發送消息,監聽窗口綁定message事件,監聽其他窗口的消息。這里存在兩個安全問題,一是對于監聽窗口來說,監聽窗口作為數據的接收方會將數據進行二次處理或顯示,如果直接使用獲得數據,就會如同SQL語句之前沒有過濾導致注入一樣,會導致一些不可控的后果(比如XSS),所以監聽窗口在防御上至少要做到以下兩點:

    1. 始終使用origin和source屬性驗證發件人的身份,防止攻擊者偽造發送源發送惡意數據;
    2. 要對接受到的message進行檢查,即使是許可的源也有可能發送錯誤或惡意數據的,在使用之前要檢查其合法性。

    二是對發送窗口來說,我們知道在發送數據之前需要聲明一個window對象(在發送窗口的代碼截圖中可以看到),它指定了我們的數據發送到哪一個窗口,這里很多人認為既然已經指定了窗口,targetOrigin就可以不用設置。但實際上這里存在一個問題,比如當window所指定的窗口因為某種原因發生了跳轉,前往了其他鏈接,如果不指定targetOrigin數據依然會被發送,這樣就可能導致信息泄露。所以發送窗口在防御上要設置一個確切的targetOrigin,而不是空值。

    四、Flash跨域

    4.1 簡介

    flash在跨域時唯一的限制策略就是crossdomain.xml文件,該文件限制了flash是否可以跨域讀寫數據以及允許從什么地方跨域讀寫數據。位于.a.com域中的SWF文件要訪問b.com的文件時,SWF首先會檢查b.com服務器目錄下是否有crossdomain.xml文件,如果沒有,則訪問不成功;若crossdomain.xml文件存在,且里邊設置了允許a.com域訪問,那么通信正常。所以要使Flash可以跨域傳輸數據,其關鍵就是crossdomain.xml。

    4.2 位置

    自flash 10以后,如有跨域訪問需求,必須在目標域的根目錄下放置crossdomain.xml文件,且該根目錄下的配置文件稱為“主策略文件”。若不存在主策略文件,則該域將禁止任何第三方域的flash跨域請求。主策略文件對全站的跨域訪問起控制作用。也可以單獨在某路徑下放置僅對該路徑及其子路徑生效的crossdomain.xml配置文件,這需要在flash的AS腳本中使用如下語句來加載該配置文件:

    Security.loadPolicyFile(“xxx.com/subdir/crossdomain.xml”)

    4.3 配置

    cross-domain-policycross-domain-policy元素是跨域策略文件crossdomain.xml的根元素。它只是一個策略定義的容器,沒有自己的屬性。子元素有:

    site-control(確認是否可以允許加載其他策略文件)
    allow-access-from(確認能夠讀取本域內容的flash文件來源域)
    allow-access-from-identity(有特定證書的來源跨域訪問本域上的資源)
    allow-http-request-headers-from(授權第三方域flash向本域發送用戶定義的http頭)

    4.4 漏洞利用

    Flash跨域進行信息讀取能否利用成功,主要還是看crossdomain.xml文件的配置,例如某站的crossdomain.xml文件

    這樣就可以進行跨域進行信息讀取,我們利用github上的項目:

    github.com/nccgroup/CrossSiteContentHijacking

    來進行漏洞利用,將源代碼下載下來進行本地部署,類型選擇Flash。(這里注意瀏覽器要支持Flash播放)

    輸入target點擊Retrieve Contents在下方可以看到成功讀取到個人信息頁面的內容。

    這個工具只能證明漏洞存在,真正的利用情境需要重新構造特定的惡意頁面。就像CSRF需要構造一個頁面誘導用戶點擊一樣,Flash跨域也需要構造類似的情景,不過傳統的CSRF是寫入型的攻擊,而利用Flash跨域可以進行讀取操作(為什么一定要和CSRF對比呢?因為CSRF的利用是需要用戶的登陸憑證的,用戶在登陸狀態下去訪問惡意頁面才能執行指定的操作,不過CSRF一般都是通過表單提交數據包,瀏覽器自動攜帶cookie,因為js是無法跨域的,這也是為什么CSRF只能進行寫入操作。Flash跨域有著同樣的道理,也需要用戶的登陸憑證(Cookie)才能訪問敏感頁面, 其中的不同點在于Flash腳本可以操作cookie發送表單,進而可以執行讀取操作。以上工具跨域獲得的數據是在測試賬號已經登陸的狀態下顯示的數據,本身模擬了一個受害者在登陸狀態下訪問惡意頁面的情景!)。其根本原因在于crossdomain.xml允許任意源的Flash發起請求,而Flash請求會攜帶Cookie,這樣就可以在用戶不知情的情景下利用用戶的登陸憑證訪問特定的敏感頁面,再通過Flash腳本中的代碼將獲取的敏感數據發送的攻擊者的服務器中。簡單的一句話就是可以將Flash跨域理解成讀取型CSRF。在防御上其實很簡單,在設置crossdomain.xml文件的時候僅配置信任的源,一定不要使用domain=”*”這樣的寫法

    五、CORS

    5.1 簡介

    CORS是一個W3C標準,全稱是”跨域資源共享”(Cross-origin resource sharing)。CORS需要瀏覽器和服務器同時支持,瀏覽器一旦發現AJAX請求跨源,就會自動添加一些附加的頭信息,有時還會多出一次附加的請求,但用戶不會有感覺。因此,實現CORS通信的關鍵是服務器。只要服務器實現了CORS接口,就可以跨源通信。

    5.2 簡單請求

    瀏覽器將CORS請求分成兩類:簡單請求(simple request)和非簡單請求(not-so-simple request)。若請求滿足所有下述條件,則該請求可視為“簡單請求”:

    使用下列HTTP方法之一:

    • GET
    • HEAD
    • POST

    HTTP頭信息不能超過以下幾種字段類型:

    • Accept
    • Accept-Language
    • Content-Language
    • Content-Type
    • DPR
    • Downlink
    • Save-Data
    • Viewport-Width
    • Width

    其中Content-Type的值只能是以下三種:

    • text/plain
    • multipart/form-data
    • application/x-www-form-urlencoded

    前面已經說過這些跨域請求與正常的請求在代碼上沒有太多的區別,瀏覽器會幫助我們完成CORS的檢驗過程,示例如下

    上述代碼執行之后會跨域訪問我的blog,這時瀏覽器會自動在http的頭中加上Origin字段,表明請求的來源。

    當返回包中攜帶了Access-Control-Allow-Origin字段,就表示完成了一次CORS訪問控制。

    本例中,服務端返回的 Access-Control-Allow-Origin: * 表明,該資源可以被任意外域訪問。如果服務端僅允許來自 http://127.0.0.1 的訪問,該首部字段的內容如下:

    Access-Control-Allow-Origin: http://127.0.0.1

    5.3 非簡單請求

    非簡單請求使用了不同的HTTP方法與參數,并且非簡單請求會在正式通信之前用OPTIONS方法發起一個“預檢請求”,該“預檢請求”會詢問服務器,當前網頁所在的域名是否在服務器的許可名單之中,以及可以使用哪些HTTP方法和頭信息字段。只有得到肯定答復,瀏覽器才會發出正式的請求,否則就報錯。當請求滿足下述任一條件時,即應首先發送“預檢請求”:

    使用下列HTTP方法之一:

    • PUT
    • DELETE
    • CONNECT
    • OPTIONS
    • TRACE
    • PATCH

    HTTP頭信息超過了以下幾種字段類型:

    • Accept
    • Accept-Language
    • Content-Language
    • Content-Type
    • DPR
    • Downlink
    • Save-Data
    • Viewport-Width
    • Width

    其中Content-Type的值以下三種之一:

    • text/plain
    • multipart/form-data
    • application/x-www-form-urlencoded

    如下代碼會首先發起一個“預檢請求”:

    上面的代碼使用 POST 請求發送一個 XML 文檔,該請求包含了一個自定義的請求首部字段(X-PINGOTHER: pingpong)。另外,該請求的 Content-Type 為 application/xml。因此,該請求需要首先發起“預檢請求”。

    返回結果

    瀏覽器會根據返回結果決定是否進行正式通信,上述數據包表明服務器允許任意的源通過POST、GET、OPTIONS方法攜帶X-PINGOTHER 與 Content-Type頭字段進行通信,響應的有效時間為 86400 秒,也就是 24 小時,如下是正式的通信數據包

    5.4 身份憑證

    CORS請求默認不發送Cookie和HTTP認證信息,想要發送身份憑證跨源請求中必須打開withCredentials屬性,如下所示

    上述代碼的XMLHttpRequest請求中在第14行打開了withCredentials屬性,從而瀏覽器會向服務器發送cookie。

    但是想要完成整個通信還需要服務器在頭信息中返回:

    Access-Control-Allow-Credentials: true

    以及Access-Control-Allow-Origin的值不得為“*”,必須指定明確的、與請求網頁一致的域名,否則瀏覽器會拒絕返回的數據,比如我們可以在burp的返回包中看到服務器返回的數據,但是瀏覽器卻沒有任何顯示

    身份憑證是CORS的跨域的條件之一,withCredentials打開后會降低攻擊者的攻擊成本。

    5.5 漏洞利用

    實際上,由于CORS的“身份憑證”的特性,使得很難繞過CORS進行跨域資源讀取。想要通過CORS獲取到敏感信息需要像CSRF那樣誘導用戶去訪問構造的惡意頁面,然后頁面中的js代碼發起跨域請求獲取信息,再將信息發送到攻擊者服務器,也可稱之為讀取型的CSRF。但是這里需要滿足CORS的幾個身份憑證的特性,否則只能獲取一些不需要身份憑證的價值不大的信息。

    同樣利用github上的項目:

    github.com/nccgroup/CrossSiteContentHijacking

    來進行漏洞利用

    Type選擇CORS Windows,Target Page選擇想要獲取信息的目標鏈接(我自己的Blog),如果需要發送POST數據在POST Data填上數據即可,然后點擊Retrieve Contents,頁面會跳轉到/ContentHijacking.html,可以看到跨域獲取的信息

    注意頭信息需要返回下面這兩個字段才能利用成功

    不過也不是完全這么雞肋,有些內網資源,不需要攜帶身份憑證但是外網不可訪問就可以利用這個方法嘗試讀取。這里舉個例子,比如某企業內部搭建了一個私有的git服務器(不需要登陸),開發人員在上面進行代碼管理。即使攻擊者獲取了git服務器的地址也無法訪問,如果這時存在CORS漏洞,攻擊者就可以構造特定的惡意頁面,誘導企業人員去訪問,企業人員會從內網發起這個請求并把結果返回到惡意頁面上,再通過惡意頁面的代碼將數據發送到攻擊者手中。

    另外我們知道再CSRF的防御中在敏感頁面設置Token(一個隨機序列,跟隨數據包發送,防止攻擊者猜測數據包請求參數,從而無法進行CSRF發攻擊)是常用的方法,一旦完成跨域訪問即可獲取頁面源代碼,那么這個隨機序列Token就可以被我們獲取了,從而可以構造CSRF所需要的請求參數,防御也就喪失了。

    在防御上,數據接口在配置返回的頭信息時要指定可信的Access-Control-Allow-Origin源,而不要設置成*,例如php中這樣的寫法是不安全的:

    header(“Access-Control-Allow-Origin: *”);

    六、總結

    跨域即是前端開發的一種訴求也是也是前端防御的一個要點,除了以上的幾種較為典型的跨域方法外還有其他的技巧,大家可以自己補充。它就像XSS、CSRF、釣魚等前端攻擊一樣,主要目標是正常用戶而不是服務器。跨域在攻擊中造成的危害并不像SQl注入、命令執行那樣巨大,其防御也不復雜,只需要在使用的時候采用了正確的方法即可避免這些問題。具體的點主要是:

    1. 配置文件:盡量使用白名單的思路設置允許跨域的源
    2. 代價編寫:不要為了方便開發簡化參數,嚴格按照說明文檔編寫
    3. 數據輸入點進行檢測
    4. 最小特權原則

    但是并不能忽視這類安全問題,畢竟任何一個突破口都有撕開整條安全防線的可能。

    七、聲明

    文章旨在普及網絡安全知識,提高小伙伴的安全意識的同時介紹常見漏洞的特征、挖掘技巧等。若讀者因此做出危害網絡安全的行為后果自負,與合天智匯及本人無關,特此聲明。

    版權聲明:本文為Fly_hps原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接和本聲明。
    本文鏈接:https://blog.csdn.net/Fly_hps/article/details/82733519

    智能推薦

    web前端跨域操作

    1.創建 若忘記有關命令 :點擊此處反向代理 2.偽靜態 定義:偽靜態是相對真實靜態來講的,通常我們為了增強搜索引擎的友好面,都將文章內容生成靜態頁面,但是有的朋友為了實時的顯示一些信息。或者還想運用動態腳本解決一些問題。不能用靜態的方式來展示網站內容。但是這就損失了對搜索引擎的友好面。怎么樣在兩者之間找個中間方法呢,這就產生了偽靜態技術。偽靜態技術是指展示出來的是以html一類的靜態頁面形式,但...

    前端webpack跨域配置

    vue.config.js配置 “/api/v1” 就是項目的baseUrl...

    數組刪除其中某個對象的方法

    數組刪除其中的對象或元素,在前端是比較常見的需求。 我現在比較常用的方法如下: 這種方法只適合刪除具有唯一標識的對象。 有沒有想要脫單的小伙伴,加入我們的脫單星球,認識更多優秀的小哥哥小姐姐 特此聲明,星球是免費的,但是創建星球的時候說是必須輸入金額,所以只能先私聊,我再加你免費加入!...

    圖床搭建以及圖床工具的使用

    為什么要用圖床和圖床工具? 比較下面三種md中的圖片url地址(均免費),你會使用哪一種? 選1?由于是本地路徑,文檔分享后給其他人打開后很可能顯示圖片加載失敗。 選2?雖然分享后可以顯示圖片,但能保證加載速度? 選3?我肯定選這種,即兼容2的瀏覽器訪問,又能保證訪問速度。 這樣就可以回答上面的問題了!保證瀏覽器訪問要用圖床,保證加載速度要用圖床工具,又不花錢想想就開心。 除此之外本篇博客還會講解...

    并發編程理論篇

    一、必備知識回顧 計算機又叫電腦,即通電的大腦,發明計算機是為了讓他通電之后能夠像人一樣去工作,并且它比人的工作效率更高,因為可以24小時不間斷 計算機五大組成部分 控制器 運算器 存儲器 輸入設備 輸出設備 計算機的核心真正干活的是CPU(控制器+運算器=中央處理器) 程序要想被計算機運行,它的代碼必須要先由硬盤讀到內存,之后cpu取指再執行 并發 看起來像同時運行的就可以稱之為并發 并行 真正...

    猜你喜歡

    Java LinkedHashMap

    Java LinkedHashMap 前言 Map是我們在實際使用過程中常用的集合,HashMap在Java的實際開發中出鏡率很高,它通過hash算法實現了高效的非線程安全的集合,它有一個缺點就是,用戶插入集合的數據時無序,在我們需要一些有序的map的時候,我們就需要引入另外一個集合:LinkedHashMap。 LinkedHashMap是一個有序的非線程安全的集合,它是HashMap的子類,基...

    Spark Streaming處理文件(本地文件以及hdfs上面的文件)

    標題介紹文件流之前先介紹一下Dstream 下面是來自官網一段的說明,Discretized Streams或DStream是Spark Streaming提供的基本抽象。它表示連續的數據流,可以是從源接收的輸入數據流,也可以是通過轉換輸入流生成的已處理數據流。在內部,DStream由一系列連續的RDD表示,這是Spark對不可變的分布式數據集的抽象(有關更多詳細信息,請參見Spark編程指南)。...

    《痞子衡嵌入式半月刊》 第 8 期

    痞子衡嵌入式半月刊: 第 8 期 這里分享嵌入式領域有用有趣的項目/工具以及一些熱點新聞,農歷年分二十四節氣,希望在每個交節之日準時發布一期。 本期刊是開源項目(GitHub: JayHeng/pzh-mcu-bi-weekly),歡迎提交 issue,投稿或推薦你知道的嵌入式那些事兒。 上期回顧 :《痞子衡嵌入式半月刊: 第 7 期》 嘮兩句 今天是小滿,小滿節氣意味著進入了大幅降水的雨季。痞子...

    (C++)二叉樹的線索化 / 線索二叉樹

    好久不見,朋友們!雖然我知道沒人看我的博客,但我還是想叨逼叨一下。啊,好久沒編程了(其實也就一周沒編),但你們知道,程序員一天不編程那能叫程序員么???雖然我不是程序員哈哈哈哈哈,但還是要有基本素養嘛。 繼續寫二叉樹,給自己立一個flag,就是這幾天要寫完之前沒做完的幾道題,和二叉樹紅黑樹各種樹之類的~~雖然有這個flag,但我還是很實誠地遵從自己的內心,買了一張明天的電影票,等我回來告訴你們好不...

    Linux內存管理:分頁機制

    《Linux內存管理:內存描述之內存節點node》 《Linux內存管理:內存描述之內存區域zone》 《Linux內存管理:內存描述之內存頁面page》 《Linux內存管理:內存描述之高端內存》 《Linux內存管理:分頁機制》 《內存管理:Linux Memory Management:MMU、段、分頁、PAE、Cache、TLB》 目錄 1 分頁機制 1.1 為什么使用多級頁表來完成映射 ...

    精品国产乱码久久久久久蜜桃不卡