25

I was under the impression that Internet Explorer 10 fully supported CORS, but now I'm not sure.

We have a JS/HTML5 App that uses multiple domains, and reads image data. We are loading images in the JS from another domain, imageDraw()ing the image to our canvas, and then using getImageData on the canvas. (We aren't using cross-domain XMLHttpRequests). For this to work we have had to set response headers on the server that's serving the images:

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

And set this on the image object in the JS before loading:

image.crossOrigin = 'Anonymous'; //Also tried lowercase

This is working fine for all new browsers, apart from IE10 which is throwing security errors when we try to read the data.

SCRIPT5022: SecurityError

Is there something more that needs to be done for IE10 to treat these cross domain images as not tainting?

UPDATE:

I noticed this answer to a previous question. Interestingly this JSFiddle also does not work for IE10 - can anyone confirm that this does not work in their IE10?

Community
  • 1
  • 1
UpTheCreek
  • 31,444
  • 34
  • 152
  • 221
  • Setting `Access-Control-Allow-Origin` may be necessary but sometimes not sufficient. Try setting the extra options given in the answer here: http://stackoverflow.com/questions/667519/firefox-setting-to-enable-cross-domain-ajax-request – user568109 Jun 08 '13 at 19:11
  • 1
    Try hitting https://test-cors.appspot.com/#technical with your browser. If that exposes problems then you may not be able to do anything about it. – Old Pro Jun 09 '13 at 01:43
  • @user568109 - I've now added the extra headers mentioned in that answser, but unfortunately am still seeing the same problem. – UpTheCreek Jun 09 '13 at 17:04
  • @OldPro - According to that site, everything is supported...hmm. – UpTheCreek Jun 09 '13 at 17:05
  • So you're not using `XMLHttpRequest` but an `Image` object? Sharing a bit code might help. – Bergi Jun 10 '13 at 14:27
  • @Bergi - right. I'll clarify the question a bit. For code, I can't give the production code as it's a bit spread out, but please see the JSFiddle for an example that has the same issue. – UpTheCreek Jun 10 '13 at 14:34
  • According to MDN, the [`crossOrigin` property](https://developer.mozilla.org/en-US/docs/HTML/CORS_settings_attributes) is "not supported" for Safari, Opera, or any IE. I have no idea if that information is wrong or out of date, though. – apsillers Jun 10 '13 at 14:43
  • Intersting - I think it must be out of date, as it works fine in Safari. I guess it's quite possible that IE10 still doesn't support it though. Trying to get any clarification from MS sources is difficult though. – UpTheCreek Jun 10 '13 at 14:52
  • 2
    @UpTheCreek Agreed -- I just tested it in Opera and it works fine, too. So, if IE is correctly labeled as "not supported" it's the odd one out. Have you tried setting `image.crossOrigin` to `"anonymous"` (lowercase) or `true`? I think the uppercase version you posted is spec-correct, but maybe IE implemented it wrong? – apsillers Jun 10 '13 at 14:53
  • @apsillers - I've tried both all-lowercase and capitalised, neither work unfortunately. I'll give true a go. – UpTheCreek Jun 10 '13 at 14:57
  • Regarding your update question -- yeah getting Access-Denied on that JSFiddle in IE10. – Philipp Lenssen Jun 10 '13 at 20:51
  • I don't have access to Windows 8 myself, but you can check if [this](http://www.shangalulu.com/driver/test_canvas_taint.html) works on IE10? It is a test developed by someone having the same problem on IE9 who concluded that IE9's implementation of Image() does not properly support CORS and there was no workaround. http://social.msdn.microsoft.com/Forums/en-US/iewebdevelopment/thread/ab799e5c-047d-4395-89f8-b57e4fcf137b – Old Pro Jun 11 '13 at 08:07
  • @OldPro - yeah that canvas-taint-test in the thread is throwing a security error in IE10. – UpTheCreek Jun 11 '13 at 09:18
  • 2
    I had done a lot of tests on this for a project I was doing where I'd do some calculations on site's favicon. IE9 and IE10 both don't support CORS for image resources in a ``. I ended up writing a proxy to fetch the image to make the image request not run afoul of the same-origin rules. Sorry. – pseudosavant Jun 14 '13 at 19:44
  • @pseudosavant - thanks, yeah that's pretty much the conclusion I've reached. Proxying it's great if you're planning on using a CDN though :/ – UpTheCreek Jun 15 '13 at 09:46
  • @UpTheCreek: I've been having the same issue. I discovered that IE10 has CORS disabled by default – so it's pretty much useless. See my question here: http://stackoverflow.com/questions/18422980/security-error-using-cors-in-ie10-with-node-and-express – David Jones Aug 27 '13 at 00:26

2 Answers2

25

Unfortunately, IE10 still remains the only popular browser that doesn't support CORS for image drawn to Canvas even when CORS headers are properly set. But there is workaround for that via XMLHttpRequest:

var xhr = new XMLHttpRequest();
xhr.onload = function () {
    var url = URL.createObjectURL(this.response), img = new Image();
    img.onload = function () {
        // here you can use img for drawing to canvas and handling
        // ...
        // don't forget to free memory up when you're done (you can do this as soon as image is drawn to canvas)
        URL.revokeObjectURL(url);
    };
    img.src = url;
};
xhr.open('GET', url, true);
xhr.responseType = 'blob';
xhr.send();
RReverser
  • 1,940
  • 14
  • 15
  • Works great. It took me over 2 hours to get to the same solution. I just wish I had found it earlier. – Artur Marnik Apr 23 '14 at 20:05
  • This worked great for us in every browser we cared about except Android Stock Browser. Tested in Android Chrome, iOS Safari, IE10+, Chrome and FF. Very annoying! – Rob Murphy Dec 03 '14 at 12:10
  • Is there a way to test if the "toDataURL" throws a security error, then if so use this method? – MrHunter Feb 03 '15 at 14:13
  • @MrHunter Hmm, didn't try, but you could try regular `try-catch` around `toDataURL` and see if that works. – RReverser Feb 04 '15 at 08:45
  • @RReverser for some reason when I'm using this snippet I am getting black image from canvas. However no security exceptions. – vittore May 01 '15 at 01:36
  • Not familiar with XMLHttpRequest but in trying this out I've been having issues. What is meant for the "url" in the xhr.open line. The defined url on line 3 is out of scope at that point. I tried putting my dataURL in there and got access denied. I'm attempting to convert from SVG to PNG by way of canvas (there may be another or better way) but my dataUrl is 'data:image/svg+xml;base64,'+btoa(svgXml) tried stripping off the data: header and it does make it to the request, but then I'm getting other errors. – Joe Mar 08 '16 at 16:20
  • 1
    > What is meant for the "url" in the xhr.open line. Just the original image URL you're trying to load. – RReverser Mar 15 '16 at 11:31
7

Confirmed: IE10 does not support CORS images in an HTML 5 canvas. See RReverser's answer for a workaround.

Edit

Sorry, I haven't dealt with CORS images before and thought this question was about an AJAX request.

According to Mozilla Developer Network you need to set image.crossOrigin to anonymous or use-credentials. Also, according to that page today, these attributes are not supported in IE, Safari, or Opera. This test was made to demonstrate that IE9 did not support it and it seems that same test still fails in IE10, so even if Safari and Opera have added support since the MDN article was written, it is quite possible that IE10 still lacks support.

The only tip I can give you is that in general, allow-credentials is incompatible with a wildcard allow-origin. Either drop the allow-credentials or echo the request Origin in the allow-origin.

Below is for AJAX calls, not image or video canvas resources

Early versions of IE10 were known to have AJAX bugs,

so it could be another browser bug. Then again, CORS is deceptively tricky to get right. I recommend the following steps to debug CORS problems.

  1. Point the browser at http://test-cors.appspot.com/#technical to get a compatibility report. If anything fails then you have a bug or lack of support for CORS in the browser.
  2. If everything passes, use the CORS headers the test is sending as a starting point to get your CORS request working. Then change one header at a time and retest until you get the headers the way you want for your application or you run into a failure you cannot explain or work around.
  3. If necessary, post a question about that one tiny change that breaks the CORS request, posting both the working "before" and the failing "after". It always helps if you can include a runnable example.

The complete code for the CORS test client and server (Python script for Google App Engine) is available at https://github.com/rapportive-oss/cors-test to get you started.

Community
  • 1
  • 1
Old Pro
  • 24,624
  • 7
  • 58
  • 106
  • Thanks - unfortunately still no luck. 1 reports all ok, however I have all of the headers specified in each of the responses from the test, and I still get the security error. I'm not convinced that this test is really testing 'everything' though - e.g. 1) None of the response headers use the wildcard access-control-allow-origin setting 2) It's not testing drawImage or getImageData at all, and 3) It's not testing the image.crossOrigin = "Anonymous" feature. – UpTheCreek Jun 10 '13 at 13:25
  • BTW - I've found a JSFiddle that shows the problem perfectly (http://jsfiddle.net/WLTqG/29/) - see my updated question for the background. – UpTheCreek Jun 10 '13 at 13:27
  • Thanks for the extra tips. Re the incompatibility - it was my understanding that `access-control-allow-credentials` was necessary to use 'image.crossOrigin', so we probably wont be able to drop that. As you say, dynamic allow-origin headers may be an option, but TBH I haven't seen any problems using both of these. – UpTheCreek Jun 11 '13 at 07:22
  • `access-control-allow-credentials` is _not_ needed if you set `image.crossOrigin` to `anonymous`. It is only needed when it is set to `use-credentials`. With AJAX calls I have seen the allow-origin wildcard rejected consistently when use-credentials is set, which is why the CORS AJAX tester does not use wildcard origins. I guess we're seeing the rules are somewhat different for Canvas tainting, but if you do not need credentials to access the image then you can remove the allow-credentials header and rule out that as a possible source of the problem. – Old Pro Jun 11 '13 at 07:52
  • Thanks for the clarification. I've now removed the `access-control-allow-credentials`. (Wasn't causing the IE problem though unfortunately) – UpTheCreek Jun 11 '13 at 09:16
  • @ElzoValugi - can JSONP help with loading non-tainting images? – UpTheCreek Jun 14 '13 at 06:56
  • @UpTheCreek I dont know what is a non-tainting image, but what you are trying to do is cross-origin requests and JSONP solves exactly that problem. I use JSONP to transfer usually a piece of JSON code, but in that you can place a path, or a base64 image as well. And JSONP is already 4-5 years old tech which works cross browser. – Elzo Valugi Jun 14 '13 at 07:40
  • @UpTheCreek also if you send cookies along the request take a look at this issue https://connect.microsoft.com/IE/feedback/details/759587/ie10-doesnt-support-cookies-on-cross-origin-xmlhttprequest-withcredentials-true – Elzo Valugi Jun 14 '13 at 07:43
  • @ElzoValugi - I don't really have a problem with cross-origin requests as such (As I've said, I'm not doing any cross origin ajax), rather the issue is loading cross origin images in a way that will not taint the canvas. – UpTheCreek Jun 14 '13 at 07:44
  • @UpTheCreek if you have control of the server providing the cross-origin content, the JSONP paradigm would have you serve a JavaScript "file" that replaces the `var imgData = ctx.getImageData(0, 0, 100, 100);` of your [JS Fiddle](http://jsfiddle.net/WLTqG/29/) with `var imgData = JSON.parse(` _ – Old Pro Jun 14 '13 at 08:08
  • I should point out that if your going to those kinds of lengths, it probably makes more sense to retrieve the image data in an AJAX request in the first place. – Old Pro Jun 14 '13 at 08:17
  • @OldPro - interesting thanks. One of the reasons I wanted to keep it as an image request was to make use of the client cache. (probably we will lose this if we go the ajax route) – UpTheCreek Jun 14 '13 at 08:22
  • @UpTheCreek, I agree, this is an unpleasant hack to get around lack of support in IE, but if you must, then you can. Both JS files (if using JSONP) and AJAX responses (at least via jQuery) can be cached by the browser with appropriate implementation of calls and responses. If you need more details on that you should do research (lots of answers on this site alone) and then ask a new question if you still need more info. – Old Pro Jun 14 '13 at 08:29
  • This 'answer' isn't really an answer to the question. – pseudosavant Jun 14 '13 at 19:57
  • @pseudosavant, what would have preferred for an answer, given that IE10 does not support the feature but there is no official statement from Microsoft that the feature is not supported, and the comments give 2 workarounds for accomplishing the goal? – Old Pro Jun 14 '13 at 22:01
  • @OldPro - thanks for your effort! Bounty is yours but I'll leave the question open just in case someone comes up with another workaround. – UpTheCreek Jun 15 '13 at 09:47
  • @UpTheCreek, Thank You. Sorry I couldn't give you a better solution. – Old Pro Jun 15 '13 at 19:03
  • @OldPro - no need to apologise :) There probably isn't one. – UpTheCreek Jun 16 '13 at 17:38