I'm curious if anyone could fill me in on how safe it is to use toDataURL on a user provided image. The basic idea is that User A would upload an image in their browser and it would be converted to an URL, and then ignoring steps in between, eventually User B (as well as other users) would retrieve the URL format where it would be converted back into an image and displayed in User B's browser.
So my question revolves around whether someone could abuse the system to inject code into User B's browser, or otherwise cause havoc. In general, what security considerations are there that must be taken when using toDataURL and then later converting it back?
I'm aware that cross origin images taint a canvas which disallows any methods that involve the data, but I'm not aware of how much of a blanket solution this is. I've read that some browsers don't have this restriction while other's (and even other versions of the same browser) implement this restriction differently depending on the content of the cross origin image.
What I've found in my research so far:
- this question where the answer pointed to a great article that looked at it from the perspective of storing the uploaded image on a server.
- this question where the answer points out an interesting way to hide a script in an image I'd never seen before, but I'm not sure what vulnerability it creates if I'm not trying to extract a script from that image and run it.
- and this link which details a great reason why browser's choose to restrict access to image data for cross origin images. I always assumed it was just about protecting against malicious images, but now realize it also protects against much more.
None of the above have sufficiently approached it from the perspective of one user attacking another user through uploading an image (that doesn't stay as uploaded but instead gets converted to data url) that another user later downloads and views (with img src set to data url, not the malicious user's original upload). 2 is close to answering my question, but as I understand it, the detailed methods wouldn't work without the malicious user also having injected some script into the viewing user's browser.
To go along with this question is an example of what I would like to do including the file uploading/conversion to data url along with a sample data url to try out the importing (this sample url is safe to import and small so it imports quickly):
window.onload = function() {
document.getElementById("convert").onclick = convert;
document.getElementById("import").onclick = importF;
let imageLoader = document.getElementById("imageLoader");
let canvas = document.getElementById("imageCanvas");
let ctx = canvas.getContext("2d");
imageLoader.addEventListener('change', e => {
let reader = new FileReader();
reader.onload = (ee) => {
loadImage("imageCanvas", ee.target.result);
}
reader.readAsDataURL(e.target.files[0]);
}, false);
};
function loadImage(id, src) {
let canvas = document.getElementById(id);
let ctx = canvas.getContext("2d");
let img = new Image();
img.onload = () => {
canvas.width = img.width;
canvas.height = img.height;
ctx.drawImage(img, 0, 0);
}
img.src = src;
}
function convert() {
let canvas = document.getElementById("imageCanvas");
console.log(canvas.toDataURL());
}
function importF() {
let imageImport = document.getElementById("imageImport");
let url = imageImport.value;
loadImage("imageCanvas", url);
}
<label>Upload Image:</label>
<input type="file" id="imageLoader" name="imageLoader"/>
<br/>
<label>Import Image:</label>
<input type="text" id="imageImport" name="imageImport"/>
<br/>
<label>Sample URL:</label>
<code style="user-select: all;"> data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAOCAYAAAAmL5yKAAAApUlEQVQ4T2NkQALyKu5GjP8Z01kZ/1n/+s+kjSyHi80Ik1BQdvf4z8C4nYPx/z819t9M+py/GRj+MzAwgFTgocEGyCl75DEyMEz04f3OEC34lUGY+R8xloPVMMopeTgzMjLsMeb8xdAu8YFojTCFjPJKblNlWf+lTpV5z8rBCHIraYBRQ9Xtoi3XL70S0U+k6YSqZpRX9vgfK/CVIVbw66gBIzcMAHB4Ryt6jeYXAAAAAElFTkSuQmCC </code>
<br/>
<button id="import"> Import from URL </button>
<button id="convert"> Convert to URL </button>
<br/>
<canvas id="imageCanvas"></canvas>