วิธีการแก้ไขข้อผิดพลาด getImageData () ผืนผ้าใบได้รับการปนเปื้อนโดยข้อมูลข้ามแหล่งกำเนิด


131

รหัสของฉันทำงานได้ดีมากบน localhost ของฉัน แต่มันใช้งานไม่ได้บนไซต์

ฉันได้รับข้อผิดพลาดนี้จากคอนโซลสำหรับบรรทัดนี้.getImageData(x,y,1,1).data:

Uncaught SecurityError: Failed to execute 'getImageData' on 'CanvasRenderingContext2D': The canvas has been tainted by cross-origin data. 

ส่วนหนึ่งของรหัสของฉัน:

jQuery.Event.prototype.rgb=function(){
        var x =  this.offsetX || (this.pageX - $(this.target).offset().left),y =  this.offsetY || (this.pageY - $(this.target).offset().top);
        if (this.target.nodeName!=="CANVAS")return null;
        return this.target.getContext('2d').getImageData(x,y,1,1).data;
    }

หมายเหตุ: URL รูปภาพของฉัน (src) มาจาก URL โดเมนย่อย


8
ฉันได้รับข้อผิดพลาดนี้แม้ว่า img.src จะเป็น url สัมพัทธ์ในเครื่อง: "img / foo.png" - cross-origin เกี่ยวกับสิ่งนี้คืออะไร?
Sanford Staab

ดูstackoverflow.com/a/16218015/5175433 : "Chrome ไม่ถือว่าไฟล์ในเครื่องที่แตกต่างกันมาจากโดเมนเดียวกัน"
A_P

คำตอบ:


116

อย่างที่คนอื่นบอกว่าคุณกำลัง "ย้อมสี" ผืนผ้าใบโดยการโหลดจากโดเมน cross origins

https://developer.mozilla.org/en-US/docs/HTML/CORS_Enabled_Image

อย่างไรก็ตามคุณสามารถป้องกันได้โดยเพียงแค่ตั้งค่า:

img.crossOrigin = "Anonymous";

สิ่งนี้ใช้ได้เฉพาะเมื่อเซิร์ฟเวอร์ระยะไกลตั้งค่าส่วนหัวต่อไปนี้อย่างเหมาะสม:

Access-Control-Allow-Origin "*"

ตัวเลือกไฟล์ Dropboxเมื่อใช้ตัวเลือก "ลิงก์โดยตรง" เป็นตัวอย่างที่ดีสำหรับสิ่งนี้ ฉันใช้บนoddprints.comเพื่อรูปภาพจาก url รูปภาพดรอปบ็อกซ์ระยะไกลลงในผืนผ้าใบของฉันจากนั้นส่งข้อมูลรูปภาพกลับไปที่เซิร์ฟเวอร์ของฉัน ทั้งหมดในจาวาสคริปต์


1
วิธีนี้ใช้เพื่อแก้ไขข้อผิดพลาดนี้เมื่อโหลดภาพ imgur ลงใน jsfiddle.net
Travis J

3
ใช้งานได้สำหรับฉันถ้าฉันใส่ crossorigin ก่อนจากนั้นตั้งแหล่งที่มาจากนั้นเข้าถึงข้อมูล onload
jones

2
จะเป็นอย่างไรหากเป็นไฟล์ในเครื่องและแอปของคุณไม่ได้ใช้อินเทอร์เน็ตเลย เช่นเดียวกับแอปพลิเคชัน webview ของ Android และรูปภาพจะอยู่ในโฟลเดอร์เดียวกับไฟล์ html นี้ไม่ได้แก้มัน
Curtis

44

ฉันพบว่าฉันต้องใช้.setAttribute('crossOrigin', '')และต้องต่อท้ายการประทับเวลากับสตริงการสืบค้นของ URL เพื่อหลีกเลี่ยงการตอบกลับ 304 ที่ไม่มีAccess-Control-Allow-Originส่วนหัว

สิ่งนี้ให้ฉัน

var url = 'http://lorempixel.com/g/400/200/';
var imgObj = new Image();
imgObj.src = url + '?' + new Date().getTime();
imgObj.setAttribute('crossOrigin', '');

3
การลองทำสิ่งนี้โดยไม่มีเซิร์ฟเวอร์ในไฟล์ภายในเครื่องจะทำให้: เข้าถึง Image ที่ 'file: /// C: /.../img/colorPaletteCtrl.png? 1507058959277' จากต้นทาง 'null' ถูกบล็อกโดยนโยบาย CORS: การตอบสนองไม่ถูกต้อง . Origin 'null' จึงไม่อนุญาตให้เข้าถึง
Sanford Staab

1
เพียงแค่ใช้imgObj.setAttribute('crossOrigin', '')แก้ไขให้ฉัน - ขอบคุณ! img.crossOrigin = "Anonymous"ทำงานได้เช่นกัน (ดังที่กล่าวไว้ที่นี่ ) เบราว์เซอร์ @SanfordStaab ถือว่าไฟล์ในเครื่องอยู่ในโดเมนอื่นมิฉะนั้นเจ้าของเว็บไซต์จะสามารถอ่านไฟล์ในเครื่องของคุณได้ คุณต้องขอรูปภาพจากโดเมนเดียวกันหรือส่วนหัวในการตอบกลับคำขอของคุณจำเป็นต้องบอกเบราว์เซอร์ว่าไม่เป็นไรหากโค้ดจากโดเมนอื่นอ่านไฟล์นั้น

19

คุณจะไม่สามารถวาดภาพจากเซิร์ฟเวอร์อื่นลงในผืนผ้าใบได้โดยตรงจากนั้นใช้ getImageDataคุณจะไม่สามารถที่จะวาดภาพได้โดยตรงจากเซิร์ฟเวอร์อื่นเป็นผืนผ้าใบและการใช้งานแล้วเป็นปัญหาด้านความปลอดภัยและผ้าใบจะถูกพิจารณาว่า "แปดเปื้อน"

คุณจะบันทึกสำเนาของรูปภาพไปยังเซิร์ฟเวอร์ของคุณโดยใช้ PHP แล้วโหลดรูปภาพใหม่ได้หรือไม่? ตัวอย่างเช่นคุณสามารถส่ง URL ไปยังสคริปต์ PHP และบันทึกลงในเซิร์ฟเวอร์ของคุณจากนั้นส่งคืนชื่อไฟล์ใหม่เป็นจาวาสคริปต์ของคุณดังนี้:

<?php //The name of this file in this example is imgdata.php

  $url=$_GET['url'];

  // prevent hackers from uploading PHP scripts and pwning your system
  if(!@is_array(getimagesize($url))){
    echo "path/to/placeholderImage.png";
    exit("wrong file type.");
  }

  $img = file_get_contents($url);

  $fn = substr(strrchr($url, "/"), 1);
  file_put_contents($fn,$img);
  echo $fn;

?>

คุณจะใช้สคริปต์ PHP กับจาวาสคริปต์ ajax เช่นนี้:

xi=new XMLHttpRequest();
xi.open("GET","imgdata.php?url="+yourImageURL,true);
xi.send();

xi.onreadystatechange=function() {
  if(xi.readyState==4 && xi.status==200) {
    img=new Image;
    img.onload=function(){ 
      ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
    }
    img.src=xi.responseText;
  }
}

ถ้าคุณใช้ getImageDataบนผืนผ้าใบหลังจากนั้นก็จะทำงานได้ดี

หรือหากคุณไม่ต้องการบันทึกภาพทั้งหมดคุณสามารถส่งพิกัด x & y ไปยังสคริปต์ PHP ของคุณและคำนวณค่า rgba ของพิกเซลที่ด้านนั้น ฉันคิดว่ามีไลบรารีที่ดีสำหรับการประมวลผลภาพใน PHP

หากคุณต้องการใช้แนวทางนี้โปรดแจ้งให้เราทราบหากคุณต้องการความช่วยเหลือในการนำไปใช้

edit-1: peeps ชี้ให้เห็นว่าสคริปต์ php ถูกเปิดเผยและอนุญาตให้อินเทอร์เน็ตใช้งานได้โดยมีเจตนาร้าย มีหลายล้านวิธีในการจัดการสิ่งนี้หนึ่งในวิธีที่ง่ายที่สุดคือการทำให้ URL สับสน ... ฉันคิดว่าการปฏิบัติ php ที่ปลอดภัยสมควรได้รับ google แยกต่างหาก P

แก้ไข -2: ตามความต้องการที่เป็นที่นิยมฉันได้เพิ่มการตรวจสอบเพื่อให้แน่ใจว่าเป็นรูปภาพไม่ใช่สคริปต์ php (จาก: PHP ตรวจสอบว่าไฟล์เป็นรูปภาพหรือไม่ )


15
นอกจากนี้ - การโหลดรูปภาพและสคริปต์จากระบบไฟล์ภายในเครื่องทำให้เกิดปัญหาเดียวกัน
Guy Dafny

2
ที่ไม่ปลอดภัยมากบางคนอาจทำให้เซิร์ฟเวอร์ของคุณเต็มไปด้วยไฟล์ขนาดใหญ่โดยใช้สคริปต์ php ซึ่งจะไม่ดี
LAX1DUDE

1
คำตอบของ @ LAX1DUDE ปรับปรุงด้วยการตรวจสอบความปลอดภัยง่ายๆ
jumpjack

1
ด้วยวิธีนี้ทำให้สามารถส่งภาพไปยัง tesseract.js OCR engine ได้โดยไม่ต้องใช้ node.js (เพียงแค่เพิ่มการเรียกไปที่ Tesseract.recognize (img) ในฟังก์ชัน img.onload ()
jumpjack

1
คุณต้องตรวจสอบชื่อไฟล์ประเภทไฟล์ / mime ตำแหน่งและขนาดของการอัปโหลดที่ผู้ใช้ให้มา รหัสนี้เสี่ยงต่อการโจมตีหลายครั้ง ฉันจะปล่อยให้มันเป็นแบบฝึกหัดสำหรับผู้อ่าน แต่ฉันเชื่อว่ามันเป็นไปได้ที่จะอัปโหลดไฟล์. php ไปยังรากของเว็บเซิร์ฟเวอร์ด้วยรหัสนี้
hiburn8

4

ฉันพบข้อผิดพลาดนี้ในChromeขณะที่ฉันกำลังทดสอบโค้ดในเครื่อง ฉันเปลี่ยนมาใช้Firefoxและฉันไม่เห็นข้อผิดพลาดอีกต่อไป การเปลี่ยนไปใช้เบราว์เซอร์อื่นอาจเป็นการแก้ไขอย่างรวดเร็ว

หากคุณใช้วิธีแก้ปัญหาที่ให้ไว้ในคำตอบแรกตรวจสอบให้แน่ใจว่าคุณได้เพิ่มimg.crossOrigin = "Anonymous";หลังจากที่คุณประกาศimgตัวแปรแล้ว (เช่นvar img = new Image();)


2

ปัญหาของคุณคือคุณโหลดรูปภาพภายนอกซึ่งหมายถึงจากโดเมนอื่น ซึ่งทำให้เกิดข้อผิดพลาดด้านความปลอดภัยเมื่อคุณพยายามเข้าถึงข้อมูลใด ๆ ของบริบทพื้นที่ทำงานของคุณ


ใช่ฉันได้รับภาพจากโดเมนย่อยอัปโหลด ... ฉันต้องทำอย่างไร?
Erfan Safarpoor

1
คุณสามารถใช้พร็อกซีเพื่อดึงภาพของคุณพร็อกซีนี้จะอยู่บนโดเมนเดียวกับที่คุณใช้งานแคนวาส
axelduch

1
ฉันกำลังอัปโหลดรูปภาพใหม่จากคอมพิวเตอร์ของฉันและพยายามโหลดในพื้นที่ทำงานและฉันได้รับข้อผิดพลาดนี้ ฉันไม่ได้ใช้อิมเมจเซิร์ฟเวอร์ทุกประเภท
Piyush Dholariya

คอมพิวเตอร์ของคุณจะมองเห็นคอมพิวเตอร์ของคุณซึ่งเป็นที่ตั้งของสคริปต์ (แต่ไม่ได้เรียกใช้งาน) เป็นโดเมนภายนอกเนื่องจากรูปภาพที่คัดลอกลงในผืนผ้าใบถูกสร้างขึ้นบนคอมพิวเตอร์ของคุณซึ่งสคริปต์จะถูกเรียกใช้งานจริง
jumpjack

2

คุณกำลัง "ย้อมสี" ผืนผ้าใบโดยการโหลดจากโดเมน cross origins ตรวจสอบบทความ MDN นี้:

https://developer.mozilla.org/en-US/docs/HTML/CORS_Enabled_Image


ฉันเพิ่ม <IfModule mod_setenvif.c> <IfModule mod_headers.c> <FilesMatch "\. (cur | gif | ico | jpe? g | png | svgz? | webp) $"> SetEnvIf Origin ":" IS_CORS Header set Access- Control-Allow-Origin "*" env = IS_CORS </FilesMatch> </IfModule> </IfModule> ไปยัง htaccess ทุกโดเมน แต่ไม่ทำงาน!
Erfan Safarpoor

1
คุณกำลังทดสอบเบราว์เซอร์ใด และตรวจสอบให้แน่ใจว่าคุณได้รีสตาร์ท Apache แล้ว
srquinn

ฉันรีสตาร์ท apache ไม่ได้ ... ฉันแชร์บัญชี cPanel
Erfan Safarpoor

2
ไม่สามารถช่วยคุณกำหนดค่าการตั้งค่า Apache ได้ขออภัย นอกจากนี้ยังอยู่นอกขอบเขตของคำถามนี้ โพสต์ปัญหาของคุณเกี่ยวกับการตั้งค่า Apache ในคำถามใหม่และชุมชนยินดีที่จะช่วยเหลือคุณที่นั่น
srquinn

1

เมื่อทำงานบนโลคัลให้เพิ่มเซิร์ฟเวอร์

ฉันมีปัญหาคล้ายกันเมื่อทำงานกับท้องถิ่น url ของคุณจะเป็นพา ธ ไปยังไฟล์ในเครื่องเช่น file: ///Users/PeterP/Desktop/folder/index.html

โปรดทราบว่าฉันใช้ MAC

ฉันทำได้โดยการติดตั้ง http-server ทั่วโลก https://www.npmjs.com/package/http-server

ขั้นตอน:

  1. การติดตั้งทั่วโลก: npm install http-server -g
  2. เรียกใช้เซิร์ฟเวอร์: http-server ~/Desktop/folder/

PS: ฉันคิดว่าคุณได้ติดตั้งโหนดไว้มิฉะนั้นคุณจะไม่ได้รับการรันคำสั่ง npm ไกลมาก


0

ดังที่ Matt Burn กล่าวไว้ในคำตอบของเขาคุณอาจต้องเปิดใช้งาน CORS บนเซิร์ฟเวอร์ที่โฮสต์ภาพปัญหา

หากเซิร์ฟเวอร์เป็น Apache สามารถทำได้โดยการเพิ่ม snippet ต่อไปนี้ (จากที่นี่ ) ในการกำหนดค่า VirtualHost หรือ.htaccessไฟล์ของคุณ:

<IfModule mod_setenvif.c>
    <IfModule mod_headers.c>
        <FilesMatch "\.(cur|gif|ico|jpe?g|png|svgz?|webp)$">
            SetEnvIf Origin ":" IS_CORS
            Header set Access-Control-Allow-Origin "*" env=IS_CORS
        </FilesMatch>
    </IfModule>
</IfModule>

... หากเพิ่มลงใน VirtualHost คุณอาจต้องโหลด config ของ Apache ซ้ำด้วย (เช่นsudo service apache2 reloadถ้า Apache ทำงานบนเซิร์ฟเวอร์ Linux)


0

ปัญหาของฉันยุ่งเหยิงมากฉันแค่ base64 เข้ารหัสภาพเพื่อให้แน่ใจว่าไม่มีปัญหา CORS


-2

วันนี้ฉันพบปัญหาเดียวกันและแก้ปัญหาโดยใช้รหัสตามนี้

รหัส html:

<div style='display: none'>
  <img id='img' src='img/iak.png' width='600' height='400' />
</div>
<canvas id='iak'>broswer don't support canvas</canvas>

รหัส js:

var canvas = document.getElementById('iak')
var iakImg = document.getElementById('img')
var ctx = canvas.getContext('2d')
var image = new Image()
image.src=iakImg.src
image.onload = function () {
   ctx.drawImage(image,0,0)
   var data = ctx.getImageData(0,0,600,400)
}

รหัสเหมือนข้างบนและไม่มีปัญหาข้ามโดเมน


1
ค่า src ยังคงเป็นแหล่งที่มาแบบ cross origin ดังนั้นวิธีนี้จะหลีกเลี่ยงปัญหาได้อย่างไร
Loveen Dyall

วิธีนี้ใช้ได้ผลเมื่อเรียกใช้ไฟล์ html ในเครื่อง (ไม่มีเซิร์ฟเวอร์) เช่น file: /// X: /htmlfile.html คนส่วนใหญ่ลงท้ายด้วย ";" ประเด็นของคำสั่ง "var data = .. " คืออะไร? ฉันต้องการคำอธิบายว่าเหตุใดจึงหลีกเลี่ยงข้อผิดพลาด "ข้ามโดเมน" แต่มันไม่ขอบคุณ
dcromley

double smart karry
Mari Selvan

1
@dcromley "คนส่วนใหญ่จบประโยคด้วย;" ไม่แนะนำให้ใช้อัฒภาคตามมาตรฐาน อัฒภาคเพียงเพิ่มงานให้ดูน่าเกลียดและโค้ดจะทำงานได้อย่างสมบูรณ์โดยไม่ต้องใช้มัน ตรวจสอบgithub.com/standard/standard
madprops

1
@madprops developer.mozilla.org กล่าวว่า "แอปพลิเคชัน JavaScript ประกอบด้วยคำสั่งที่มีไวยากรณ์ที่เหมาะสมคำสั่งเดียวอาจครอบคลุมหลายบรรทัดคำสั่งหลายคำอาจเกิดขึ้นในบรรทัดเดียวหากแต่ละคำสั่งคั่นด้วยอัฒภาคนี่ไม่ใช่คีย์เวิร์ด แต่เป็นกลุ่มคำหลัก " ดังนั้นฉันจึงอยู่ในฝ่าย "ใช้เสมอ" ฉันไม่รู้ด้วยซ้ำว่ามีฝ่าย "ไม่เคย" ฉันคิดว่าหลังยังเชื่อว่าโลกแบน? (ล้อเล่น - ขอบคุณ)
dcromley

-3

ฉันมีปัญหาเดียวกันและสำหรับฉันมันทำงานได้โดยการเชื่อมต่อกัน https:${image.getAttribute('src')}


โปรดอธิบายสิ่งที่คุณทำ
Yehuda Schwartz
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.