There exists many good articles for CORS in general such as this one but this article will focus on CORS together with images used on a canvas element.
What is CORS?
When do CORS kick in?
The CORS restrictions kicks in when a page request data from an origin not equal to its own origin.
The definition of origin is schema (or protocol) ie.
https, domain and port number.
For two origins to be the same these three needs to match. If not the browser will consider the two to be of different origins and then apply restrictions due to security and the default same-origin policy.
You will also experience a security error when you try to load an image from the local file protocol (
file://) even if some browsers such as Chrome allow you to override this by using command line argument with it.
Restrictions with images on canvas
When we want to load and draw an image onto the canvas we can do so with no particular restriction or problem if we are just displaying the image.
The restriction however kicks in when we want to extract any pixels from the canvas using either the
canvas.toDataURL() methods for the 2D context. The browser throws an error in console saying
SECURITY_ERR or a message such as this:
Failed to execute 'getImageData' on 'CanvasRenderingContext2D': The canvas has been tainted by cross-origin data.
So, why are there restrictions?
Most people encountering this sees these restrictions as a problem when we just want to build our Photoshop clone or image cropper. Understandable enough.
At the same time, most of us can see the general risk if requesting data from a different domain were allowed without any sort of mechanism for protection. We wouldn’t be too thrilled finding out that we entered our password into a form that appeared to be from the actual bank site but actually typed it into an AJAX injected form coming from a malicious site.
But it may be a little harder to understand what security risks are involved in this case when we can already draw the image, flip it, mix it with shapes and what have you, but we can’t extract it as an image.
And this does not only apply to the 2D canvas context. There is also a theoretical risk involved with WebGL 3D textures as a hacker could use advanced techniques to determine what the user were doing (what application was used and so forth) if he was able to read the pixel data from a texture.
How can we avoid security errors?
When we have the purest intentions with our applications we would like to avoid running into this scenario and there are a few things we can do to make our applications run without any problems:
- The obvious one is to host all the resources yourselves. This works well will small sites, but when your site grows you may want to use a CDN for your images and then CORS could strike once more as these are typically external.
- If you control the servers yourselves or have access to modify it, you can add for example an
Access-Control-Allow-Originheader. For more information on headers in particular see this link.
- If your images are hosted on an external server that allows CORS use you can simply request such usage by providing a
crossOriginproperty on the image (see below).
- If you test in a local environment don’t use the file:// protocol but install a light-weight browser such as Mongoose and use the localhost (127.0.0.1) domain instead.
- There is also the option of using your own server (same as your page) as an image proxy to load the external resource on server side and forward it through a page request on your server (however, in most cases you could might as well just host the image directly if bandwidth is the main concern).
If we host all the images ourselves on the same server as the page is loaded from, there is no need to do anything in particular.
If we however use a different origin to load the images from we need to do a simple extra step:
We can request the images from this origin to be allowed for CORS usage (the effect here for canvas is that we can extract its pixels, the images can be displayed in either case). The only thing we need to do to request such usage is to provide a CORS “use level” before we set the
var img = new Image; img.onload = handleLoad; img.crossOrigin = 'anonymous'; /// optionally 'use-credentials' img.src = 'externalUrlToImage';
We could also set an empty string if we want to use
anonymous (any invalid value will revert to
anonymous - I won’t cover the
use-credential as it is a bit more extensive but the most common level is the
In HTML we simply do:
<img src="..." crossOrigin="anonymous" />
or simply leave it as a key without any value as most will probably use this with document type HTML5 and not XHTML.
Now, that being said it is still up to the server to actually allow the resource being loaded this way (see the bullet above with access header) provided that the user client has implemented CORS support (which all of the major browsers do).
The sever can accept it or reject it and the user client will comply. In the latter case where the server do not allow such use an error will happen and nothing is loaded so the key here is to know in advantage if the server will allow this use or not.
As we can see the CORS is a good thing and necessary as there are as usual a few bad guys out there willing to ruin things for us all.
We can also see that the way around this is fairly straight-forward: host the resources on the same server or use a server that allow cross-origin usage and request such use.
I hope in any case that how CORS relates to Canvas is a bit more clear. Feel free to use the comment field below for any questions or comments.