从 Chrome 扩展执行跨源请求时存在 XMLHTTPRequest 漏洞?
XMLHTTPRequest vulnerabilities when doing cross origin requests from a Chrome extension?
您可以使用 Chrome 扩展程序进行跨源请求。我用这个创建了 fiddle 的测试 Chrome 扩展。只需单击一个按钮,它就会从站点获取特定页面中的所有代码。
我只需要页面中的数据(只是一些文本和数字),然后将其显示在扩展程序的选项页面中。
我提取此数据的方式是遍历响应中的文档(请求的 response
或 responseXML
属性)。例如,我使用 querySelectorAll
来获取一堆元素,然后我将它们的所有 textContent
属性放在一个数组中,然后我将数组中的每个元素放在一个 <ul>
中DOM 的扩展页面。
最后,在我从站点请求特定页面后,我将响应文档存储在我的 localStorage
中(只会存储最后请求的页面,覆盖之前存储的页面)。我通过存储响应元素的 outerHTML
(通过 document.documentElement.outerHTML
)来执行此操作。然后当我刷新扩展页面时,我使用 DOMParser
和 parseFromString
将其转换回文档。转回文档后,又发生了上一段的事情(DOM数据的遍历和提取)。
有任何潜在的安全问题吗?
MDN 是这样说的:
"Processing a responseText property containing an HTML document If you
use XMLHttpRequest to get the content of a remote HTML webpage, the
responseText property is a string containing the raw HTML. This could
prove difficult to manipulate and analyze. There are three primary
ways to analyze and parse this raw HTML string:
- Use the XMLHttpRequest.responseXML property as covered in the article
https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/HTML_in_XMLHttpRequest
HTML in XMLHttpRequest. Inject the content into the body of a document
fragment via fragment.body.innerHTML and traverse the DOM of the
fragment.
RegExp can be used if you always know the content of the
HTML responseText beforehand. You might want to remove line breaks, if
you use RegExp to scan with regard to linebreaks. However, this method
is a "last resort" since if the HTML code changes slightly, the method
will likely fail."
我用的是第一种方法
此页面讨论处理响应的危险和安全方法(尽管这里讨论的是 responseText,而不是从响应或 responseXML 获得的 html 文档):
https://developer.chrome.com/apps/xhr
总结:
// 1. WARNING! Might be evaluating an evil script!
var resp = eval("(" + xhr.responseText + ")");
// 2. WARNING! Might be injecting a malicious script!
document.getElementById("resp").innerHTML = xhr.responseText;
// 3. JSON.parse does not evaluate the attacker's scripts.
var resp = JSON.parse(xhr.responseText);
// 4. innerText does not let the attacker inject HTML elements.
document.getElementById("resp").innerText = xhr.responseText;
这里唯一的问题是第 2 个问题。我使用 innerHTML 在 <ul>
中使用响应文档中的数据创建了一个 <li>
。现在,我知道这个站点,但我想我可以将其更改为不使用 innerHTML。
安全API/properties:
textContent
或 innerText
绝对安全
responseXML
是安全的,参见 step 5 in XHR specification:
scripting support disabled on received bytes
DOMParser
API 同样安全。
可能不安全:
innerHTML
不会 运行 <script>
元素,参见 (HTML5 spec):
When inserted using the innerHTML and outerHTML attributes, they do not execute at all.
但它会 运行 事件处理程序属性中的内联代码,例如 <img src="x" onerror="alert(1)">
,尽管通常这不会 运行 由于默认的 CSP [=27] =] 在扩展页面中,但许多作者需要放宽 CSP。
即使您没有放宽默认 CSP 并想在主文档中使用原始的外部 html,您也需要将 <style>
和 <link>
元素作为那些可以更改主页外观,删除 on
属性,以及 <script>
元素(只是为了保持一致性)。或者将 HTML 放在 iframe with sandbox
属性中。
还有 Mozilla 的政策需要考虑:
If your project is one that will undergo any form of security review, using innerHTML most likely will result in your code being rejected. For example, if you use innerHTML in a browser extension and submit the extension to addons.mozilla.org, it will not pass the automated review process.
您可以使用 Chrome 扩展程序进行跨源请求。我用这个创建了 fiddle 的测试 Chrome 扩展。只需单击一个按钮,它就会从站点获取特定页面中的所有代码。
我只需要页面中的数据(只是一些文本和数字),然后将其显示在扩展程序的选项页面中。
我提取此数据的方式是遍历响应中的文档(请求的 response
或 responseXML
属性)。例如,我使用 querySelectorAll
来获取一堆元素,然后我将它们的所有 textContent
属性放在一个数组中,然后我将数组中的每个元素放在一个 <ul>
中DOM 的扩展页面。
最后,在我从站点请求特定页面后,我将响应文档存储在我的 localStorage
中(只会存储最后请求的页面,覆盖之前存储的页面)。我通过存储响应元素的 outerHTML
(通过 document.documentElement.outerHTML
)来执行此操作。然后当我刷新扩展页面时,我使用 DOMParser
和 parseFromString
将其转换回文档。转回文档后,又发生了上一段的事情(DOM数据的遍历和提取)。
有任何潜在的安全问题吗?
MDN 是这样说的:
"Processing a responseText property containing an HTML document If you use XMLHttpRequest to get the content of a remote HTML webpage, the responseText property is a string containing the raw HTML. This could prove difficult to manipulate and analyze. There are three primary ways to analyze and parse this raw HTML string:
- Use the XMLHttpRequest.responseXML property as covered in the article https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/HTML_in_XMLHttpRequest
HTML in XMLHttpRequest. Inject the content into the body of a document fragment via fragment.body.innerHTML and traverse the DOM of the fragment.
RegExp can be used if you always know the content of the HTML responseText beforehand. You might want to remove line breaks, if you use RegExp to scan with regard to linebreaks. However, this method is a "last resort" since if the HTML code changes slightly, the method will likely fail."
我用的是第一种方法
此页面讨论处理响应的危险和安全方法(尽管这里讨论的是 responseText,而不是从响应或 responseXML 获得的 html 文档): https://developer.chrome.com/apps/xhr
总结:
// 1. WARNING! Might be evaluating an evil script!
var resp = eval("(" + xhr.responseText + ")");
// 2. WARNING! Might be injecting a malicious script!
document.getElementById("resp").innerHTML = xhr.responseText;
// 3. JSON.parse does not evaluate the attacker's scripts.
var resp = JSON.parse(xhr.responseText);
// 4. innerText does not let the attacker inject HTML elements.
document.getElementById("resp").innerText = xhr.responseText;
这里唯一的问题是第 2 个问题。我使用 innerHTML 在 <ul>
中使用响应文档中的数据创建了一个 <li>
。现在,我知道这个站点,但我想我可以将其更改为不使用 innerHTML。
安全API/properties:
textContent
或innerText
绝对安全responseXML
是安全的,参见 step 5 in XHR specification:scripting support disabled on received bytes
DOMParser
API 同样安全。
可能不安全:
innerHTML
不会 运行<script>
元素,参见 (HTML5 spec):When inserted using the innerHTML and outerHTML attributes, they do not execute at all.
但它会 运行 事件处理程序属性中的内联代码,例如
<img src="x" onerror="alert(1)">
,尽管通常这不会 运行 由于默认的 CSP [=27] =] 在扩展页面中,但许多作者需要放宽 CSP。即使您没有放宽默认 CSP 并想在主文档中使用原始的外部 html,您也需要将
<style>
和<link>
元素作为那些可以更改主页外观,删除on
属性,以及<script>
元素(只是为了保持一致性)。或者将 HTML 放在 iframe withsandbox
属性中。还有 Mozilla 的政策需要考虑:
If your project is one that will undergo any form of security review, using innerHTML most likely will result in your code being rejected. For example, if you use innerHTML in a browser extension and submit the extension to addons.mozilla.org, it will not pass the automated review process.