XHR使用CSP保护从iframe中保存文档

时间:2018-03-30 13:09:18

标签: javascript spring-boot iframe xmlhttprequest content-security-policy

设置

我们正在另一个(春季启动)项目的iframe中运行一个spring boot项目。 顶层项目包含一个集成视图,并控制iframe中显示的程序。到目前为止一切都很好。

顶层具有CSP保护,因此我们在iframe中可以显示的唯一内容是可信资源,它们如下:

"default-src 'self';" +
"style-src 'self';" +
"child-src 'self' " + getAllowedHosts() + " " + getDomain() + ";" +
"frame-src 'self' " + getAllowedHosts() + " " + getDomain() + ";" +
"img-src 'self' www.google-analytics.com;" +
"connect-src 'self' www.google-analytics.com " + getAllowedHosts() + ";" +
"font-src 'self';" +
"script-src 'self' www.googletagmanager.com www.google-analytics.com;";

iframe中的项目包含以下CSP设置:

"default-src 'self';" +
"style-src 'self';" +
"child-src 'self';" +
"frame-src 'self';" +
"img-src 'self' www.google-analytics.com;" +
"connect-src 'self' www.google-analytics.com;" +
"font-src 'self';" +
"object-src 'self' blob:;" +
"script-src 'self' www.googletagmanager.com www.google-analytics.com;";

问题。

我正在尝试下载生成的文件(excel文件,虽然类型无关紧要),并使用以下javascript代码:

/** 
 * @param url the url to post to
 * @param data formatted JSON string.
 */
 function download(url, data) {
    var xhr = new XMLHttpRequest();
    xhr.open('POST', url, true);
    xhr.responseType = 'blob';
    xhr.onload = function () {
        if (this.status === 200) {
            var disposition = xhr.getResponseHeader('Content-Disposition');
            var matches = /"([^"]*)"/.exec(disposition);
            var filename = (matches != null && matches[1] ? matches[1] : 'REI.xlsx');
            var type = xhr.getResponseHeader('Content-Type');

            var blob = new Blob([this.response], {type: type});
            if (typeof window.navigator.msSaveBlob !== 'undefined') {
                // IE workaround for "HTML7007:
                // One or more blob URLs were revoked by closing the blob for which they were created.
                // These URLs will no longer resolve as the data backing the URL has been freed."
                window.navigator.msSaveBlob(blob, filename);
                return;
            }
            // use HTML5 a[download] attribute to specify filename
            var a = document.createElement("a");
            a.href = window.URL.createObjectURL(blob);
            console.log(a.href);
            a.download = filename;
            document.body.appendChild(a);
            a.click();
            document.body.removeChild(a);
        }
    };
    xhr.setRequestHeader('Content-type', 'application/json');
    xhr.send(data);
}

当我在iframe环境之外打开我的页面时,文件下载得很好,但在iframe中我得到以下CSP错误:

Chrome:
Refused to frame '' because it violates the following Content Security Policy directive: "default-src *". Note that 'frame-src' was not explicitly set, so 'default-src' is used as a fallback.

Firefox:
Content Security Policy: The page’s settings blocked the loading of a resource at blob:https://localhost:8444/dd686147-ea7f-4711-86fd-715b4834e0ba (“default-src”).

1 个答案:

答案 0 :(得分:0)

最后,我选择通过动态表单提交,使用一个输入字段来保存字符串化的JSON数据。

结果下载功能:

/** 
 * @param url the url to post to
 * @param data formatted JSON string.
 */
function download(url, data) {
  var f = $('<form>')
    .prop('method', 'post')
    .prop('action', url)
    .css('display', 'none')
    .append($('<input type="text" name="data">').val(data));

  $('body').append(f);
  f.submit();
  f.remove();
}

然而,这要求我更改服务器端的帖子,因此它接受了JSON字符串而不是直接映射的POJO。