trust(html)
描述
將 HTML 或 SVG 字串轉換為不經過轉義的 HTML 或 SVG。請勿在未經過濾的使用者輸入上使用 m.trust
。
在考慮使用 m.trust
之前,請務必先嘗試使用替代方法。
簽名式
vnode = m.trust(html)
參數 | 類型 | 是否必填 | 描述 |
---|---|---|---|
html | String | 是 | 包含 HTML 或 SVG 文字的字串 |
回傳值 | Vnode | 代表輸入字串的受信任 HTML vnode |
運作原理
預設情況下,Mithril.js 會轉義所有值,以防止一類稱為 XSS 注入 的安全問題。
var userContent = "<script>alert('evil')</script>";
var view = m('div', userContent);
m.render(document.body, view);
// equivalent HTML
// <div><script>alert('evil')</script></div>
但是,有時需要呈現富文本和格式標記。為了滿足這種需求,m.trust
會建立受信任的 HTML vnode,這些 vnode 會呈現為 HTML。
var view = m('div', [m.trust("<h1>Here's some <em>HTML</em></h1>")]);
m.render(document.body, view);
// equivalent HTML
// <div><h1>Here's some <em>HTML</em></h1></div>
受信任的 HTML vnode 是物件,而不是字串;因此,它們不能與常規字串串聯。
安全性考量
您必須過濾 m.trust
的輸入內容,以確保 HTML 字串中沒有使用者產生的惡意程式碼。如果您不過濾 HTML 字串,並將其標記為受信任,則 HTML 字串中的任何非同步 JavaScript 呼叫都可能被觸發,並以檢視頁面使用者的權限執行。
HTML 字串可能包含可執行程式碼的方式有很多種。注入安全攻擊最常見的方式是在 <img>
或 <iframe>
標籤中新增 onload
或 onerror
屬性,或是使用不平衡的引號 (例如 " onerror="alert(1)
) 在未過濾的字串插值中注入可執行上下文。
var data = {};
// 易受攻擊的 HTML 字串範例
var description =
"<img alt='" + data.title + "'> <span>" + data.description + '</span>';
// 利用 JavaScript 相關屬性進行攻擊
data.description = "<img onload='alert(1)'>";
// 使用不平衡的標籤進行攻擊
data.description = "</span><img onload='alert(1)'><span";
// 使用不平衡的引號進行攻擊
data.title = "' onerror='alert(1)";
// 使用不同的屬性進行攻擊
data.title = "' onmouseover='alert(1)";
// 不使用 JavaScript 的攻擊
data.description =
"<a href='https://evil.com/login-page-that-steals-passwords.html'>Click here to read more</a>";
建立惡意程式碼有無數種不明顯的方法,因此強烈建議您使用允許的 HTML 標籤、屬性和屬性值的白名單,而不是黑名單來過濾使用者輸入。還強烈建議您使用適當的 HTML 解析器,而不是使用正則表達式進行過濾,因為正則表達式極難測試所有邊緣情況。
不執行的腳本
即使有很多隱晦的方式可以使 HTML 字串執行 JavaScript,<script>
標籤在 HTML 字串中出現時,通常不會執行。
基於歷史因素,瀏覽器會忽略透過 innerHTML 插入到 DOM 的 <script>
標籤。它們這樣做是因為一旦元素準備就緒(因此具有可訪問的 innerHTML 屬性),如果腳本呼叫類似 document.write("</body>")
的內容,則渲染引擎無法回溯到解析階段。
對於來自 jQuery 的開發人員來說,這種瀏覽器行為可能看起來令人驚訝,因為 jQuery 實現了專門用於查找腳本標籤並在此場景中執行它們的程式碼。Mithril.js 遵循瀏覽器行為。如果需要 jQuery 行為,您應該考慮將程式碼移出 HTML 字串並移入 oncreate
生命週期函式,或使用 jQuery(或重新實現其腳本解析程式碼)。
避免信任 HTML
一般來說,除非您明確地呈現富文本並且沒有其他方法可以獲得您想要的結果,否則您應該避免使用 m.trust
。
// 避免
m('div', m.trust('hello world'));
// 優先
m('div', 'hello world');
避免盲目複製和貼上
常見的 m.trust
濫用方式是使用第三方服務,其教程包含要複製和貼上的 HTML 程式碼。在大多數情況下,應使用 vnode(通常透過 m()
實用程式)編寫 HTML。
以下是 Facebook 讚按鈕 的範例程式碼片段:
<!-- 載入 Facebook JavaScript SDK -->
<div id="fb-root"></div>
<script>
(function (d, s, id) {
var js,
fjs = d.getElementsByTagName(s)[0];
if (d.getElementById(id)) return;
js = d.createElement(s);
js.id = id;
js.src = '//connect.facebook.net/en_US/sdk.js#xfbml=1';
fjs.parentNode.insertBefore(js, fjs);
})(document, 'script', 'facebook-jssdk');
</script>
<!-- 您的讚按鈕程式碼 -->
<div
class="fb-like"
data-href="https://www.your-domain.com/your-page.html"
data-layout="standard"
data-action="like"
data-show-faces="true"
></div>
以下是如何將其重構為 Mithril.js 元件,以避免 m.trust
:
var FacebookLikeButton = {
oncreate: function () {
(function (d, s, id) {
var js,
fjs = d.getElementsByTagName(s)[0];
if (d.getElementById(id)) return;
js = d.createElement(s);
js.id = id;
js.src = '//connect.facebook.net/en_US/sdk.js#xfbml=1';
fjs.parentNode.insertBefore(js, fjs);
})(document, 'script', 'facebook-jssdk');
},
view: function () {
return [
m('#fb-root'),
m(
'.fb-like[data-href=https://www.your-domain.com/your-page.html][data-layout=standard][data-action=like][data-show-faces=true]'
),
];
},
};
上面的 Mithril.js 元件只是將腳本標籤的程式碼複製到 oncreate
鉤子中,並使用 Mithril.js 的 m()
語法宣告剩餘的 HTML 標籤。
避免 HTML 實體
常見的 m.trust
濫用方式是將其用於 HTML 實體。更好的方法是使用相應的 unicode 字元:
// 避免
m('h1', 'Coca-Cola', m.trust('™'));
// 優先
m('h1', 'Coca-Cola™');
可透過適用語言的鍵盤配置輸入帶重音符號的字元的 Unicode 字元。此外,還可以選擇記住鍵盤快捷鍵以產生常用符號 (例如,Windows 中的 Alt+0153
或 Mac 上的 Option+2
用於 ™ 符號)。另一種簡單的產生方式是簡單地從 unicode 字元表 複製並貼上所需的字元。另一種相關方法是輸入逸出的 Unicode 碼位 (例如,™ 符號的 "\u2122"
)。
所有能以 HTML 實體表示的字元都有 Unicode 對應項,包括不可見字元,例如
和 ­
等。
為了避免編碼問題,您應該將 JavaScript 檔案的檔案編碼設定為 UTF-8,並在主機 HTML 檔案中新增 <meta charset="utf-8">
meta 標籤。