Lessons

Protecting your SWFs from prying eyes

Ok. So you’ve made a Flex application… Now what? You’ve got to deploy your SWF on a server somewhere, and give access to the world. The only problem with that is……..

THE WORLD HAS ACCESS TO YOUR SWF

A SWF is a compiled file and can thus be decompiled using applications like Sothink SWF Decompiler. Applications like these can take your SWF file as decode the binary data, hence allowing you to see most of the source code contained therein. Flex apps are slightly more difficult to hack – as there is just so much more code than a plain old file made in Flash – but nonetheless, it can be done.

There a few ways to protect your SWF file and the data contained therein, but none of them are really hack-proof (and i’m sure my idea isn’t hack-proof either, but i see no easy way around it).

One highly obvious security tip is to keep all sensitive data out of your SWF. Rather store keys, codes and digests in your server-side scripts.

However, that only protects the data in your SWF, not the intellectual property (ActionScript logic, embedded images, etc). I had a brainfart last night about how to do this, and i figured it out this morning: let’s think about it… How do people access files on your server? They can access them if your files are in your webroot (public_html folder or /var/www). However, all files outside the webroot are not visible on the web.

So i got to thinking… How can i load a SWF at runtime from outside the webroot while fooling both the browser and the application into thinking that it is sitting in the webroot? Well, i managed this with PHP and got a few nice surprises. See the files below (i used this SWF in my last post and i was too lazy to make a new one):

Get Adobe Flash player

Get Adobe Flash player

The SWF on the left loads another SWF securely, while the one on the right loads a SWF as one normally would – via a relative or absolute link.

To actually see whether or not the SWF is being seen by the browser (i.e. via a GET request), try using the Net Monitor of Firebug. The SWF on the right – once clicked will force the browser into making a GET request while the one on the left will not. How’s this accomplished?

Well, it’s all about the PHP. See the script below:

1
2
3
<?php
	echo base64_encode(file_get_contents("/home/riacoder/etc/SWF/menu.swf"));
?>

If you navigate to http://ria-coder.com/blog/wp-content/uploads/2009/03/loader.php, you will see a bunch of nonsense being printed to the page. This is actually the base64 data of the menu.swf file, located outside my webroot, but there’s a copy of it here. As you can see in my PHP code, i have done is pointed PHP to the the menu.swf file located somewhere on my server (outside the accessible range) and i’m getting the file contents of the SWF (compiled binary data) and encoding it in base64 format.

In the ActionScript below, i am decoding the base64 data back into binary data and then returning those bytes.

1
2
3
4
5
6
private function loadSWF(base64String:String):ByteArray
{
	var decoder:Base64Decoder = new Base64Decoder();
	decoder.decode(base64String);
	return decoder.toByteArray();
}

You can download the files used in this tutorial here.

*** UPDATE: Serge Jespers (www.webkitchen.be) has informed me that this method is not infallable, as anybody could decompile the container SWF (the SWF from which you’re calling the PHP), find the link to your PHP script, decode the base64 data, and then write the bytes to a file – thus obtaining your SWF. Even though this method is not hack-proof, it’s still an extra deterrent and i’d recommend your using it nonetheless if you feel it’s worth the extra effort.

A tip on using the Image component in Flex

At some time in the future – if you’re using the <mx:Image> component in Flex – you will need to listen for an event that will signal the load completion of an image’s source. The Event.COMPLETE function doesn’t work, so you’ll have to use the FlexEvent.UPDATE_COMPLETE function. This will do exactly the same thing as using the Loader class, and using the following code: loader.contentLoaderInfo.addEventListener(Event.COMPLETE…).