iframe内联元素有白边原因_教你如何使用内联框架元素 IFrames 的沙箱属性提高安全性?
作者:Huup_We
轉發鏈接:https://mp.weixin.qq.com/s/21ydrXuinCtYiJdsynsTrA
前言
想要構建一個體驗豐富的網站,嵌入組件和內容幾乎是不可避免的,而這些組件和內容你是無法真正控制的。第三方組件可以提高用戶參與度并且在整個用戶體驗中起重要作用,且有時用戶自定義內容甚至比網站本地的內容更重要。我們不能放棄使用第三方組件和用戶自定義內容,但這兩種方法都增加了網站的風險。你嵌入的每一個組件 —— 廣告、社交媒體都可能含有惡意的攻擊:
內容安全政策 (CSP) 允許白名單中的可信源嵌入腳本和其他內容,以減少第三方組件和用戶自定義內容帶來的風險。這是正確且重要的一步,但需要注意的是,大多數 CSP 指令只有兩種情況:要么被允許,要么不被允許。有時會遇到這種矛盾的情況:我不確定內容的來源是否可 「信任」 ,但我想在瀏覽器中嵌入它。
最小特權
本質上,我們正在尋找一種只授予其完成工作所需的最小權限的機制。如果組件不 「需要」 彈出一個新窗口,就禁止訪問 window.open。如果組件不需要 Flash,就關閉對 Flash 插件的支持。當我們遵守 最小特權原則,關閉與功能不直接相關的權限,那就會很安全了。
iframe 元素是為這種解決方案構建良好框架的第一步。在 iframe 中加載不信任的組件時,它將提供應用程序與加載內容的分離:嵌入的內容不能訪問頁面的 DOM 或本地存儲的數據,也不能在頁面上任意位置繪圖;它的作用范圍僅限于被嵌入的元素。然而,這種分離并不是真正可靠的。被嵌入的頁面仍然有許多令人討厭或惡意的行為:比如自動播放的視頻、多余的插件和彈出窗口,而這些只是冰山一角。
iframe 元素的 「sandbox」 屬性 加強了對框架內容的限制。我們可以指示瀏覽器在低權限環境中加載特定框架的內容,只允許完成所需功能子集。
先去除,再校驗
Twitter 的 "Tweet" 按鈕是個很好的示例,它可以通過沙箱更安全地嵌入到站點中。Twitter 允許你 通過 iframe 嵌入按鈕,用以下代碼:
為了確定我們可以鎖定哪些內容,需要仔細檢查按鈕有哪些功能。被加載的 HTML 從 Twitter 的服務器上執行一系列 JavaScript 代碼,并在點擊時彈出一個有推文接口的窗口。同時,為了綁定推文到正確的賬號,接口需要訪問 Twitter 的 cookies,最后再提交包含推文內容的表單。
沙箱工作在白名單的基礎上。我們首先刪除所有可能的權限,然后通過向沙箱的配置中添加特定的標志,最后再重新啟用各個權限。對于 Twitter 組件,我們決定啟用 JavaScript、彈出窗口、表單提交和獲取 twitter.com 的 cookie 的權限。我們可以通過添加一個 sandbox 屬性到 iframe ,如下:
如上,我們已經為框架提供了它所需要的功能,瀏覽器將拒絕任何沒有被 sandbox 屬性授予的權限的訪問。
權限的力度控制
在上面的例子中可以看到一些可能的沙箱標志,現在讓我們更詳細地挖掘屬性的內部工作機制。
給定一個帶有空沙箱屬性的 iframe(
- JavaScript 將不會在框架文檔中執行。這不僅包括通過 script 標簽加載的 JavaScript,還包括內聯事件處理程序和 javascript: URLs。這還意味著 noscript 標簽中的內容會被顯示,就像用戶自己禁用了腳本一樣。
- 框架文檔被加載到唯一的源,這意味著所有同源檢查都將失敗;唯一的源不匹配其他源,甚至它們自己。在其他影響中,這意味著文檔不能訪問其他源的 cookie 或任何其他存儲機制( DOM 存儲、索引數據庫等)中的數據。
- 框架文檔不能創建新窗口或對話框(例如,通過 window.open 或 target="_blank")。
- 表單不能提交。
- 插件不會被加載。
- 框架文檔只能導航自己,而不能導航其頂級父文檔。設置 window.top.location 將拋出一個異常,點擊帶有 target="_top"的鏈接將不起作用。
- 自動觸發的功能(自動聚焦的表單元素、自動播放視頻等)將被阻止。
- 無法獲得 Pointer lock。
- 該框架文檔包含的 iframes 上忽略 seamless 屬性。
文件被加載到一個完全沙箱化的 iframe 中,帶來的風險非常小,但這是十分苛刻的。當然,這樣做也沒有太大的價值:對于一些靜態內容,可以使用一個完整的沙箱,但大多數情況下,可以放寬松一些。
除了插件之外,這些限制都可以通過向 sandbox 屬性的值添加一個標志來解除。沙箱化的文件是不能運行插件的,因為插件源碼未被沙箱化,除此之外其他的都一樣:
- 「allow-forms」 允許提交表單。
- 「allow-popups」 允許(window.open(), showModalDialog(), target="_blank" 等)彈出。
- 「allow-pointer-lock」 允許鼠標指針鎖住.
- 「allow-same-origin」 允許文檔維持源;加載自 https://example.com/ 的頁面將保留對該源數據的訪問權。
- 「allow-scripts」 允許 JavaScript 執行,也允許特性自動觸發(因為通過 JavaScript 實現這些特性是瑣碎的)。
- 「allow-top-navigation」 允許文檔通過導航頂級窗口跳出框架。
由此,我們可以準確地知道為什么我們在上面的 Twitter 例子中使用了一組特定的沙箱標志:
- 「allow-scripts」 是必須的,因為當頁面加載到框架時,需要執行 JavaScript 來處理用戶交互。
- 「allow-popups」 是必須的,因為按鈕需要在新窗口彈出表單。
- 「allow-forms」 是必須的,因為表單內容需要提交。
- 「allow-same-origin」 是必須的,否則 twitter.com 的 cookies 將無法訪問,用戶無法登錄發布表單。
需要注意的重要一點是,應用于框架的沙箱標記也適用于在沙箱中創建的任何窗口或框架。這意味著我們必須將 「allow-forms」 添加到框架的沙箱中,即使表單只存在于框架彈出的窗口中。
有了 sandbox 屬性后,組件只獲得所需的權限,插件、頂部導航和 pointer lock 等功能仍然被禁用。我們降低了嵌入組件的風險,且沒有產生不良影響。
分離權限
為了在低權限環境中運行不受信任的代碼,對第三方內容進行沙箱化是非常有益的。但對于你自己的代碼呢?你肯定相信自己,那為什么還擔心沙箱化呢?
試問一下:如果你的代碼不需要插件,為什么給它插件的權限?最好的情況,你不會用到這個權限;但最壞的情況,對于攻擊者來說,這給了攻擊者一個可乘之機。每個人的代碼都有 bug,幾乎每個應用程序都容易受到各式各樣的攻擊。代碼沙箱化意味著即使一個攻擊者成功的破壞你的應用,他們也不會被賦予對你應用程序 「完整」 的訪問權;他們只能夠做應用程序可以做的事情。雖然這樣已經很糟糕,但還沒到糟糕透頂的程度。
你可以通過將應用程序拆分成邏輯塊,并使用盡可能少的特權對每個塊進行沙箱化,以達到進一步減少危險的目的。這個方法在源碼中很常見:例如 Chrome,將自己分解為一個高權限的瀏覽器進程,用于訪問本地硬盤和網絡連接;以及許多低權限的呈現進程,用于負責解析不受信任的內容。屬于低權限的渲染器不需要接觸磁盤,瀏覽器會提供渲染頁面所需的所有信息。即使黑客找到了破壞渲染器的方法,也不會有什么進展,因為所有高權限訪問都必須通過瀏覽器的進程路由。攻擊者須在系統的不同部分找出漏洞,才可進行破壞,這樣做就大大降低了風險。
安全的沙箱:eval() 方法
通過沙箱和 postMessage API,這個模型可以成功的應用到 web 上。應用程序的各個部分可以放置在沙箱化的 iframe 中,父文檔可以通過發布消息和偵聽響應使各個部分之間通信。
Evalbox 可以將字符串解析成 JavaScript 代碼。而這就是你一直期待的。當然,這是一個相當危險的應用程序,因為允許任意的 JavaScript 執行意味著源提供的任何數據都是可獲取的。我們通過確保代碼在沙箱中執行來降低風險,從框架的內容開始,從內到外完成代碼:
Evalbox's Frame在框架內部,我們有一個最小的文檔,它通過連接到 window 對象的 message 事件來偵聽來自其父對象的消息。每當父進程對 iframe 的內容執行 postMessage 時,這個事件就會觸發,然后執行父進程希望我們執行的字符串。
在處理程序中,用父窗口獲取事件的 source 屬性。一旦我們完成工作,就用它發送結果。然后,將數據傳遞給 eval() 來完成繁重的工作。這個調用包括在 try 塊中,因為在沙箱化的 iframe 中禁止的操作經常會生成 DOM 異常;我們將捕獲它們并報告一個友好的錯誤消息。最后,我們將結果發布回父窗口。整個過程是很簡單的。
父類也同樣簡單。我們會創建一個小的 UI 層,代碼有一個 textarea,和一個可執行的 button,我們會通過一個只允許執行腳本的沙箱 iframe 嵌入到 frame.html:
eval() in a sandboxed frame.現在來寫一個方法執行吧。首先,利用 window.addEventListener 偵聽來自iframe 和 alert() 的響應。一個真正的應用程序應該簡潔明確:
window.addEventListener('message', function (e) { // iframe 的 sandbox 屬性值不為“allow-same-origin”時, // 嵌入內容的來源將被視為一個null而不是有效來源。 // 這意味著你必須小心那些通過 API 接收的數據。 // 這種情況下,你需要檢查源,并驗證輸入。 var frame = document.getElementById('sandboxed'); if (e.origin === "null" && e.source === frame.contentWindow) alert('Result: ' + e.data); });接著,我們在 按鈕 上掛載一個單擊事件。當用戶點擊時,我們會抓取 textarea 的內容,并將其傳遞到 iframe 中執行:
function evaluate() { var frame = document.getElementById('sandboxed'); var code = document.getElementById('code').value; // 注意,我們正發送信息給“*”,而不是特定源。 // iframe 的 sandbox 屬性值不為“allow-same-origin”時, // 發送的信息就沒有目標源,這就會導致一些不尋常的攻擊。 // 所以你必須要校驗你的輸出! frame.contentWindow.postMessage(code, '*');}document.getElementById('safe').addEventListener('click', evaluate);是不是很簡單?我們寫了一個簡單的評估 API,同時確保被評估的代碼不會訪問敏感信息,比如 cookie 或 DOM 存儲。同樣,被評估的代碼也不能加載插件,彈出新窗口,或者其他一些糟糕的惡意行為。
在這里檢查一下你自己的代碼:
- Evalbox Demo
- index.html
- frame.html
你可以把程序解構為單一用途的組件,然后對自己的代碼執行評估操作。就像上面代碼所示,每個組件都可以封裝在一個簡單的消息傳遞 API 中。高權限父窗口可以充當控制器和調度程序,將消息發送到每個模塊中,而模塊只擁有完成工作的最少特權。我們只要偵聽結果,并確保每個模塊只獲得所需的信息就可以了。
但是請注意,你需要非常小心的處理來自與父元素相同源的框架內容。如果 https://example.com/ 上的某個頁面構建了同源的另一個頁面(這個頁面的 sandbox 只包括 「allow-same-origin」 和 「allow-scripts」),那么被構建頁面的權限可以向上達到父頁面,并完全刪除沙箱屬性。
你該如何使用沙箱
你可以在各種瀏覽器中使用沙箱,例如 Firefox 17+、IE10+ 和 Chrome。也可以根據 最新的支持表 查看是否可以使用。在 iframes 中使用 sandbox 屬性,允許你授予 「僅」 保證內容正常運行的特權。超出了內容安全策略所能提供的安全范圍。
此外,沙箱非常強大,可以降低攻擊者巧妙利用你代碼中漏洞的風險。通過將單個應用程序分離到一組沙箱服務中,每個沙箱服務只負責一小塊自己的功能。這樣做攻擊者除了要破壞特定的構建內容,還要破壞它們的控制器。這樣做很困難,特別是因為控制器的作用域可以大大減少。如果你請求瀏覽器幫助你完成剩下的工作,那么你可以多做審核 「這種」 代碼的工作。
這并不是說沙盒是互聯網安全問題的完整解決方案。它提供了深度防御,但是除非你能夠控制用戶的客戶端,否則不要依賴于瀏覽器支持(如果你真的控制了比如企業環境這種的用戶客戶端,那是最理想的)。現在沙盒是被用來加強防御的另一層保護,但這不是能完全依賴的防御。盡管如此,我還是建議使用它。
進一步了解
你可以在各種瀏覽器中使用沙箱,例如 Firefox 17+、IE10+ 和 Chrome。也可以根據 最新的支持表 查看是否可以使用。在 iframes 中使用 sandbox 屬性,允許你授予 「僅」 保證內容正常運行的特權。這幫你大大減少了第三方內容風險,甚至超出了內容安全策略所能提供的安全范圍。
- "HTML5 應用中的權限分離" 是一篇有趣的文章,講述了一個小框架的設計,以及它在三個 HTML5 app 中的應用。
- 當沙箱結合兩個新的 iframe 屬性時,可以更加靈活:srcdoc 和 seamless。前者允許您用內容填充框架,而不需要 HTTP 請求的開銷,后者允許樣式應用到框架內容中。兩者目前瀏覽器的支持度不高(只有 Chrome 和 WebKit nightlies)。但這將是未來一個有趣的組合。例如,你可以通過以下代碼對一篇文章進行沙盒注釋:
推薦JavaScript經典實例學習資料文章
《細說前端開發UI公共組件的新認識「實踐」》
《細說DOM API中append和appendChild的三個不同點》
《細品淘系大佬講前端新人如何上王者「干貨」》
《一文帶你徹底解決背景跟隨彈窗滾動問題「干貨」》
《推薦常用的5款代碼比較工具「值得收藏」》
《Node.js實現將文字與圖片合成技巧》
《愛奇藝云剪輯Web端的技術實現》
《我再也不敢說我會寫前端 Button組件「實踐」》
《NodeX Component - 滴滴集團 Node.js 生態組件體系「實踐」》
《Node Buffers 完整指南》
《推薦18個webpack精美插件「干貨」》
《前端開發需要了解常用7種JavaScript設計模式》
《淺談瀏覽器架構、單線程js、事件循環、消息隊列、宏任務和微任務》
《了不起的 Webpack HMR 學習指南(上)「含源碼講解」》
《了不起的 Webpack HMR 學習指南(下)「含源碼講解」》
《10個打開了我新世界大門的 WebAPI(上)「實踐」》
《10個打開了我新世界大門的 WebAPI(中)「實踐」》
《10個打開了我新世界大門的 WebAPI(下)「實踐」》
《「圖文」ESLint 在中大型團隊的應用實踐》
《Deno是代碼的瀏覽器,你認同嗎?》
《前端存儲除了 localStorage 還有啥?》
《Javascript 多線程編程?的前世今生》
《微前端方案 qiankun(實踐及總結)》
《「圖文」V8 垃圾回收原來這么簡單?》
《Webpack 5模塊聯邦引發微前端的革命?》
《基于 Web 端的人臉識別身份驗證「實踐」》
《「前端進階」高性能渲染十萬條數據(時間分片)》
《「前端進階」高性能渲染十萬條數據(虛擬列表)》
《圖解 Promise 實現原理(一):基礎實現》
《圖解 Promise 實現原理(二):Promise 鏈式調用》
《圖解 Promise 實現原理(三):Promise 原型方法實現》
《圖解 Promise 實現原理(四):Promise 靜態方法實現》
《實踐教你從零構建前端 Lint 工作流「干貨」》
《高性能多級多選級聯組件開發「JS篇」》
《深入淺出講解Node.js CLI 工具最佳實戰》
《延遲加載圖像以提高Web網站性能的五種方法「實踐」》
《比較 JavaScript 對象的四種方式「實踐」》
《使用Service Worker讓你的 Web 應用如虎添翼(上)「干貨」》
《使用Service Worker讓你的 Web 應用如虎添翼(中)「干貨」》
《使用Service Worker讓你的 Web 應用如虎添翼(下)「干貨」》
《前端如何一次性處理10萬條數據「進階篇」》
《推薦三款正則可視化工具「JS篇」》
《如何讓用戶選擇是否離開當前頁面?「JS篇」》
《JavaScript開發人員更喜歡Deno的五大原因》
《僅用18行JavaScript實現一個倒數計時器》
《圖文細說JavaScript 的運行機制》
《一個輕量級 JavaScript 全文搜索庫,輕松實現站內離線搜索》
《推薦Web程序員常用的15個源代碼編輯器》
《10個實用的JS技巧「值得收藏」》
《細品269個JavaScript小函數,讓你少加班熬夜(一)「值得收藏」》
《細品269個JavaScript小函數,讓你少加班熬夜(二)「值得收藏」》
《細品269個JavaScript小函數,讓你少加班熬夜(三)「值得收藏」》
《細品269個JavaScript小函數,讓你少加班熬夜(四)「值得收藏」》
《細品269個JavaScript小函數,讓你少加班熬夜(五)「值得收藏」》
《細品269個JavaScript小函數,讓你少加班熬夜(六)「值得收藏」》
《深入JavaScript教你內存泄漏如何防范》
《手把手教你7個有趣的JavaScript 項目-上「附源碼」》
《手把手教你7個有趣的JavaScript 項目-下「附源碼」》
《JavaScript 使用 mediaDevices API 訪問攝像頭自拍》
《手把手教你前端代碼如何做錯誤上報「JS篇」》
《一文讓你徹底搞懂移動前端和Web 前端區別在哪里》
《63個JavaScript 正則大禮包「值得收藏」》
《提高你的 JavaScript 技能10 個問答題》
《JavaScript圖表庫的5個首選》
《一文徹底搞懂JavaScript 中Object.freeze與Object.seal的用法》
《可視化的 JS:動態圖演示 - 事件循環 Event Loop的過程》
《教你如何用動態規劃和貪心算法實現前端瀑布流布局「實踐」》
《可視化的 js:動態圖演示 Promises & Async/Await 的過程》
《原生JS封裝拖動驗證滑塊你會嗎?「實踐」》
《如何實現高性能的在線 PDF 預覽》
《細說使用字體庫加密數據-仿58同城》
《Node.js要完了嗎?》
《Pug 3.0.0正式發布,不再支持 Node.js 6/8》
《純JS手寫輪播圖(代碼邏輯清晰,通俗易懂)》
《JavaScript 20 年 中文版之創立標準》
《值得收藏的前端常用60余種工具方法「JS篇」》
《箭頭函數和常規函數之間的 5 個區別》
《通過發布/訂閱的設計模式搞懂 Node.js 核心模塊 Events》
《「前端篇」不再為正則煩惱》
《「速圍」Node.js V14.3.0 發布支持頂級 Await 和 REPL 增強功能》
《深入細品瀏覽器原理「流程圖」》
《JavaScript 已進入第三個時代,未來將何去何從?》
《前端上傳前預覽文件 image、text、json、video、audio「實踐」》
《深入細品 EventLoop 和瀏覽器渲染、幀動畫、空閑回調的關系》
《推薦13個有用的JavaScript數組技巧「值得收藏」》
《前端必備基礎知識:window.location 詳解》
《不要再依賴CommonJS了》
《犀牛書作者:最該忘記的JavaScript特性》
《36個工作中常用的JavaScript函數片段「值得收藏」》
《Node + H5 實現大文件分片上傳、斷點續傳》
《一文了解文件上傳全過程(1.8w字深度解析)「前端進階必備」》
《【實踐總結】關于小程序掙脫枷鎖實現批量上傳》
《手把手教你前端的各種文件上傳攻略和大文件斷點續傳》
《字節跳動面試官:請你實現一個大文件上傳和斷點續傳》
《談談前端關于文件上傳下載那些事【實踐】》
《手把手教你如何編寫一個前端圖片壓縮、方向糾正、預覽、上傳插件》
《最全的 JavaScript 模塊化方案和工具》
《「前端進階」JS中的內存管理》
《JavaScript正則深入以及10個非常有意思的正則實戰》
《前端面試者經常忽視的一道JavaScript 面試題》
《一行JS代碼實現一個簡單的模板字符串替換「實踐」》
《JS代碼是如何被壓縮的「前端高級進階」》
《前端開發規范:命名規范、html規范、css規范、js規范》
《【規范篇】前端團隊代碼規范最佳實踐》
《100個原生JavaScript代碼片段知識點詳細匯總【實踐】》
《關于前端174道 JavaScript知識點匯總(一)》
《關于前端174道 JavaScript知識點匯總(二)》
《關于前端174道 JavaScript知識點匯總(三)》
《幾個非常有意思的javascript知識點總結【實踐】》
《都2020年了,你還不會JavaScript 裝飾器?》
《JavaScript實現圖片合成下載》
《70個JavaScript知識點詳細總結(上)【實踐】》
《70個JavaScript知識點詳細總結(下)【實踐】》
《開源了一個 JavaScript 版敏感詞過濾庫》
《送你 43 道 JavaScript 面試題》
《3個很棒的小眾JavaScript庫,你值得擁有》
《手把手教你深入鞏固JavaScript知識體系【思維導圖】》
《推薦7個很棒的JavaScript產品步驟引導庫》
《Echa哥教你徹底弄懂 JavaScript 執行機制》
《一個合格的中級前端工程師需要掌握的 28 個 JavaScript 技巧》
《深入解析高頻項目中運用到的知識點匯總【JS篇】》
《JavaScript 工具函數大全【新】》
《從JavaScript中看設計模式(總結)》
《身份證號碼的正則表達式及驗證詳解(JavaScript,Regex)》
《瀏覽器中實現JavaScript計時器的4種創新方式》
《Three.js 動效方案》
《手把手教你常用的59個JS類方法》
《127個常用的JS代碼片段,每段代碼花30秒就能看懂-【上】》
《深入淺出講解 js 深拷貝 vs 淺拷貝》
《手把手教你JS開發H5游戲【消滅星星】》
《深入淺出講解JS中this/apply/call/bind巧妙用法【實踐】》
《手把手教你全方位解讀JS中this真正含義【實踐】》
《書到用時方恨少,一大波JS開發工具函數來了》
《干貨滿滿!如何優雅簡潔地實現時鐘翻牌器(支持JS/Vue/React)》
《手把手教你JS 異步編程六種方案【實踐】》
《讓你減少加班的15條高效JS技巧知識點匯總【實踐】》
《手把手教你JS開發H5游戲【黃金礦工】》
《手把手教你JS實現監控瀏覽器上下左右滾動》
《JS 經典實例知識點整理匯總【實踐】》
《2.6萬字JS干貨分享,帶你領略前端魅力【基礎篇】》
《2.6萬字JS干貨分享,帶你領略前端魅力【實踐篇】》
《簡單幾步讓你的 JS 寫得更漂亮》
《恭喜你獲得治療JS this的詳細藥方》
《談談前端關于文件上傳下載那些事【實踐】》
《面試中教你繞過關于 JavaScript 作用域的 5 個坑》
《Jquery插件(常用的插件庫)》
《【JS】如何防止重復發送ajax請求》
《JavaScript+Canvas實現自定義畫板》
《Continuation 在 JS 中的應用「前端篇」》
作者:Huup_We
轉發鏈接:https://mp.weixin.qq.com/s/21ydrXuinCtYiJdsynsTrA
總結
以上是生活随笔為你收集整理的iframe内联元素有白边原因_教你如何使用内联框架元素 IFrames 的沙箱属性提高安全性?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python写linux脚本_Linux
- 下一篇: 频谱仪使用方法图解_钳形电流表使用方法图