多个子域上图像数据的内联编码

发布于 2024-12-18 13:10:11 字数 992 浏览 0 评论 0 原文

我试图用图像中包含的 Base64 编码数据替换网页中的所有 img 标签。

表示为的图像:

<img src="http://a.example.com" />

将更改为:

<img src="data:image/png;base64,iVBORw0KGg..." />

该网页包含来自多个子域的图像,例如

<img src="http://a.example.com" />
<img src="http://b.example.com" />

在单个子域上我可以使用:

var images = document.getElementsByTagName('img');
for(var i=0; i<images.length; i++){
 var img = new Image();
 img.src = images[i].src;
 // Create canvas tag to represent img
 var canvas = document.createElement("canvas"); 
 canvas.width = img.width; 
 canvas.height = img.height;
 var context = canvas.getContext("2d");
 context.drawImage(img,0,0);

 img.src = canvas.toDataURL("image/png");
 $(images[i]).replaceWith(img);
}

但是,当图像位于 HTML 之外的子域中时页面,我得到:

Uncaught Error: SECURITY_ERR: DOM Exception 18

在控制台中。如何在页面上执行此操作以将所有图像引用与其各自的编码数据转换?

I am attempting to replace all img tags in a webpage with the base64 encoded data contained in the image.

An image that is represented as:

<img src="http://a.example.com" />

would be changed to:

<img src="data:image/png;base64,iVBORw0KGg..." />

The webpage contains images from multiple sub-domains, e.g.

<img src="http://a.example.com" />
<img src="http://b.example.com" />

On a single sub-domain I can use:

var images = document.getElementsByTagName('img');
for(var i=0; i<images.length; i++){
 var img = new Image();
 img.src = images[i].src;
 // Create canvas tag to represent img
 var canvas = document.createElement("canvas"); 
 canvas.width = img.width; 
 canvas.height = img.height;
 var context = canvas.getContext("2d");
 context.drawImage(img,0,0);

 img.src = canvas.toDataURL("image/png");
 $(images[i]).replaceWith(img);
}

however, when the images are in a sub-domain other than that of the HTML page, I get:

Uncaught Error: SECURITY_ERR: DOM Exception 18

in the console. How do I perform this operation on a page to convert all image references with their respective encoded data?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

春花秋月 2024-12-25 13:10:11

您违反了规范的法律,该法律规定,如果您将 drawImage 与与画布文档来源不同的图像一起使用,则 orgin-clean标志设置为 false。从那时起,您将无法使用toDataURL。该规范关于此事的完整内容是 此处。

这种安全措施的原因是为了防止所谓的信息泄漏。要了解为什么这是不好的,请考虑以下假设情况:

假设您位于工作网络上,因此您可以通过浏览器访问内部私人公司网站和您的(私人!)硬盘驱动器。私人网站可能类似于 www.internal.myCompany.com,并且您的硬盘驱动器可以通过 file:///C:/SomeOfMyPhotos/ 之类的 URL 进行访问。

现在假设您访问了一个带有隐藏画布的网站,并且在浏览该网站时,该画布不断调用 drawImage() 到该画布上,并猜测可能存在 URL。这些网址类似于私有子域上的图像:

www.internal.myCompany.com/secret/secret-plans.jpg

或硬盘驱动器上的图像:

file:// /C:/SomeOfMyPhotos/thatEmbarassingPhoto.png

恶意网站会不断尝试不同的私有 URL 组合,直到找到一个实际上是文件的 URL。然后它会将其绘制到画布上。然后它会从画布获取imageData并将其发送到服务器。

瞧!他们在未经您同意的情况下窃取了您的秘密计划和令人尴尬的照片。

现在我们知道,上述情况的可能性不大:毕竟,秘密计划几乎都是PNG格式,而尴尬的照片几乎都是JPG格式。但事实是,上述情况可能会发生,因此安全影响必须考虑到这一点。

You are violating the laws of the spec which state that if you use drawImage with an image that is not of the same origin as that of the canvas's document then the orgin-clean flag is set to false. From then onwards you are not allowed to use toDataURL. The spec's full words on the matter are here.

The reason for this security is to prevent something called information leakage. To see why this is bad, consider the following hypothetical situation:

Say you are on a work network and so you have access to internal, private company sites and your (private!) hard-drive from your browser. The private sites might be something like www.internal.myCompany.com and your hard drive would be accessible from urls like file:///C:/SomeOfMyPhotos/.

Now suppose you visited a website with a hidden canvas and while you were browsing the site that canvas was constantly calling drawImage() onto that canvas with urls that it was guessing might exist. These urls would be things like an image on the private subdomain:

www.internal.myCompany.com/secret/secret-plans.jpg

Or an image on your hard drive:

file:///C:/SomeOfMyPhotos/thatEmbarassingPhoto.png

The malicious site would keep trying different combinations of private-to-you urls until it found one that was actually a file. Then it would draw it to the canvas. Then it would get the imageData from the canvas and send it off to the server.

Voila! They have stolen your secret plans and your embarassing photos, much without your consent.

Now we know that the above scenario is not very probable: After all, secret plans are almost always in PNG format whereas embarassing photos are nearly always in JPG format. But it stands that situations like the above could happen and so the security implications must take this into account.

北陌 2024-12-25 13:10:11

如果画布上绘制了来自其他域的图像,安全沙箱将不允许您在画布上调用 toDataURL。我不明白确切的逻辑,但它的存在是为了阻止你这样做。

The security sandbox will not let you call toDataURL on a canvas if it has had an image from another domain drawn on it. The exact logic escapes me, but it exists to prevent you from doing exactly this.

请远离我 2024-12-25 13:10:11

通常,您无法从其他域读取图像数据。它违反了跨源资源共享 (CORS) 安全模型。也就是说,您可以通过让每个子域使用 HTTP 访问控制来解决此问题header (这是一个 示例,其中 node.js) 以及设置

最终,服务器和客户端都必须选择绕过图像的 CORS 安全性。

另一种解决方法需要使用名为 $.getImageData 的 jquery 插件。在幕后,该插件使用名为 img-to-jsonJSONP 来解决安全问题。下面是如何使用 img-to-json 的具体示例:

"//img-to-json.appspot.com/?url=" + escape(img_url) + "&callback=" + callback

基本上,该服务需要两个参数:您正在下载的图像的 URL(需要进行 URL 转义),以及您要在下载时执行的回调的名称图像加载完成。回调通过图像的 数据 url 版本以及一些元数据传递,例如图像的高度和宽度。

另请注意,上面的 URL 是 协议相关 URL 的示例(即它以 // 开头),这意味着它可以在 httphttps 页面上运行。

希望这有帮助。

Generally you cannot read image data from other domains. It violates the Cross-Origin Resource Sharing (CORS) security model. That said you can get around this issue by having each subdomain use a HTTP access control header (here's an example with node.js) as well as setting the crossorigin attribute to use-credentials on each image tag. Note that not all browsers support the crossorigin attribute.

Ultimately, both the server and client have to opt-in to get around CORS security for images.

Another work-around entails using a jquery plugin called $.getImageData. Under the covers this plugin uses a third party service called img-to-json and JSONP to get around the security issues. Here's a concrete example of how to use img-to-json:

"//img-to-json.appspot.com/?url=" + escape(img_url) + "&callback=" + callback

Basically, the service takes two parameters: the URL of the image you're downloading (which needs to be URL escaped), and the name of the callback you want executed when the image is done loading. The callback is passed an objected with the data url version of the image as well as some metadata such as the height and width of the image.

Also, note the URL above is an example of a protocol relative URL (i.e. it begins with //), which means it'll worked on both http or https pages.

Hope this helps.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文