Here's an indirect test for CORS tainting that doesn't use try-catch:
A Demo: http://jsfiddle.net/m1erickson/uDt2K/
It works by setting a image.tainted=true
flag before loading the image
Then in image.onload, context.getImageData
triggers/doesn't trigger a CORS violation.
If no violation occurs, then the tainted flag is set to false (image.tainted=false
).
var img=new Image();
// set a "tainted flag to the image to true (initialize as tainted)
img.tainted=true;
img.onload=function(){
// try an action that triggers CORS security
var i=ctx.getImageData(1,1,1,1);
// if we don't get here, we violated CORS and "tainted" remains true
// if we get here, CORS is happy so set the "tainted" flag to false
img.tainted=false;
};
// test with tainted image
img.src="http://pp-group.co.uk/wp/wp-content/uploads/2013/10/house-illustration-web.gif";
Since image.onload is asynchronous, your code outside image.onload will still execute even after a CORS violation.
Here's example code that:
- creates an image object
- tests if the image is CORS compliant
- executes one callback if the image is compliant
- executes another callback if the image is not compliant
Example Code:
<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<style>
body{ background-color: ivory; }
canvas{border:1px solid red;}
</style>
<script>
$(function(){
// known CORS violator
var src1="http://pp-group.co.uk/wp/wp-content/uploads/2013/10/house-illustration-web.gif";
// known CORS compliant
var src2="https://dl.dropboxusercontent.com/u/139992952/houseIcon.png";
// callbacks depending on if the image causes tainted canvas
function tainted(img){console.log("tainted:",img.src);}
function notTainted(img){console.log("not tainted:",img.src);}
// testing
var image1=newImage(src1,tainted,notTainted);
var image2=newImage(src2,tainted,notTainted);
function newImage(src,callWhenTainted,callWhenNotTainted){
// tmpCanvas to test CORS
var tmpCanvas=document.createElement("canvas");
var tmpCtx=tmpCanvas.getContext("2d");
// tmpCanvas just tests CORS, so make it 1x1px
tmpCanvas.width=tmpCanvas.height=1;
var img=new Image();
// set the cross origin flag (and cross our fingers!)
img.crossOrigin="anonymous";
img.onload=function(){
// add a tainted property to the image
// (initialize it to true--is tainted)
img.tainted=true;
// draw the img on the temp canvas
tmpCtx.drawImage(img,0,0);
// just in case this onload stops on a CORS error...
// set a timer to call afterOnLoad shortly
setTimeout(function(){
afterOnLoad(img,callWhenTainted,callWhenNotTainted);
},1000); // you can probably use less than 1000ms
// try to violate CORS
var i=tmpCtx.getImageData(1,1,1,1);
// if we get here, CORS is OK so set tainted=false
img.tainted=false;
};
img.src=src;
return(img);
}
// called from image.onload
// at this point the img.tainted flag is correct
function afterOnLoad(img,callWhenTainted,callWhenOK){
if(img.tainted){
// it's tainted
callWhenTainted(img);
}else{
// it's OK, do dataURL stuff
callWhenOK(img);
}
}
}); // end $(function(){});
</script>
</head>
<body>
<canvas id="canvas" width=360 height=281></canvas>
</body>
</html>