控制台显示有关内容安全策略的错误和大量失败的 GET 请求

IT技术 javascript google-chrome dom google-chrome-extension content-security-policy
2021-03-04 21:22:22

我实际上正在开发我的第一个 Chrome 扩展程序,即使它运行顺利,我也从get()我用来检索一些数据函数中得到了很多错误,以及一个关于代码安全性的恼人错误。

这是控制台日志屏幕截图控制台日志

下面是涉及的代码:

弹出窗口.html

<!doctype html>
<html>
<head>
    <title>NGI Little Helper - Subscribes</title>
    <link rel="stylesheet" href="popup.css">
    <!-- JavaScript and HTML must be in separate files for security. -->
    <script type="text/javascript" src="common/jquery.js"></script>
    <script type="text/javascript" src="popup.js"></script>
</head>

<body>
    <h1>Topics</h1>
    <div id="content">..:: Loading ::..</div>
</body>
</html>

弹出窗口.js

这个脚本开始制作$.get()一个远程网页。变量的内容data可以在这里找到

$.get("http://gaming.ngi.it/subscription.php?do=viewsubscription", function(data) {
    var TDs = $('td[id*="td_threadtitle_"]', data);
    $(document).ready(function() {
        $("#content").html("<br/>");
        $.each( TDs, function() {
            //Removes useless elements from the source
            $('img[src="images/misc/tag.png"]', this).remove();
            $('span', this).remove(); //$('span[class="smallfont"]', this).remove();
            $('div[class="smallfont"]', this).remove();
            $('img[src="images/buttons/firstnew.gif"]', this).attr('src', '/img/icons/comment.gif');
            $('a[style="font-weight:bold"]', this).removeAttr("style");
            //Modify the lenght of the strings
            if ($("a[id^='thread_title_']", this).text().length > 35) {
                $("a[id^='thread_title_']", this).text( $("a[id^='thread_title_']", this).text().substring(0, 30) + " [...]" );
            }
            //Modify the URL from relative to absolute and add the target="_newtab"
            $("a[id^='thread_']", this).attr('href', "http://gaming.ngi.it/"+ $("a[id^='thread_']", this).attr('href'));
            $("a[id^='thread_']", this).attr('target', "_newtab");
            //Send the HTML modified to the popup window
            $("#content").html($("#content").html() + $('div', this).wrap("<span></span>").parent().html() +"<br/>" );
        });
    });
});

在这里您可以找到所有 jquery 操作后的 HTML。

老实说,我无法理解为什么会显示这些错误,尤其是与安全相关的错误。我没有在 popup.html 中使用任何内联代码。

清单文件.json

{
    "name": "NGI Little Helper",
    "version": "0.8.5",
    "manifest_version": 2,
    "description": "Extension per gli Utenti del forum gaming.ngi.it",
    "options_page": "fancy-settings/source/index.html",
    "background": {
        "page": "background.html"
    },
    "icons": {
        "16": "img/logo16.png",
        "48": "img/logo48.png",
        "128": "img/logo128.png"
    },
    "content_scripts": [{
        "matches": ["*://gaming.ngi.it/*"],
        "js": ["common/jquery.js", "logo_changer/logo_change.js"],
        "run_at": "document_start"
    }],
    "browser_action": {
        "default_icon": "img/icon.png",
        "default_popup": "popup.html",
        "default_title": "Visualizza Subscriptions"
    },
    "permissions": [
        "*://gaming.ngi.it/*"
    ]
}

以下是一段 HTML 代码,在所有操作后将呈现到弹出窗口中。所有的div都与此类似,只是 url 发生了变化:

<div>

            <a href="http://gaming.ngi.it/showthread.php?goto=newpost&amp;t=555954" id="thread_gotonew_555954" target="_newtab"><img class="inlineimg" src="/img/icons/comment.gif" alt="Go to first new post" border="0"></a>




            <a href="http://gaming.ngi.it/showthread.php?goto=newpost&amp;t=555954" id="thread_title_555954" target="_newtab">[All Gamez] [Frozen Synapse] S [...]</a>

        </div>

如果需要,我可以提供完整的源代码。

1个回答

让我们从最简单的问题开始:

拒绝执行内联脚本,因为...

$('div', this)选择 a 中的所有<div>元素<td>您提供源代码中,可以找到以下事件处理程序:

<div class="smallfont">
    <span style="cursor:pointer" onclick="window.open('member.php?u=47995', '_self')" >K4raMong</span>
</div>

根据默认的内容安全策略,这是禁止的。要摆脱错误,只需在将其插入文档之前删除该属性:

element.removeAttribute('onclick'); // in jQuery: $element.removeAttr('onclick');

为什么要加载这些图像?我没有把它们放在文档中

在 jQuery/JavaScript 可以操作 DOM 之前,必须先解析它。在您的代码中,这项工作在var TDs = $(.., data). 线。这种解析大约等于:

var dummy = document.createElement('div'); // Container
dummy.innerHTML = data;

听说过预加载图像吗?这是缓存图像的有用功能,以便在需要时准备就绪。这可以使用(new Image).src='...';. 创建的<img>元素不必插入到文档中。

在您的情况下,这是不受欢迎的行为,因为在您的扩展程序中查找了这些图像。这是因为您的网页使用相对 URL而不是绝对URL使用相对 URL 时,资源的预期位置取决于当前文档的位置。

如何修复

千万不能使用jQuery由于您正在编写 Chrome 扩展程序,因此您无需担心跨浏览器兼容性。jQuery 使用该innerHTML技巧来解析 HTML,但失败了,正如我之前所展示的。

JavaScript 有DOMParser对象,从 Chrome 30 开始可以如下使用:

var doc = (new DOMParser).parseFromString(data, 'text/html');

您可以使用该responseType属性跳过从字符串到文档的手动转换,如下所示。

到达解决方案

如您所知,Chrome 扩展程序中可以进行跨站点请求,前提是 URL 已正确添加到permissions清单文件中部分。我们将使用 XMLHttpRequest 级别 2 中引入的一个特性,即responseType属性

// Fetching data
var xhr = new XMLHttpRequest();
xhr.open('GET', 'http://gaming.ngi.it/subscription.php?do=viewsubscription');
xhr.onload = function() {
    var doc = xhr.response;
    // Now, you can use jQuery, since the string has been parsed.
    ...
};
xhr.responseType = 'document'; // Chrome 18+
xhr.send();

您可以轻松地重写代码以使用原生 DOM 和 JavaScript 而不是 jQuery。大多数选择器引擎使用 jQuery,但大多数情况下,它也可以使用element.querySelectorAll. 使用 获取文档后var doc = xhr.response;,执行以下操作:

var TDs = doc.querySelectorAll('td[id*="td_threadtitle_"]');
var html = '';
[].forEach.call(TDs, function(td) {
    // etc, etc. Do your job
});

你看到了var html = '';吗?无论您是否使用 jQuery,这都是很好的做法。永远不要在循环中element.innerHTML += ...;甚至更糟$element.html($element.html() + ...);浏览器将很难一遍又一遍地渲染它,而您 - 作为用户 - 会注意到性能下降。

根据MDNDOMParser从 Chrome 30 开始使用 HTML。
2021-04-20 21:22:22
@Xan 更新答案。我仍然建议使用responseType='document'提到 DOMParser 只是为了展示如何解决使用 vanilla JS 而不是 jQuery 将字符串转换为 DOM 的一般问题。顺便说一下,我没有修复错误,我只是验证了错误已修复并更新了 MDN 上的 crbug 代码和文档。
2021-04-22 21:22:22
妈的,这太神奇了。刚刚遇到 jQuery 无法解析包含 <html>、<head> 和 <body> 标签的页面,这是 Chrome 的解决方案……Chrome 的 DOM 解析器如何不接受 text/html mime 类型?阿格。
2021-04-25 21:22:22
抱歉迟了回应。这个提示真的很有用:)
2021-05-02 21:22:22