画布图像跨平台不安全错误

IT技术 javascript canvas
2021-02-05 15:46:18

我有这个代码用于从不同的服务器 url 创建画布图像

function getBase64Image(imageUri) { 
    var canvas = document.createElement("canvas");
    ctx = canvas.getContext("2d"); 
    var img = new Image();
    img.src = imageUri;
    img.crossOrigin = "Anonymous";
    img.onload = function() {
       canvas.width = this.width;
       canvas.height = this.height;
       ctx.drawImage(img, 0, 0, this.width, this.height);
       var imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
       var dataURL = canvas.toDataURL("image/png");
       document.getElementById("dummyhiddenField").value = dataURL;
   };
}

我试图从服务器获取图像并将其画布 url 设置为隐藏字段,但它仅适用于本地图像

根据我设置的 stackoverflow 的其他答案,crossOrigin = "Anonymous"它不起作用也无法设置来自服务器的访问源,必须从 localscript 管理所有内容

谢谢

1个回答

对具有跨域内容的 Html5 Canvas 的更新。

以下是跨域内容如何影响 html5 画布以及如何在适用于跨域内容的安全限制内工作的更新视图

今天(2016 年 1 月)的更新很有用,因为有几种新的(ish)方法允许将跨域图像绘制到画布上而不会污染画布。

在 html5 画布上绘制跨域内容会导致它被“污染”

您可以在画布上绘制来自另一个域的图像,它会显示在画布上。从另一个域访问资源称为“跨域资源共享”——通常简称为“CORS”。

出于安全原因,绘制 CORS 内容(例如:图像)将导致画布被“污染”。

如果画布被污染,则不能使用这些画布和上下文方法:

  • context.getImageData 获取画布上的像素数据
  • canvas.toDataURL 将画布导出为图像

您不能“欺骗”canvas 以违反其 CORS 安全限制——希望您甚至不想尝试!但是您可以通过满足 CORS 安全限制来绘制跨域图像而不会污染画布

处理图像的“通常”(也是最简单的)方式,这样它们就不会污染画布:

将您的图像放在与网页相同的域中您可以有多个物理服务器来传送内容,但图像必须与创建画布的 html 代码(或 javascript 代码)相同。CORS 限制得到满足,画布没有被污染。

在自己的计算机上开发时关于 CORS 的注意事项

解决方案#1(!):您可以在开发计算机上安装 Web 服务器,并从一个域提供网页文件(.html、.js 等)和图像文件(.png、.jpg 等)。

您的开发计算机的文件夹被声明为不同的域。因此,从本地磁盘上的子目录中绘制图像将违反 CORS 限制,因为不同的本地文件夹是不同的域。

解决方案#2:在进行开发时,您可以将网页文件和图像文件都放在桌面上,图像将被声明在同一个域中,并且您的画布不会被污染。

当图像位于不同域时满足 CORS 限制

解决方案#3:可以在画布上使用跨域图像而不会污染它。为此,您必须满足以下要求:

  • 客户端:图像对象必须crossOrigin设置属性以允许跨源内容。此属性可以在 html 元素标签内或在 javascript 内设置。启用设置是“匿名”和“使用凭证”。

  • 服务器端:服务器必须配置为返回标头,指示响应包含授权内容。

根据配置,可能需要 1 个以上的响应标头:

Access-Control-Allow-Origin将返回匿名授权 ( *) 或将根据请求返回特定授权。

Access-Control-Allow-Credentials 如果身份验证需要其他信息(如 cookie),则需要。

Access-Control-Expose-Headers 使客户端可以访问其他响应信息。

在服务器上启用跨域请求可能很复杂,尤其是在提供基于客户端角色授权的内容时。有关启动配置的更多信息,您可以访问:http : //enable-cors.org/index.html

使用允许匿名访问其图像的跨域图像主机

解决方案#4:一些公共图像主机允许您上传图像,这些图像将以符合 CORS 的方式提供给客户端。几个例子是:imgurdropboxStackoverflow 图片托管在 Imgur 上。

以下是如何以符合 CORS 的方式在 Dropbox.com 上提供图像的示例:

  1. 注册一个Dropbox 帐户
  2. 您将获得几个默认文件夹。将您的图像上传到特殊的“公共”文件夹中。这是 Dropbox 提供符合 CORS 的匿名访问权限的文件夹。
  3. 右键单击要提供的图像,然后选择“复制公共链接”。您的剪贴板将包含指向符合 CORS 的图像的链接。
  4. 使用 img 标签或在 javascript 中将图像加载到您的页面上。

以下是使用 javascript 从 Dropbox 获取符合 CORS 的图像对象的示例代码:

var img=new Image();
img.crossOrigin='anonymous';
img.src="https://dl.dropboxusercontent.com/u/139992952/multple/sun.png";
img.onload=start;
function start(){
    context.drawImage(img,0,0);
    // The canvas is not tainted so 
    // the following both work without errors
    var url=canvas.toDataURL();
    var imageData=context.getImageData(0,0,100,100);
}

新(ish):通过让客户端用户同意来满足 CORS

CORS 安全限制旨在阻止坏人在让您不知情的情况下秘密获取您的信息。

直到最近,浏览器还依赖客户端-服务器配置来满足安全要求。最近,如果用户肯定参与决定正在使用什么内容,浏览器已经开始允许跨源内容。

解决方案#5: Chrome 和 Firefox 现在允许客户端用户使用right click the canvas & save the canvas as an image. 这相当于手动canvas.toDataURL创建图像对象并将该图像对象保存到本地驱动器。CORS 很满意,因为用户决定画布内容是否适合保存到他们的本地驱动器,并且他们肯定地右键单击以启动下载过程。

解决方案#6:您可以使用 aninput element, type='file'来让客户端用户选择图像。用户甚至可以选择一个互联网 URL ( http://... )。同样,因为用户参与了选择过程,所以 CORS 很满意。

以下示例代码显示了如何监听用户使用输入选择图像:

解决方案#7:您可以使用 new(ish)FileReader让用户选择要在画布上绘制的图像。

待续...

此更新中可能需要包含更多信息位。请随时评论我的心不在焉,我会继续更新。:-)

5我会添加一个注释,说明在另一个画布上绘制的受污染画布也会污染后者。此外,没有办法“清除”画布,即使clearRect在画布的整个区域上调用,画布仍将被标记为被污染。在这种情况下,您必须创建一个新画布并重新绘制除受损部分之外的所有内容。
2021-03-20 15:46:18
此外,正如@Kaiido 在他的第 5 点中提到的那样,我每次都必须重新绘制画布,并且每当我通过它时,它已经发生在我的项目中。所以非常感谢你们两个:)
2021-03-28 15:46:18
你好@markE,我很感激你的回答,它对我和其他正在寻找这种解决方案的人真的很有帮助,正如我之前在@Kaiido 的评论中提到的,我只有一个选择是使用Access-Control-Allow-Origin所以跟随你的Solution#3:这是第一个也是我在工作中取得成功的最后机会。
2021-03-29 15:46:18
3我会补充说,如果设置并支持 crossOrigin 属性,但服务器不允许请求,则图像根本不会加载,这将引发error事件<img> 4我会添加有关 CORS 的注释不是污染画布的唯一方法:IE<Edge 会污染任何绘制了 svg 的画布,Safari 9 会污染那些<foreignObject>绘制了包含元素的 svg 的画布
2021-04-10 15:46:18
一些注意事项:1即使服务器配置良好并且设置了<img>crossOrigin 属性,您也必须在服务器上(不管怎样http://localhost):尝试从file://协议执行跨域请求是行不通的。2 imgur.com没有发送正确的标头,请参阅此元问题,其中提供了代理服务作为解决方法,也可以编写自己的标头。
2021-04-12 15:46:18