Using Cross-domain images in WebGL and Chrome 13

Wednesday, July 06, 2011

Labels:

A few weeks ago, we became aware of a security issue with WebGL: shaders could be used to indirectly deduce the contents of textures uploaded to the GPU. As a result, the WebGL specification was updated to be more restrictive when it comes to using cross-domain images and videos as WebGL textures.

As a result, Chrome 13 (and Firefox 5) will no longer allow cross-domain media as a WebGL texture. The default behavior will be a DOM_SECURITY_ERR. However, applications may still utilize images and videos from another domain with the cooperation of the server hosting the media, otherwise known as CORS.

CORS support for MediaElements has also been fully implemented in WebKit by setting a new .crossOrigin attribute. This means that sophisticated applications that were using cross-origin textures before, can continue to do so, assuming the hosting image server grants the necessary cross-origin permission using CORS. If you want to enable CORS request on an image, all you have to do is add one line of code:

var img = document.createElement('img');
img.onload = function(e) { … };
img.crossOrigin = ''; // no credentials flag. Same as img.crossOrigin='anonymous'
img.src = 'http://other-domain.com/image.jpg';


Another nice property that we gain from this new setting is the ability to read cross-domain image data set on a 2D canvas. Normally, filling a canvas with a remote image (e.g. ctx.drawImage()) flips the origin-clean flag to false. Attempting to read back the pixels using ctx.toDataURL() or ctx.getImageData() throws a SECURITY_ERR. This is to prevent information leakage. However, when .crossOrigin is set (and the remote server supports CORS), the read is possible. For example:

var img = document.createElement('img');
img.onload = function(e) {
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
var url = canvas.toDataURL(); // Read succeeds, canvas won't be dirty.
};
img.crossOrigin = '';

img.src = 'http://other-domain.com/image.jpg';


Unfortunately, this new restriction in WebGL means that some existing content will break. We’ve already started working with external image and video hosting services like Flickr to evangelize the use of CORS on their images.

You can test this new behavior today using images from Picasa, which already sends a CORS header allowing cross-origin requests, and the Chrome dev channel.

Post a Comment