You can draw with different fonts and background colors, then grab the raw pixel values and hash them. The hash will be different depending on the versions of fonts installed, the OS, the GPU, the browser's text rendering algorithms, and the subpixel order/orientation of the display.
They should have standardized the font rendering for canvas. For those rare graphs using canvas i can live without Cleartype and only use normal anti aliasing, and with modern high DPI displays you hardly even need that in the first place anyway.
I mean, one of the major reasons for using canvas over DOM is to get pixel perfect placement of things, like text connecting to an arrow. If your fonts suddenly change size that won't work anymore. SVG has the same problem, on some computers with slightly larger letter spacing a line might become too long so it wraps and become two lines, totally spoiling the desired diagram.
There are many legitimate uses. Vendors have experimented with making canvas readback opt-in (with a popup) but I don't know if it'll ever ship because it simply breaks too many websites. Sometimes it's used at page load to generate variants of a single image to reduce file sizes, or used by games to prepare image assets before they start up.
Longer: this is actually a viable way to do many types of fingerprinting, not just canvas. I'll give an example. In a graphics class I took our professor gave us output images to compare to. Two people with the same model computer, same specs, would frequently have a pixel or two different from one another. Change the specs and you're easily a dozen off. Worse than that, the pixels that are off from the original image can be different pixels. This comes down to the silicon lottery. So if you can think of anything that you can access where you can get the user's computer to do some sort of floating point calculation, you can probably get a fingerprint out of that.
So to fix this problem, you'd have to figure out how not just to make pixel perfect images, but for two CPUs of different types (which even same type doesn't currently) to always calculate the save answer to the same precision, every time. There's tricks that can be done like rounding, but it gets hairy really fast and becomes unpractical. But if you do know how to solve the problem, I'm sure people would really appreciate the answer.
Random, probably uninformed thought: I wonder if the solution could be LESS determinism rather than more. If you could make it so the same hardware rendered pixels in a slightly different (random) way each time, it would no longer be possible to determine if you were looking at the same machine.
That's an interesting idea. It might be a good way to circumnavigate this problem. But there are some drawbacks. Maybe there's a lot of things we could get away with actually needing FP16 accuracy (like iterative methods can sometimes do this, especially in ML) but call FP32 but there's plenty of times where FP32 matters. So I guess it is highly dependent upon those issues and where you can get away with them. But further, how do you enforce that? I think it is interesting though.