It's a standard side-channel attack, relying on rendering differences among individual browsers. As the linked paper by Acar et al (which is only 16 pages long and easy reading) notes, things like browser type and version, installed fonts, graphics hardware, and OS settings affect the rendering at the pixel level.
So you put a script on your page that creates a Canvas object, draws some text in it, converts the resulting bitmap into Base64-encoded data, and hashes that Base64-encoded string. That hash is the fingerprint. In practice the collision rate is low enough that it is a strong contribution toward a unique client identifier.
Section 3 of the Acar paper has some additional details. It's mostly about how they detected canvas fingerprinting, but the list of fingerprinting text strings in Table 1 is interesting, for example.
Like any side-channel attack, the only real defenses are blocking all related channels (so basically anything a script can use to query browser state) or whitening (adding noise to the data). Browser fingerprinting is an arms race and there's no reason to think the bad guys aren't going to continue to stay ahead.
But eventually we'll all move to IPv6 and every machine will be globally, uniquely, directly addressable, and none of that will matter.