Problem:
Flash forms are very vulnerable to attacks. Spiders may not be able to easily iterate through your Flash content but they can sure spam your form submission URL. How can you be sure your form was submitted through Flash?
Definition:
A CAPTCHA or Captcha is a type of challenge-response test used in computing to ensure that the response is not generated by a computer.
Solution:
What if we have a user drag a circle onto a box? A spider would have a pretty hard time with that, right? WRONG. While this may be a good filter at the view level it still does not solve our problem. All the hacker would need to do is submit the form correctly one time and use a program like Firebug to sniff the submission URL. They could then completely bypass your view and submit the form as many times as they want.
The only way to ensure the Flash form is being used is to pull the logic out of the view and onto the server. The Flash merely serves up content and never knows what the ‘answer’ is. In this example we will use PHP to generate the image, MySQL to store the key value pairs, and Flash to display the content. This implementation does not require any images to be stored on the server so it NEVER re-uses an existing image. The PHP generates the image on the fly and serves it directly to the Flash application.
Here is a diagram representing the high level information. Blue lines represent Captcha generation and the red lines represent the Captcha verification.
Let’s start with the PHP. There are already plenty of PHP scripts out there to generate Captcha. In this example I re-purposed a script called Securimage.
First we need a script that will retrieve the image:
<?php $flash_id = $_GET['flash_id']; include 'securimage.php'; $img = new securimage(); $img->show($flash_id); // alternate use: $img->show('/path/to/background.jpg'); ?>
Next we will need one that verifies the user input with the image:
<?php $flash_id = $_GET['flash_id']; $captcha_text = $_GET['captcha_text']; if ($flash_id && $captcha_text){ $con = mysql_connect('localhost', 'DB_USERNAME', 'DB_PASSWORD'); if (!$con) { die('Could not connect: ' . mysql_error()); } mysql_select_db("utils", $con); $result = mysql_query("SELECT * FROM captcha WHERE flash_id = '".$flash_id."'"); $match = 0; $valid = 0; $answer = "false"; while($row = mysql_fetch_array($result, MYSQL_ASSOC)) { if($row['valid'] == 1) { $valid = 1; if($row['captcha_id'] == $captcha_text){ $match = 1; $answer = "true"; } } } if($valid == 1){ mysql_query("UPDATE captcha SET valid = '0' WHERE flash_id = '".$flash_id."'"); } echo $answer; mysql_close($con); } ?>
Now that we have the PHP in place we can create the Flash. The display logic is separated from the view so you can re-use this code with any server side script. The Captcha class requires an ID and a URL to the image to display. It has optional styling parameters to match the look and feel of your webpage.
Generating a Captcha in Flash:
// Create a Captcha object _captcha = new Captcha( ); // Create a unique ID so the server can identify the Flash var date:Date = new Date(); var id:String = "" + Math.floor(Math.random()*1000) + date.time; // Pass in the url along with the ID so the Captcha can load _captcha.loadCaptcha("http://www.blackcj.com/utils/securimage_show.php?flash_id=" + id, id);
Verifying a Captcha in Flash:
var loader:URLLoader = new URLLoader(); loader.addEventListener(Event.COMPLETE, formSuccess, false, 0, true); var request:URLRequest = new URLRequest("http://www.blackcj.com/utils/check_captcha.php?flash_id=" + _captcha.id + "&captcha_text=" + _text.text); loader.load(request);
Flash Demo and Source:
(click the image to manually refresh the captcha)
Full source code for Flash & PHP can be found here.
In the source code you will need to replace DB_USERNAME and DB_PASSWORD with your username and password. This example also requires a MySQL database with a table called captcha containing rows flash_id, captcha_id and valid. Valid is used to ensure the Captcha is only submit one time. Since we are always generating a new image there is no reason the Captcha should be allowed to be submitted twice with the same id.
Next Steps:
Additional steps could be taken to prevent robots. Failure rates and number of attempts could be stored for each IP address. No human should ever attempt to re-submit an old Captcha since each time it is randomly generated. The system could block anyone that attempted to re-submit a Captcha.
I would eventually like to make this accessible by integrating audio support. This is a feature of Securimage and would make the utility more versatile.