Snapchat's (and now Facebook Poke's) main claim to fame is that it lets you send "self-destructing" image messages. Setting aside the debate about the uses of this beyond sexting, the key vulnerability in both apps is the built-in ability to take screenshots. Both take a reactive approach, where you're notified if the recipient took a screenshot, but can't really do anything about it.

I was thinking about ways of mitigating this issue, and figured that perhaps turning the image into an animation where individual frames are not (or at least less) recognizable would be the right path. This is a variant of temporal dithering, except we're intentionally pretending like each frame has a limited amount of precision, and only when averaged together is the original image re-created.

I've created a proof of concept (source) of this. It loads the image into a <canvas> and generates a "positive" and "negative" frame out of it. The positive frame has a random offset added to each pixel's RGB components, while the negative one has it subtracted. When displayed in quick sequence (requestAnimationFrame is used to do this every time the screen refreshes) the two offsets should cancel out, and the resulting image should re-appear.

Source

Temporal dithering1

Positive frame

Negative frame

The resulting flicker is unfortunate, but perhaps that only enhances the furtiveness of an image that will disappear in a few seconds. It also seemed fitting to include Lenna as a source image, given its origin.

Obviously this technique is meant to deter only casual attempts at screen capture. Beyond the analog hole, screen recording software (albeit not an issue on non-jailbroken iOS devices) can easily reconstruct the original image.

Potential areas of exploration are doing the offsets in a different color space (RGB is not linear) and using more than two frames. One option for generating more frames is to keep making random positive and negative pairs. That way repeated screen captures are less likely to yield a pair that can be combined to reconstruct the original image. Another option for generating more frames is to create three or more images that need to be averaged together to yield the original. However, that will result in more image degradation, since the frames are less likely to be perceived as one image; persistence of vision lasts for 1/25th of a second, which is between 2 and 3 frames at 60Hz.

The embedded example in this blog post is rendered as an animated GIF. Due to clamping of GIF frame rates, lack of precision (the delay is specified as an integer counting hundredths of a second) and guessing at the screen's refresh rate (it assumes 60Hz), it will exhibit even more flicker than the programmatic version.

21 Comments

I've used similar approach to protect CAPTCHA images before which was named "sparkle" for obvious reasons. Because the approach was too easy to counter, I came up with another approach named "peekaboo" which can also be applied to Snapchat-like applications.

Peekaboo works by displaying only a small circular area around mouse cursor or finger. To get the whole image, hacker has to record many images and stitch them together. Consider its voyeuristic nature to be a feature. ;-)

Great work guys. Someone creates a great proof of concept and all you can do is whine about possible workarounds.

Sure WE can work around this issue, but if I am sexting with someone who is a computeretarded they might not think of a work around. Even if they could, so what? Whining here about there being work arounds is like claiming that bike locks are useless because there are workarounds, they serve a certain purpose in making it more difficult to steal the bike. Same goes for this.

This is a fantastic ideas for online security companies who encounter people stealing security seal images and posting them on their site.

Think hackerproof or SSL secured seals that could easily be copied and pasted on another site. With this, it adds a painful step to overcome if you want to steal a seal image and post it on your own site.

Folks, remember, nothing is 100% fool-proof, but you need to think of making your content, product, or feature a little bit harder to steal than the rest of the competition to protect yourself.

Interesting idea. I think it will give people a headache though, unfortunately.

Another approach would be for the mobile OS makers to grant apps the right to disable screenshots, though I suppose that would open a pandora's box of copyright abuses (e.g. apps which suddenly don't allow users to make fair use of content).

Maybe time for a user script hiding anonymous comments by content regexp match, defaulting to /stupid|dumb|expletives/i; those are predictably very likely to just be junk noise.

I got curious if the animation jitteriness is easily fixed by making a requestAnimationFrame loop that flips the images and runs in full 60Hz, instead of whatever drives the animation now. Or is this already the case?

Johan: I already use requestAnimationFrame. Not sure why frames are occasionally skipped, very little work is done per-frame (for example, no JS objects are created or destroyed, so there should be no GC).

The jitter might be temporal aliasing, caused by the animation frame-rate running out of sync with the display device refresh rate. Native software can wait for a v-sync before drawing the next frame, thus latching the image switching speed to a stable frequency. The browser canvas element, however, seems to suffer from a lack of v-sync hooks.

A possible workaround: Create a double-buffer. Two divs, each contains a canvas, one pixelated variation image per canvas, setTimeout alternatively toggling div visibility. This should allow animation without canvas functions in the inner loop.

That's pretty much how it works now. The canvas is only used for image processing; it outputs into two img tags that are swapped between by changing their zIndex. The swap happens via requestAnimationFrame, which is supposed to track the screen's refresh rate. I can only assume that the flicker is caused by browser or graphics driver bugs; skipped frames are much more noticeable here than in the usual animation.

Is interpolation a useful addition to this?As far as the complaint that we're all picking the solutions apart, that's what hacking IS, and if you don't have an answer for a workaround that took three smart guys two days to come up with, then you don't have a robust enough concept to bring to market yet. To catch a thief, you must think like a thief, etc.