Tại sao canvas.toDataURL () ném một ngoại lệ bảo mật?


90

Tôi đã không ngủ đủ giấc hay sao? Mã sau đây

var frame=document.getElementById("viewer");
frame.width=100;
frame.height=100;

var ctx=frame.getContext("2d");
var img=new Image();
img.src="http://www.ansearch.com/images/interface/item/small/image.png"

img.onload=function() {
    // draw image
    ctx.drawImage(img, 0, 0)

    // Here's where the error happens:
    window.open(frame.toDataURL("image/png"));
}

đang mắc lỗi này:

SECURITY_ERR: DOM Exception 18

Không có cách nào mà điều này không hoạt động! Bất cứ ai có thể giải thích điều này, xin vui lòng?



2
Giải pháp đó dường như không hữu ích đối với những người không sử dụng Adobe AIR.
Ít người biết đếnRobot

Câu trả lời:


67

Trong thông số kỹ thuật nó nói:

Bất cứ khi nào phương thức toDataURL () của phần tử canvas có cờ gốc sạch được đặt thành false được gọi, phương thức này phải tạo ra một ngoại lệ SECURITY_ERR.

Nếu hình ảnh đến từ một máy chủ khác, tôi không nghĩ bạn có thể sử dụng toDataURL ()


6
Nếu kẻ tấn công có thể đoán được tên của bức ảnh mà bạn có trong trang web riêng tư, thì hắn sẽ có thể lấy bản sao của bức ảnh đó bằng cách vẽ trên canvas và gửi hình ảnh mới đến trang web của mình. Hạn chế chính theo quan điểm của tôi là tránh vẽ nội dung của trang web khác, nhưng bảo mật quá phức tạp vì kẻ tấn công có thể tìm thấy lỗ hổng trong bất kỳ trang web không mong muốn nào.
AlfonsoML

3
Lưu ý rằng miền phụ cũng quan trọng. Theo kinh nghiệm của tôi, ít nhất trong Chrome, SECURITY_ERR: DOM Exception 18 được đưa ra khi thực hiện cuộc gọi được coi là trên các miền phụ: 1. in example.com/some/path/index.html cho video hoặc hình ảnh trong foo .example.com 2. khi truy cập cùng một trang như trong 1 nhưng bằng cách nhập URL example.com/some/path/index.html và sau đó cố gắng gọi toDataUrl () cho một video hoặc hình ảnh trong www.example.com
Sam Dutton

3
@AlfonsoML, có lẽ tôi nhầm, nhưng "Nếu kẻ tấn công có thể đoán tên của một bức ảnh mà bạn có trong một trang web riêng tư" thì có lẽ anh ta sẽ lấy hình ảnh đó một cách không chính xác bằng trình duyệt. Quan điểm của tôi: Nội dung công khai URL công khai.
kilianc

4
@ pop850 Tôi đang gặp sự cố này ngay cả khi tôi sử dụng URL dữ liệu. Có cách nào tôi có thể giải quyết vấn đề này cho các URL dữ liệu không?
Sujay

6
@kilianc Hạn chế này tồn tại để ngăn kẻ tấn công khiến trình duyệt của bạn (với cookie xác thực) tìm nạp hình ảnh và gửi nội dung của nó cho kẻ tấn công; kẻ tấn công không có cookie của bạn, vì vậy chúng không thể sử dụng curl để lấy cùng các tài nguyên mà bạn được phép lấy. "URL công khai, nội dung công khai" là một cách nghĩ khá sai lầm: trang Facebook của tôi có các thành phần đối mặt với công chúng, nhưng có rất nhiều thứ chỉ có thể truy cập được bằng mã xác thực phù hợp.
apsillers

18

Đặt thuộc tính gốc chéo trên các đối tượng hình ảnh phù hợp với tôi (tôi đang sử dụng vảijs)

    var c = document.createElement("img");
    c.onload=function(){
        // add the image to canvas or whatnot
        c=c.onload=null
    };
    c.setAttribute('crossOrigin','anonymous');
    c.src='http://google.com/cat.png';

Đối với những người sử dụng Fabricjs, đây là cách vá Image.fromUrl

// patch fabric for cross domain image jazz
fabric.Image.fromURL=function(d,f,e){
    var c=fabric.document.createElement("img");
    c.onload=function(){
        if(f){f(new fabric.Image(c,e))}
        c=c.onload=null
    };
    c.setAttribute('crossOrigin','anonymous');
    c.src=d;
};

Cảm ơn, nó phù hợp với tôi trong Chrome. Tôi không sử dụng fabric.js dù
Philip007

Tôi sử dụng Fabricjs nhưng không thể giải quyết nó. Làm thế nào bạn sẽ làm điều này với mã này? function wtd_load_bg_image (img_url) {if (img_url) {var bg_img = new Image (); bg_img.onload = function () {canvasObj.setBackgroundImage (bg_img.src, canvasObj.renderAll.bind (canvasObj), {originX: 'left', originY: 'top', left: 0, top: 0}); }; bg_img.src = img_url; }}
HOY

Hoạt động trên Firefox.
vanowm

16

Nếu hình ảnh được lưu trữ trên một máy chủ đặt Access-Control-Allow-Origin hoặc Access-Control-Allow-Credentials, bạn có thể sử dụng Chia sẻ tài nguyên nguồn gốc chéo (CORS). Xem tại đây (thuộc tính crossorigin) để biết thêm chi tiết.

Tùy chọn khác của bạn là để máy chủ của bạn có một điểm cuối tìm nạp và cung cấp hình ảnh. (ví dụ: http: // your_host / endpoint? url = URL ) Nhược điểm của phương pháp đó là độ trễ và lý thuyết không cần thiết tìm nạp.

Nếu có nhiều giải pháp thay thế hơn, tôi muốn nghe về chúng.


Xin chào, tôi vừa làm vậy, tôi có Access-Control-Allow-Origin: * trên hình ảnh, tôi có crossorigin = 'nặc danh', sau đó tôi vẽ hình ảnh trên canvas, sau đó tôi gọi toDataUrl và tôi vẫn nhận được SECURITY_ERR : DOM ngoại lệ 18
skrat

13

Có vẻ như có một cách để ngăn chặn điều đó nếu lưu trữ hình ảnh có thể cung cấp các tiêu đề HTTP sau cho tài nguyên hình ảnh và trình duyệt hỗ trợ CORS:

access-control-allow-origin: *
access-control-allow-credentials: true

Nó được nêu ở đây: http://www.w3.org/TR/cors/#use-case


1
access-control-allow-credentials: true sẽ không hoạt động với access-control-allow-origin: *. Khi cựu được thiết lập, sau này cần phải có một giá trị gốc, không phải là một giá trị ký tự đại diện từ developer.mozilla.org/en-US/docs/HTTP/Access_control_CORS
Bạc Gonzales

4

Cuối cùng tôi đã tìm ra giải pháp. Chỉ cần thêm tham số crossOriginthứ ba trong fromURLfunc

fabric.Image.fromURL(imageUrl, function (image) {
            //your logic
    }, { crossOrigin: "Anonymous" });

2

Tôi đã gặp vấn đề tương tự và tất cả hình ảnh được lưu trữ trong cùng một miền ... Vì vậy, nếu ai đó đang gặp vấn đề tương tự, đây là cách tôi giải quyết:

Tôi có hai nút: một để tạo canvas và một nút khác để tạo hình ảnh từ canvas. Nó chỉ hoạt động với tôi, và xin lỗi rằng tôi không biết tại sao, khi tôi viết tất cả mã trên nút đầu tiên. Vì vậy, khi tôi nhấp vào nó sẽ tạo canvas và hình ảnh cùng một lúc ...

Tôi luôn gặp sự cố bảo mật này khi các mã ở các chức năng khác nhau ... = /


2

Tôi đã có thể làm cho nó hoạt động bằng cách sử dụng cái này:

Viết điều này trên dòng đầu tiên của bạn .htaccesstrên máy chủ nguồn của bạn

Header add Access-Control-Allow-Origin "*"

Sau đó, khi tạo một <img>phần tử, hãy thực hiện như sau:

// jQuery
var img = $('<img src="http://your_server/img.png" crossOrigin="anonymous">')[0]

// or pure
var img = document.createElement('img');
img.src='http://your_server/img.png';
img.setAttribute('crossOrigin','anonymous');

1

Bạn không thể đặt dấu cách trong ID của mình

Cập nhật

Tôi đoán là hình ảnh đó nằm trên một máy chủ khác với nơi bạn đang thực thi tập lệnh. Tôi đã có thể sao chép lỗi của bạn khi chạy nó trên trang của riêng tôi, nhưng nó hoạt động tốt khi tôi sử dụng hình ảnh được lưu trữ trên cùng một miền. Vì vậy, nó liên quan đến bảo mật - hãy đặt hình ảnh trên trang web của bạn. Có ai biết tại sao lại như vậy không?


0

Nếu bạn chỉ vẽ một số hình ảnh trên canvas, hãy đảm bảo rằng bạn đang tải các hình ảnh từ cùng một miền.

www.example.com khác với example.com

Vì vậy, hãy đảm bảo rằng hình ảnh của bạn và url bạn có trong thanh địa chỉ của bạn giống nhau, có www hoặc không.


0

Tôi đang sử dụng Fabric.js và có thể giải quyết vấn đề này bằng cách sử dụng toDatalessJSON thay vì toDataURL:

canvas.toDatalessJSON({ format: 'jpeg' }).objects[0].src

Chỉnh sửa: Đừng bận tâm. Điều này dẫn đến việc ảnh nền chỉ được xuất sang JPG, không có hình vẽ ở trên nên sau cùng thì nó không hoàn toàn hữu ích.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.