This has been debated *eternally* in game circles since the advent of
networked games, and I've followed these discussions for at least the
last decade. The conclusion is always the same and is not disputable:
in a broad-based, open competition (such as a web-based game for
prizes, e.g. a casino website) you *absolutely* cannot trust the
client no matter how many layers of encryption (which is designed for
and protects against man-in-the-middle attacks) and obfuscation (which
only slows, not stops) you apply.

Sure, those are a lot of suggestions for "whacky" obfuscation
techniques (the statistical stuff is not useful as Tom pointed out),
but ultimately that only slows. And really, if you're going to use
obfuscation *please* invent your own, otherwise it's ineffective as
obfuscation. Built it out of standard pieces (MD5 hashes, time
windows, etc.) to make the implementation easier -- because you'll
have to change it eventually.

With the web, if you have a game that's at all popular *and* has a
prize worth cheating for (or rather, worth *preventing* cheating for),
then your energy is best spent trying to (a) work out *some* way to
validate a score server-side that doesn't involve *trusting* the
client, and (b) plugging in an obfuscation system that can be swapped
out trivially and routinely.

If security is *critical* then you'll need to run all the
score-affecting logic on the server as I outlined earlier. If security
is merely *important* and/or it's not possible to run all the logic on
the server (such as an action game), then I'd go with a variation on
the rotating, randomized obfuscator module I outlined earlier. Here's
a variation on that:

1. Break out all of the score-centric game logic into an independent
module (SWF). Make sure that anything that can affect the score
(timing included!) is contained in that SWF. Hopefully this SWF will
be fairly compact (it won't contain art assets or a lot of UI code,
nor should it require any Flex framework stuff, etc.).

2. Write an obfuscation algorithm (encryption, hashing, shuffling,
zipping, ROT13, whatever...). In fact, write as many as you can (I'd
recommend at least a dozen). You'll need to create server-side
equivalents of these as well (to verify the results).

3. Compile one version of your scoring SWF for each obfuscation algorithm.

4. For each scoring SWF, run it through something like SWFEncrypt to
complicate decompiling as much as possible. It's not perfect, but
it'll lower the number of script-kiddies out there who can attempt to
crack it.

5. When the game loads up on the client-side it needs to connect to
the server when a new game is started (not a new session, but each new
game, i.e. each time the score is reset to 0). The server logs the new
game starting, selects one of your obfuscation algorithms, assigns it
a randomly generated unique ID, and passes it back to the client. Even
better -- and I don't know if this is possible, but it *should* be,
don't use SWFEncrypt on the scoring SWF until right before you send it
to the user and have SWFEncrypt use a different seed value for its
obfuscation; this ensures that the SWF's checksum (or any other
fingerprinting the user could do on the SWF) can't be used to detect
repeats in the selected scoring SWF.

6. The client uses the scoring module for the duration of their game.
At the conclusion of the game, the scoring system returns its
obfuscated result back to the server.

7. The server receives the response, looks up which obfuscation
algorithm was used for that client (based on the unique ID generated
in step #5), and it decodes the result.

This method has several advantages:

- The client can't prepare ahead of time to fake the obfuscation
because it's randomly selected and (ideally) unrecognizable in binary
form (CRC of the SWF, etc.).

- The hacker's only recourse is to attempt and reverse-engineer the
SWF during the game time window. If you've got a game that can't be
run on the server because it's too "real time" then it's likely your
time window is going to be small enough that reverse-engineering isn't
feasible.

- If the hacker hammers your server trying to collect all of the
possible obfuscation algorithms, you can attempt to only send a random
sub-set of your algorithms to any given IP to prevent/slow the hacker
from sharing their results. Ideally, you would SWFEncrypt on the fly
with a random seed so that the hacker would have to invest a large
amount of time not only determining which obfuscation algorithm each
"new" scoring module used but how many scoring modules there are in
total (which, without the random seed or IP subsets would be possible
without reverse-engineering).

Troy.

Reply via email to