Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

120
Visualizações
Prevent malicious users from abusing and spamming unauthenticated open APIs

Here's a security problem I've encountered a couple of times when building small web-based projects interacting with a REST API service. For example, let's say you're building a casual JavaScript-based game where you want a leaderboard of highscores, so you need to post the scores of users to a database.

The easiest solution would be to build a simple web service, e.g. using PHP, Node.js or Python, that accepts GET request and saves the results to a database. Let's imagine the API looks something like this:

GET https://www.example.com/api/highscore?name=SuperGoat31&score=500

Creating such an API for posting highscores has some obvious drawbacks. A malicious user could write a three-line piece of PHP code to spam the database full of false results, for example:

for ($i = 0; $i < 100; i++) {
    file_get_contents("https://www.example.com/api/highscore?name=SuperGoat31&score=5000000");
}

So, I'm looking for a way to prevent that. This mostly relates to small hobby or hackathon projects that just need some kind of protection that will prevent the most obvious of attacks, not large enterprise applications that need strict security. A couple of things I could think of:

1. Some form of authentication

An obvious way to solve this would be to have user accounts and only allow requests from logged-in users. This unfortunately has the drawback of putting up a large barrier for users, who need to get an account first. It would also require building a whole authentication workflow with password recovery and properly encrypting passwords and the like.

2. One-time token based protection

Generate a token on the server side and serve that to the user on first load, then only allow requests that serve that specific token. Simple enough, but also very easy to circumvent by finding the requests in a browser web inspector and using that for the three-line PHP script.

3. Log IP address's and ban when malicious use happens

This could work, but I feel it's not very privacy friendly. Also, logging IP addresses would require GDPR consent from users in Europe. Also doesn't prevent the actual spamming itself so you might to first clean up the mess before you start banning IP addresses.

4. Use an external service

There are services that provide solutions to this problem. For example, in the past I've used Google's reCAPTCHA to prevent malicious use. But that also means integrating an external service, making sure you keep it up to date, concerns about the privacy aspects (esp. regarding a service like reCAPTCHA), etc. It feels a bit much for a weekend project.

5. Throttle requests

I feel this is probably the easiest solution that actually works for a bit. This does require some form of IP address logging (which might give the problems stated in 3), but at least you can delete those IP addresses pretty quickly afterwards.

But I'm sure there are other methods I've missed, so I would be curious to see other ways of tackling this problem.

about 4 years ago · Juan Pablo Isaza
3 Respostas
Responde à pergunta

0

Taking into account all mentioned limitations, I would recommend using a combination of methods:

  1. Simple session authentication based on one-time token
  2. Script obfuscation
  3. Request encryption with integrity control

Example:

let req_obj = {
  user: 'SuperGoat31',
  score: 123456,
  sessionId: '4d2NhIgMWDuzarfAY0qT3g8U2ax4HCo7',
};
req_obj.hash = someCustomHashFunc(JSON.stringify(req_obj));
// now, req_obj.hash = "y0UXBY0rYkxMrJJPdoSgypd"

let req_string = "https://www.example.com/api/cmd?name=" +
                 req_obj.user +
                 "&data=" +
                 Buffer.from(JSON.stringify(req_obj)).toString('base64');

// now, your requests will look like that:
"https://www.example.com/api/cmd?name=SuperGoat31&data=eyJ1c2VyIjoiU3VwZXJHb2F0MzEiLCJzY29yZSI6MTIzNDU2LCJzZXNzaW9uSWQiOiI0ZDJOaElnTVdEdXphcmZBWTBxVDNnOFUyYXg0SENvNyIsImhhc2giOiJ5MFVYQlkwcllreE1ySkpQZG9TZ3lwZCJ9"

For casual players, this allows start playing very quickly, as no explicit registration is required. Upon generation, token might be saved as cookie for repetitive use, but this is not necessary, single-time use would also suffice. No personal info gathered.

However, if short-term storage of some client information is an option, the token might be not just some random bytes, but an encrypted string, containing some parameters, such as random salt + IP address + nickname + agent id + etc. In this case you may start silently ignore certain requests from fraudulent clients upon detection.

Obviously, this would be very easy to crack for a professional, but this is not our goal. When such simple methods are mixed with several kilobytes of logic of the game and obfuscated, figuring out how to deal with it would require significant amount of knowledge and time, which might serve as a sufficient barrier.

As it is all about balance between convenience and protection, you may implement some additional scoring logic to detect cheating attempts, like final score cannot end with '0', or cannot be even, etc. This would allow you to count cheating attempts (in addition to counting forged requests) and then estimate efficiency of implemented combination of methods.

about 4 years ago · Juan Pablo Isaza Relatório

0

Your list of solutions are mostly mitigations, and they are good ideas if they are your only tools. The list seems pretty exhaustive.

2 major ways to actually solve this problem are:

  1. Remove the incentive of cheating. There's no point submitting a fake score if you are the only person who can see the score. Think about the purpose of why you even want a global high-score list. Maybe there's another way you can reach your objective that makes it uninteresting (or undesirable) to cheat.
  2. Have the server completely manage (or duplicate) the game state. You can't cheat if the server calculates the score. For example, if you're modelling a chess game the server can compute every valid move, preventing clients from submitting moves that wouldn't be possible.

It's possible that for your specific case neither are possible, but if you can't adopt either of these strategies you are stuck to imperfect detection mechanisms.

about 4 years ago · Juan Pablo Isaza Relatório

0

I suspect that a perfect solution will be elusive because two of your wishes are, perhaps, contradictory:

"You need to post the scores of users to a database" but... "prevent the most obvious of attacks" without "Some form of authentication."

The most obvious of attacks are those from users without some form of authentication.

You wish this system to work without placing an undue burden on your users. You wish to avoid the usual login and password authentication which can be cumbersome for users.

I think there is a way to accomplish what you want by creating a very simple form of authentication by the use of a one-time token based protection. And I would also incorporate IP tracking against abuse. In other words, let's combine your options 1 and 2 and 3 in the following way.

You already have implied that you will maintain a database, and that within the database, user names will be unique (otherwise you couldn't record unique high scores). Let people sign up freely by submitting their requested user name, which you'll accept if not already used by someone prior. Track the sign-up requests by IP address to detect and prevent abuse: too many sign-ups from one IP address within a given timeframe. So far, the burden is all at the server end, not on the user.

When you process a valid sign-up (i.e. new user name) into the database, you will also generate, record into the database, and return to the user a shared secret (a token) that will be used by the Time-based One-time Password (TOTP) algorithm.

Don't reinvent this.

See:

  • Time-based One-Time Password
  • FreeOTP
  • OneTimePass

When you return a token to the user, it will be in the form of a "QR Code"

QR code

which the user will scan and store with his "Google Authenticator" or equivalent TOTP application.

When the user returns to your web site to update his high score, he will authenticate himself using his Google Authenticator" or equivalent TOTP application. These are often used for "second factor" authentication, 2FA (Multi-factor authentication), but because of your need for less strict security, you'll be using the TOTP authentication as the primary and only form of authentication.

So we have combined a form of authentication which doesn't place a very high burden on the user (apps already widely available and in use), with one-time token based protection (provided by the TOTP app) and a little bit of IP address-based abuse protection for the initial sign-ups.

On of the weaknesses of my proposal is that a user may share his TOTP token with another person, who may then impersonate him. But this is no different from the risk of password sharing. And there will be no "recover my lost password" option.

about 4 years ago · Juan Pablo Isaza Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda