What are security concerns around use of canvas.toDataURL? - javascript

What security threads would canvas.toDataURL generate in general? What measures we have to take to make use of it secure and thread free to our website?
In the following links there are discussions around security error that .toDataURL raises if the image is not hosted locally, but why is that?
canvas.toDataURL() causing a security error
Capture HTML Canvas as gif/jpg/png/pdf?

You may be aware of the same-origin policy. In essence, it's a security mechanism employed by browsers to make sure that only scripts that originate from the same site that the user is visiting are allowed to run without restrictions and access the DOM.
You could disguise a script as an image, for example you could store each group of 4 characters in the script in a pixel (one byte per channel), then read the pixels of that image to reconstruct the script.
This is why the same-origin policy applies to images too: if you draw images from a different domain into a canvas on your web page, there is a limit to what you can do with your canvas if you have drawn cross-origin images into it. For example, you can't inspect its pixels.
Now imagine that you could use canvas.toDataURL() to generate a data url from your cross-origin canvas. While your browser knows that your canvas contains cross-origin content, a data URL is just that: a URL. So there is no sure way of knowing that it has originated from a different domain in some way, and it could be potentially used to bypass the whole same-origin thing. As an example, you could create a new img and use the data URL as its src.

Related

Create a "Save As" userscript

The idea is quite simple in concept:
I would like to create a userscript that will let me press a button and save something on the page(most commonly and problematically images).
Note: A userscript is a script that is injected client-side(by browser extensions such as Tampermonkey and Greasemonkey) and is used to add functionality to a site.
To do so I merely need to call the saveAs() function and pass it the data.
The question then becomes how to I obtain the data.
Most approaches I've seen run into the situation where the resource is not of the same domain as the script perhaps?(not sure how this works).
Now, Tampermonkey(and Greasemonkey) have created a function to deal with this problem specifically - GM_XMLHTTPRequest, which can circumvent the need for proper CORS headers.
This however creates another request to the server, for a file that has already been downloaded.
My question is: Is there a way to not have to send secondary requests to the server?
Here is a chronicle of my efforts:
From what research I've managed to do, you can create a canvas and draw the image in there. However this "taints" the canvas, preventing it from running functions that extract that data(such as .toBlob() or .toDataURL()).
CORS offers 2 mechanisms as far as I understand it: Setting the proper HTTP headers, which requires control of the server, and a special attribute that can be put on HTML elements: crossorigin
I tried adding this property post-load and it won't work, you still get a tainted canvas.
Tampermonkey offers several different options on when to run the script. So the next idea was to run when the DOM is loaded, but the resources haven't yet been fetched. It seems the earliest this is possible is document-end(earlier the getElementById call returns null). However this currently returns an error when loading the image on the page(before any other additional code is run):
Image from origin '...' has been blocked from loading by Cross-Origin Resource Sharing policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin '...' is therefore not allowed access.
There's also the --disable-web-security flag in Chrome, but I'd rather not go there.
No, there is no way to do it without a new request to the server.
When the first request is made, the image is marked as unsafe by the browser, and will then block a few features, like canvas' toDataURL, getImageData or toBlob, or in case of audio files, AudioContext's createMediaElementSource and AnalyserNode's methods and probably some others.
There is nothing you can do to circumvent this security, once it's marked as unsafe, it is unsafe.
You then have to make a new request to the server to get a new file from the server in safe way this time.
Commonly, you would just set the crossOrigin attribute on the media element before doing the request, and after the server has been properly configured to answer to such requests.
Now in your case, it seems clear that you can't configure any server where your script will be used on.
But as you noticed, extensions such as GreaseMonkey or TamperMonkey have access to more features than basic javascript ran from a webpage. In these features, there is one allowing your browser to be less careful about such cross-origin requests, and this is what the GM_xmlhttpRequest method does.
But once again, even extensions don't have enough power to unmark non-safe media.
You must perform a new request, using their less secured way.

HTML5 Canvas getImageData - Security Issue

I am building a web app which reads an image through the FileReader API, and then displays it on a Canvas. After that, I re-color the image by going pixel-by-pixel after making the .getImageData call on the canvas, as shown below:
// Color Image on Canvas
ctx = document.getElementById('my_canvas').getContext('2d');
var img_px = ctx.getImageData(0,0,canv_w,canv_h);
img_px = colorImage(img_px,red,green,blue);
ctx.putImageData(img_px,0,0);
colorImage() is a function I've written that changes the pixel values given a corresponding RGB color code, and it definitely does work. The above snippet of code does work when I am loading an image locally, but it does not when I try to access an image from an online server, like a public Dropbox account. Firefox is telling me it's a security issue; is there a way to get around it?
I believe that this is a Cross Origin Resource Sharing CORS (security) issue.
See HTML5 Canvas getImageData and Same Origin Policy
The gist is, requests to images from external domains could inherently supply the user's authentication cookies, etc, allowing your javascript to access their potentially protected images and assets. While you can reference them, via <img>, CORS was established as a security protocol to prevent you from programmatically reading (and perhaps storing) the pixel data.
The Dropbox API supports CORS as of mid August, 2012. You may be able to accomplish what you want using their API once users properly authenticate.
https://github.com/dropbox/dropbox-js/blob/master/doc/getting_started.md

Vintage.js: remote images

Plugin only applies filter to files on my server, but with remote images:
Unable to get image data from canvas because the canvas has been tainted by cross-origin data.
How to fix it?
The error you are receiving is part of the browser's built-in security mechanisms to prevent hackers from using remote data to manipulate sites. You can't get around it (and if you could, it would be a major security hole that the browser makers would be very quick to fix)
To confirm this, the same question has already been asked on the Vinatge.js website (as a github issue ticket), and the answer given by the Vinatge.js author was that it isn't possible to load remote images.
Sorry to disappoint you.
The work-around given was to use a proxy loader on your own server to load the images so that they are not given to the site as remote images.
In some cases, it may in fact be possible. It is possible for the remote server to be configured to allow it. However this configuration would need to be done on the remote server, so if you don't have access to that then the problem remains.

canvas.toDataURL Alternative?

I'm trying to convert an the contents of an HTML5 canvas to a png image.
Problem is that the canvas contains an image that isn't hosted locally so I get the security error.
I don't have the option to host the image locally, is there any other way to capture what is inside the canvas element?
Thanks!
Unless you can make your image resource CORS friendly, then no.
https://developer.mozilla.org/en-US/docs/CORS_Enabled_Image#What_is_a_.22tainted.22_canvas.3F
Although you can use images without CORS approval in your canvas,
doing so taints the canvas. Once a canvas has been tainted, you can no
longer pull data back out of the canvas. For example, you can no
longer use the canvas toBlob(), toDataURL(), or getImageData()
methods; doing so will throw a security error.
Edit: Of course, if you aren't limited to pure HTML5 methods, there are some Flash/Crossdomain.xml tricks you could use, but that still assumes you have some control over the server which serves the images.
If you're not opposed to using jQuery this plugin my do the trick.
http://www.maxnov.com/getimagedata/
Guess there is no way around that on the client-side otherwise what would be the point of blocking toDataURL anyway right?
Maybe you could have a server side script forwarding external images to the client so the browser won't know it's from another domain. (Not that it need to anyway since you can't use the browser's credentials from the server side)
Just send the image url as a get parameter, have the content-type header modified according to the image file, of course, and just spread all those bytes on the response content.

Frames with JavaScript

How can I manipulate using JavaScript (JQuery) a site, not in my server, that I loaded in a frame?
I'm afraid you can't. The Same Origin Policy prevents it.
The same origin policy prevents a document or script loaded from one origin from getting or setting properties of a document from another origin. This policy dates all the way back to Netscape Navigator 2.0.
the only conceivable workaround is to fetch the page through a proxy on your own web server, and do the JavaScript operations on that. This, though, will destroy any relative links on the page, and is therefore usually not a workable approach without a lot of work (fixing relative links, etc.)

Categories

Resources