【问题标题】:Why CORS on Images with HTML Canvas?为什么使用 HTML Canvas 对图像进行 CORS?
【发布时间】:2016-05-03 09:28:49
【问题描述】:

最近,我花了一些时间研究 Web 开发中一个相当常见的问题的解决方案 - 我正在处理在透明背景上居中对齐的徽标,但必须在它们下方放置文本,然后看起来好像文本和图像之间的空白量从一页转移到另一页。经过一番研究,我发现我可以使用画布重新对齐左下角的图像,并且该解决方案运行良好......至少在我将解决方案集成到我们的代码库并发现它失败之前:

“无法从画布获取图像数据,因为画布已被跨域数据污染。” (说什么!?)

调查发现,有问题的代码位于以下函数的第一行:

getColumn: function (context, x, y, imageHeight) {
    var arr = context.getImageData(x, y, 1, imageHeight).data; //<-- CORS HATES THIS!
    return pvt.normalizeRGBArray(arr)
}

现在,我非常了解 CORS 标准是什么,并且我知道解决这个问题的方法。服务器首先需要支持 CORS。服务器可以设置 http 标头 access-control-allow-origin: "*",或者允许开发人员将图像的 crossDomain 属性设置为 "anonymous"/"use-credentials"。这一切都很好而且花花公子,除非你在一家大公司的前端工作,说服服务器领主改变任何与安全相关的事情是一件容易的事。

所以说真的,我的问题是画布上的图像发生此安全错误背后的逻辑是什么?他们是因为大声哭泣而令人讨厌的图像!可以下载它们,热链接到它们,在内存中使用它们,但是“哦,不!”不要以任何方式操纵它们,否则 CORS 会引发错误!

如果你问我,图像没有被污染,那就是这个脑筋急转弯的 CORS 标准。有人可以解释为什么会发生这种情况的逻辑吗?使用画布操作图像怎么可能存在安全问题?

【问题讨论】:

  • 作为曾经在一家广告公司工作过的人,你会惊讶于你可以在图片中加入什么样的东西。但是举个简单的例子,由于您尚未在两方之间建立信任,因此当您期待猫时,有人可能会向您发送色情内容。
  • 浏览器区别于仅仅显示数据(如针对 iframe 的异地指向表单)并允许 JS 深入检查数据。这是为了减少僵尸网络,防止深度链接图像更名等。真的,你是对的:大多数用途都是无害的,但规则就是规则,JS 不应该使用第三方资产。他们在无害的 CSSRules 上做同样的事情......
  • 在过去,溢出错误会让恶意代码运行,而图像处理是触发溢出的一种方式。今天的想法是 html5 画布既可以读取 img 元素 (drawImage) 又可以导出数据(getImageDatatoDataURL),因此它可以成为窃取机密信息的渠道。例如,如果您正在查看银行对账单的图像,恶意代码可以创建一个不引人注意的内存画布,将您的银行对账单图像绘制到画布上,序列化您的银行对账单像素并将序列化的像素数据发送到贼。你都没有注意到。
  • 是的,但是如果您可以将代码发送到银行的服务器,您可能已经拥有对它们的完全访问权限,因此您可以随心所欲。
  • @MikeC 哦,我明白了,要清楚,你的意思是因为恶意脚本的来源是 ,它不能检查 中的图像,所以如果银行不小心链接了一些国外的api,国外的api变成了恶意的,无法开始采集访客活动截图。访问本地图像的外部脚本是粗略的,但我不太清楚为什么当前位置托管的脚本无法访问外部图像。

标签: javascript html canvas cors


【解决方案1】:

这可以防止用户通过使用图像在未经许可的情况下从远程网站提取信息而暴露私人数据。

来源:MDN

【讨论】:

  • 感谢您的回答,但我认为这没有任何意义。用户仍然可以通过从另一个网站拉取图像来暴露私人数据,无论是否获得该网站的许可。它被称为跟踪像素。
  • @JoshuaDannemann 是的,但正如 markE 指出的那样,这不是提取数据的唯一方法。想象一下,您打开了一张银行对帐单,由于某种身份验证标头,只有您可以查看该对帐单,但随后第 3 方创建了一个画布元素并将该图像插入到画布中。然后,如果画布没有被标记为“污染”,他们可以将其转换为 blob 并将其发送回基地。
  • @JoshuaDannemann 不同的是,提供跟踪像素的站点是“攻击者”。从第 3 方站点提取跟踪像素没有多大意义;唯一可以读取跟踪数据的一方是您从中提取数据的站点。
  • @MikeC 哇哦!很好的例子!我没有考虑到这一点,但这就是我问这个问题的原因。我真的很想知道为什么/如何它可能是一个安全风险。
【解决方案2】:

抱歉,不是问题的答案,而是...

仅供参考:不是

服务器可以设置http header access-control-allow-origin: "*",或者允许开发者将图片的crossDomain属性设置为"anonymous"/"use-credentials"。

两者都是必需的

您需要设置crossOrigin,因为它会更改浏览器向服务器发出的图像请求。但是即使你没有设置它,并且服务器无论如何都会发送 CORS 标头,浏览器仍然不会让你使用图像,除非你设置了crossOrigin

你可以在这个例子中看到,两张图片,它们都从服务器接收 CORS 标头,但浏览器只允许一个工作。

loadAndDrawImage("https://i.imgur.com/fRdrkI1.jpg", "");
loadAndDrawImage("https://i.imgur.com/Vn68XJQ.jpg");

function loadAndDrawImage(url, crossOrigin) {
  const img = new Image();
  img.onload = function() { 
    log("For image", crossOrigin !== undefined ? "WITH" : "without", "crossOrigin set");
    try {
      const ctx = document.createElement("canvas").getContext("2d");
      ctx.drawImage(img, 0, 0);
      ctx.getImageData(0, 0, 1, 1);
      log("canvas still clean:", name);
    } catch (e) {
      error(name, ":", e);
    }
    log(" ");
  };  
  if (crossOrigin !== undefined) {
    img.crossOrigin = crossOrigin;
  }
  img.src = url;
}

function logImpl(color, ...args) {
  const elem = document.createElement("pre");
  elem.textContent = [...args].join(" ");
  elem.style.color = color;
  document.body.appendChild(elem);
}

function log(...args) {
  logImpl("green", ...args);
}

function error(...args) {
  logImpl("red", ...args);
}
pre { margin: 0; }
&lt;div&gt;check headers in devtools&lt;/div&gt;

如果您检查标头,您会看到他们都收到了 CORS 标头,但只有一个图像有效。

【讨论】:

    猜你喜欢
    • 2021-03-26
    • 1970-01-01
    • 1970-01-01
    • 2013-01-28
    • 1970-01-01
    • 2020-10-04
    • 1970-01-01
    • 2017-12-07
    • 2010-12-14
    相关资源
    最近更新 更多