Search code examples
javascriptfirebasechecksum

How to protect against Firebase Request Forgery?


If you use Firebase real time database in browser you need to share the API key so there are no way to protect the database. I have simple game (ASCII Tetris) that save the high score of the game, the problem is that anyone can spoof the request and send his own score. (here is screenshot of what one person did):

ASCII Tetris Game

What are the solution to protect against this? I was thinking about doing the same as protection against CSRF where you create a token and validate if it's valid so only my code will have proper CSRF like token. The attacker would still be able to pause the app in debugger and check the token and send his own but this will require from him to know how to use debugger so it will be little bit harder to hack.

The firebase real time database have ".validate" rule where you can validate if token is valid (https://firebase.google.com/docs/database/security). I was also thinking of creating something like chain of checksums (like in git or block chain).

Do you think that something like this is possible to create? Do you know if there are better ways of protecting the firebase real time database for my case of saving scores? THe answer will probably be useful for other cases than simple case like mine for this simple game.


Solution

  • There's a surprising amount of complexity you can implement in Firebase's security rules. For example, I once saw rules that validated chess moves - pretty impressive.

    Mostly I'd recommend storing enough information to replay what happened, so that you can check if the result is valid. My first Firebase game was a word typing game, so I'd store:

    • The seed of the game
    • Each keypress and its timestamp
    • The total score

    This allows me to replay the game to check if I get the same result. But it also allows me to (in the future) write code that checks for irregular patterns in the keypresses. For example, my bots used to press a key at a very specific interval. Of course malicious users can easily make this more intelligent, but so can you improve your cheat detection code.

    Such cheat detection code should of course never be present in the client, as that would give malicious users information you don't want them to have. So you'd run this code in a trusted environment, such as you development machine, a server you control, or Cloud Functions.

    So my typical steps:

    1. Store the exact moves of the user, and the seed of your PRNG, so that you can reproduce the exact game.
    2. Use security rules to reject invalid moves as much as possible.
    3. Use security rules to reject outcomes that are extremely unlikely, like scores higher than a certain amount (especially when you can tie it back to how long the game took).
    4. Use server-side code to check if the moves the player made, lead to the result they got.
    5. Consider quarantining unusually high scores, so you can validate them with a replay before posting them to the score board. This would be a combination of client-side code, and server-side security rules.
    6. If you suspect abuse, inspect the list of moves. If this happens regularly, start automating this.

    Welcome to the arms race of game developers vs malicious players. :)