How to properly waste your time using EGL
ChrisLaffra 060000KCEQ Comments (2) Visits (3103)
Today, I wrote a game in EGL Rich UI inspired by the well-known web game called "Escape", "Escapa", "The Red Box Game", or whatever name the latest inspired copier decided to give before hosting it on their own homepage. I am still trying to find out who really wrote the original.
Anyway, it looks like this:
The intent of the game is simple. You drag the red box labeled "EGL" around with your mouse. All you need to do is avoid the blue boxes and the walls.
How does the game work?
The game essentially consists of two parts: the UI that draws the boxes and let you drag the red box and a service component that can show the top 10 scores. I will describe the two parts in more detail now.
The main algorithm for this game is the following:
The blue boxes shown in the UI are positioned absolutely using a syntax like this:
By making the boxes positioned absolutely, we can place them at any place we want. For this box, the initial location is at x=300 and y=330.
Each time the game timer goes off, we move the blue boxes in a given direction:
For each blue box, we remember its x and y direction. For instance, when it bounces against the right wall, we make its x direction -1. The box is moved simply by giving it a new x and y coordinate. After moving the box, we check to see if we now touch the red box. If so, we stop the game.
The red box itself has drag and drop handlers define on it:
This allows us to start the game and drag the red box while the user moves the mouse:
Finally, when the game stops, we inform the user and display the top 10 scores:
Keeping a Top 10 List
Our top 10 list consists of a little bit of UI, and a service call to report the current score and receive an answer back with the total number of games played and the top 10 games.
The UI is nothing thrilling, other than using a cookie to remember your name:
That same cookie is updated when the user enters a new name, and stored in the browser's cookie jar. Next time the user returns, the stored value will be automatically picked up. Updating a cookie value is as easy as giving it a new value:
The service calls a REST service with 2 URL parameters. It returns a record with inside it an array of top scores. Notice from the definition below that it is not relevant if the service is using XML or JSON to encode its contents. The EGL runtime will determine at runtime how to parse the result.
The service definition looks like this:
To call the service, we use the EGL call statement identifying the service we want to call and what function we want to use when the response arrives in the future:
The top 10 scores are stored in a div that is given an opacity of 0.8, so it is a little bit transparent:
When the answer comes back from the top10 service it is converted automatically by EGL into a set of nested records and we simply add them to our top10 div. Finally, we show the top10 div in the right position:
Using PHP to implement the backend service
All the client code is done in EGL. I decided to place the game on an ISP where I took the cheapest plan available. The plan comes standard with PHP and MySQL. So, I decided to try and use MySQL and PHP to store the high scores to see how that worked.
The MySQL table structure is pretty simple:
I added and IP field to remember where the service came from (which is of course a very limited approach to authentication). I created the table using the phpMyAdmin client that my Internet provider offers.
Then I wrote some PHP and placed it right next to my game's index.html file. Here is what the (insecure) PHP looks like:
My PHP code is highly insecure for various reasons. First, anyone can simply call the URL above and assign any score they like:
Note that I added some sanity checks so that the above URL no longer works
Using a REST service with URL parameters makes it trivial to call in a browser. Tools like Rational AppScan know this and run a huge number of "worst practice" scenarios on a website to find holes like the one I inserted here.
Some ways of making service hacking more difficult would be:
Of course, obscuring thing stops the really silly hacks and even the accidental ones. However, as Andy Tanenbaum used to say when I was stil back in school attending his class on Operating Systems: obscurity is the worst form of security.
Always use SLL and proper authentication to increase security.
Securing the channel and authentication helps to a certain degree. In the end, however, services have to be extremely defensive, paranoid, trace everything, apply statistical analysis, and allow for easy human intervention. Think of your credit card company calling you on your cellphone to verify a suspicious transaction. Also, most comment sections on website have a button to report spam messages or abuse. Any system that runs over the Internet should be assuming the worst and be able to easily recover from abuse.
One special form of disruptive hacking is to try and make the service run arbitrary code on the hacker's behalf. In our PHP example shown above, we allow for SQL injection very easily.
Then main attack vector in our example is given here:
We retrieve $name and $score from the request URL, and compose a query out of it. If we pass in 'name=Chris' and 'score=32.351', the resulting query would be:
Now, assume someone passes the following parameters to the REST service:
Our query would then look like this:
As "--" starts a comment in SQL, the query now becomes the following two separate SQL statements:
By naively allowing any arguments to be passed to us we allowed random SQL code to be executed on our database. Hackers do not need access to the PHP to come up with this, as automated tools are available to try random fragments until they find one that works.
The simplest solution is to not allow for the script to insert the ';' character. Namely, without that the SQL injection cannot insert a second statement. To avoid further unintentional modifications to the original select statement, we can also check for the single quote character.
To help fight SQL injection, there is a simple PHP trick to sanitize URL parameters. It looks like this:
I added that to the PHP that is currently used by the published game.
In our sample above, we do not monitor client access, other than storing the IP address. Additional information may be collected and stored, such as host name, referer page, browser agent, timestamp, etc. Basically, you should record anything that may help the FBI solve your case once someone drained your server from all its data.
How to really solve security problems
Basically the advise is: Don't try this at home, kids!
Enterprise organizations should not use adhoc security models, of course. The recommendation is to use something like Tivoli Access Manager to control access to, and monitor, their services.
Furthermore, instead of using PHP, you should really write your services in EGL, compile them to Java, and run them on WebSphere, which is proven to be much more secure for Enterprise applications. Using EGL will also make it easier for you to write the service as you will not have to struggle with the quirky syntax of both PHP and MySQL.
To take a look at the client code yourself, download the following attachment and import it as an existing project into your workspace.