從 0 開始入門 Chrome Ext 安全(一) -- 瞭解一個 Chrome Ext

者:LoRexxar'@知道創宇404實驗室
時間:2019年11月21日
系列文章:《從 0 開始入門 Chrome Ext 安全(二) -- 安全的 Chrome Ext》
English version: https://paper.seebug.org/1094/

在2019年初,微軟正式選擇了Chromium作爲默認瀏覽器,並放棄edge的發展。並在19年4月8日,Edge正式放出了基於Chromium開發的Edge Dev瀏覽器,並提供了兼容Chrome Ext的配套插件管理。再加上國內的大小國產瀏覽器大多都是基於Chromium開發的,Chrome的插件體系越來越影響着廣大的人羣。

在這種背景下,Chrome Ext的安全問題也應該受到應有的關注,《從0開始入門Chrome Ext安全》就會從最基礎的插件開發開始,逐步研究插件本身的惡意安全問題,惡意網頁如何利用插件漏洞攻擊瀏覽器等各種視角下的安全問題。

第一部分我們就主要來聊聊關於Chrome Ext的一些基礎。

獲取一個插件的代碼

Chrome Ext的存在模式類似於在瀏覽器層新加了一層解釋器,在我們訪問網頁的時候,插件會加載相應的html、js、css,並解釋執行。

所以Chrome Ext的代碼也就是html、js、css這類,那我們如何獲取插件的代碼呢?

當我們訪問擴展程序的頁面可以獲得相應的插件id

然後我們可以在https://chrome-extension-downloader.com/中下載相應的crx包。

把crx改名成zip之後解壓縮就可以了

manifest.json

在插件的代碼中,有一個重要的文件是manifest.json,在manifest.json中包含了整個插件的各種配置,在配置文件中,我們可以找到一個插件最重要的部分。

首先是比較重要的幾個字段

  • browser_action
    • 這個字段主要負責擴展圖標點擊後的彈出內容,一般爲popup.html
  • content_scripts
    • matches 代表scripts插入的時機,默認爲document_idle,代表頁面空閒時
    • js 代表插入的scripts文件路徑
    • run_at 定義了哪些頁面需要插入scripts
  • permissions
    • 這個字段定義了插件的權限,其中包括從瀏覽器tab、歷史紀錄、cookie、頁面數據等多個維度的權限定義
  • content_security_policy
    • 這個字段定義了插件頁面的CSP
    • 但這個字段不影響content_scripts裏的腳本
  • background
    • 這個字段定義插件的後臺頁面,這個頁面在默認設置下是在後臺持續運行的,只隨瀏覽器的開啓和關閉
    • persistent 定義了後臺頁面對應的路徑
    • page 定義了後臺的html頁面
    • scripts 當值爲false時,background的頁面不會在後臺一直運行

在開始Chrome插件的研究之前,除了manifest.json的配置以外,我們還需要了解一下圍繞chrome建立的插件結構。

Chrome Ext的主要展現方式

browserAction - 瀏覽器右上角

瀏覽器的右上角點擊觸發的就是mainfest.json中的browser_action

 "browser_action": {
      "default_icon": "img/header.jpg",
      "default_title": "LoRexxar Tools",
      "default_popup": "popup.html"
    },

其中頁面內容來自popup.html

pageAction

pageAction和browserAction類似,只不過其中的區別是,pageAction是在滿足一定的條件下才會觸發的插件,在不觸發的情況下會始終保持灰色。

contextMenus 右鍵菜單

通過在chrome中調用chrome.contextMenus這個API,我們可以定義在瀏覽器中的右鍵菜單。

當然,要控制這個api首先你必須申請控制contextMenus的權限。

{"permissions": ["contextMenus"]}

一般來說,這個api會在background中被定義,因爲background會一直在後臺加載。

chrome.contextMenus.create({
    title: "測試右鍵菜單",
    onclick: function(){alert('您點擊了右鍵菜單!');}
});

https://developer.chrome.com/extensions/contextMenus

override - 覆蓋頁面

chrome提供了override用來覆蓋chrome的一些特定頁面。其中包括歷史記錄、新標籤頁、書籤等...

"chrome_url_overrides":
{
    "newtab": "newtab.html",
    "history": "history.html",
    "bookmarks": "bookmarks.html"
}

比如Toby for Chrome就是一個覆蓋新標籤頁的插件

devtools - 開發者工具

chrome允許插件重構開發者工具,並且相應的操作。

插件中關於devtools的生命週期和F12打開的窗口時一致的,當F12關閉時,插件也會自動結束。

而在devtools頁面中,插件有權訪問一組特殊的API,這組API只有devtools頁面中可以訪問。

chrome.devtools.panels:面板相關;
chrome.devtools.inspectedWindow:獲取被審查窗口的有關信息;
chrome.devtools.network:獲取有關網絡請求的信息;
{
    // 只能指向一個HTML文件,不能是JS文件
    "devtools_page": "devtools.html"
}

https://developer.chrome.com/extensions/devtools

option - 選項

option代表着插件的設置頁面,當選中圖標之後右鍵選項可以進入這個頁面。

{
    "options_ui":
    {
        "page": "options.html",
        "chrome_style": true
    },
}

omnibox - 搜索建議

在chrome中,如果你在地址欄輸入非url時,會將內容自動傳到google搜索上。

omnibox就是提供了對於這個功能的魔改,我們可以通過設置關鍵字觸發插件,然後就可以在插件的幫助下完成搜索了。

{
    // 向地址欄註冊一個關鍵字以提供搜索建議,只能設置一個關鍵字
    "omnibox": { "keyword" : "go" },
}

這個功能通過chrome.omnibox這個api來定義。

notifications - 提醒

notifications代表右下角彈出的提示框

chrome.notifications.create(null, {
    type: 'basic',
    iconUrl: 'img/header.jpg',
    title: 'test',
    message: 'i found you!'
});

權限體系和api

在瞭解了各類型的插件的形式之後,還有一個比較重要的就是Chrome插件相關的權限體系和api。

Chrome發展到這個時代,其相關的權限體系劃分已經算是非常細緻了,具體的細節可以翻閱文檔。

https://developer.chrome.com/extensions/declare_permissions

拋開Chrome插件的多種表現形式不談,插件的功能主要集中在js的代碼裏,而js的部分主要可以劃分爲5種injected script、content-script、popup js、background js和devtools js.

  • injected script 是直接插入到頁面中的js,和普通的js一致,不能訪問任何擴展API.
  • content-script 只能訪問extension、runtime等幾個有限的API,也可以訪問dom.
  • popup js 可以訪問大部分API,除了devtools,支持跨域訪問
  • background js 可以訪問大部分API,除了devtools,支持跨域訪問
  • devtools js 只能訪問devtools、extension、runtime等部分API,可以訪問dom
JS 是否能訪問DOM 是否能訪問JS 是否可以跨域
injected script 可以訪問 可以訪問 不可以
content script 可以訪問 不可以 不可以
popup js 不可直接訪問 不可以 可以
background js 不可直接訪問 不可以 可以
devtools js 可以訪問 可以訪問 不可以

同樣的,針對這多種js,我們也需要特殊的方式進行調試

  • injected script: 直接F12就可以調試
  • content-script:在F12中console選擇相應的域

  • popup js: 在插件右鍵的列表中有審查彈出內容
  • background js: 需要在插件管理頁面點擊背景頁然後調試

通信方式

在前面介紹過各類js之後,我們提到一個重要的問題就是,在大部分的js中,都沒有給與訪問js的權限,包括其中比較關鍵的content script.

那麼插件怎麼和瀏覽器前臺以及相互之間進行通信呢?

- injected-script content-script popup-js background-js
injected-script - window.postMessage - -
content-script window.postMessage - chrome.runtime.sendMessage chrome.runtime.connect chrome.runtime.sendMessage chrome.runtime.connect
popup-js - chrome.tabs.sendMessage chrome.tabs.connect - chrome.extension. getBackgroundPage()
background-js - chrome.tabs.sendMessage chrome.tabs.connect chrome.extension.getViews -
devtools-js chrome.devtools.inspectedWindow.eval - chrome.runtime.sendMessage chrome.runtime.sendMessage

popup和background兩個域互相直接可以調用js並且訪問頁面的dom。

popup可以直接用chrome.extension.getBackgroundPage()獲取background頁面的對象,而background可以直接用chrome.extension.getViews({type:'popup'})獲取popup頁面的對象。

// background.js
function test()
{
    alert('test');
}

// popup.js
var bg = chrome.extension.getBackgroundPage();
bg.test(); // 訪問bg的函數
alert(bg.document.body.innerHTML); // 訪問bg的DOM

popup\background 和 content js

popup\background 和 content js之間溝通的方式主要依賴chrome.tabs.sendMessagechrome.runtime.onMessage.addListener這種有關事件監聽的交流方式。

發送方使用chrome.tabs.sendMessage,接收方使用chrome.runtime.onMessage.addListener監聽事件。

chrome.runtime.sendMessage({greeting: '發送方!'}, function(response) {
    console.log('接受:' + response);
});

接收方

chrome.runtime.onMessage.addListener(function(request, sender, sendResponse)
{
    console.log(request, sender, sendResponse);
    sendResponse('回覆:' + JSON.stringify(request));
});

injected script 和 content-script

由於injected script就相當於頁面內執行的js,所以它沒權限訪問chrome對象,所以他們直接的溝通方式主要是利用window.postMessage或者通過DOM事件來實現。

injected-script中:

window.postMessage({"test": 'test!'}, '*');

content script中:

window.addEventListener("message", function(e)
{
    console.log(e.data);
}, false);

popup\background 動態注入js

popup\background沒辦法直接訪問頁面DOM,但是可以通過chrome.tabs.executeScript來執行腳本,從而實現對頁面DOM的操作。

要注意這種操作要求必須有頁面權限

 "permissions": [
        "tabs", "http://*/*", "https://*/*"
    ],

js

// 動態執行JS代碼
chrome.tabs.executeScript(tabId, {code: 'document.body.style.backgroundColor="red"'});
// 動態執行JS文件
chrome.tabs.executeScript(tabId, {file: 'some-script.js'});

chrome.storage

chrome 插件還有專門的儲存位置,其中包括chrome.storage和chrome.storage.sync兩種,其中的區別是:

  • chrome.storage 針對插件全局,在插件各個位置保存的數據都會同步。
  • chrome.storage.sync 根據賬戶自動同步,不同的電腦登陸同一個賬戶都會同步。

插件想訪問這個api需要提前聲明storage權限。

總結

這篇文章主要描述了關於Chrome ext插件相關的許多入門知識,在談及Chrome ext的安全問題之前,我們可能需要先了解一些關於Chrome ext開發的問題。

在下一篇文章中,我們將會圍繞Chrome ext多個維度的安全問題進行探討,在現代瀏覽器體系中,Chrome ext到底可能會帶來什麼樣的安全問題。

re

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章