10

I'm looking to prevent a DDoS attack on a web service, by making the cost of performing an attack prohibitive. Typical users will only need to call out it once a day, and can afford to spend a few CPU cycles on each call, but I want to make it so an attacker making millions of calls would have spend considerably more than I do hosting the service. There's an inherent cost to the service, so I'd like a "proof of work"-like system where I can know the caller has done a specific amount of computation, and can validate that work for cheaper than it costs them.

The message we sign would be something like a timestamp+nonce. On the server side we validate timestamp is fresh, and nonce isn't reused.

Something like bcrypt has the nice property in that it's designed to be costly, has a sliding cost scale, and is intentionally not easy to optimize in hardware. However, there would be a symmetric cost on my side which is a dealbreaker.

Something like RSA signing seems good, the cost to sign is much much greater than the cost to validate*. However, I'm not sure if it's possible to hardware accelerate RSA, and if you could the protection goes out the window. I want an algorithm where the cost/work is an intentional feature, not a byproduct.

Edit: lots of people are suggesting traditional ways to mitigate DDoS attacks. These are great, and are the best first line of defence for traditional services. I'm adding a more detailed explanation of why I'm asking specifically about POW:

  • This service is anonymous, with no user account/cookies/etc
  • This isn't user facing (no captcha, signups, etc)
  • Serving a valid request is somewhat expensive (computationally) so cheaply rejecting invalid requests before processing will save us significant resources (making the service more resilient to DDoS attacks).
  • We want to change the economics of the equation: if we make abusing our service more costly than just hosting your own version, then it's not likely to be abused. The service is something anyone could clone, they will just abuse ours to save cost/compute.
  • We want to avoid central databases/state-storage as these are typical points of failure/cost in attack/abuse scenarios (and a source of complexity). A "cheap validation" that can be run on cheap and horizontally scaleable edge compute is ideal.

*Source: https://www.fastly.com/blog/is-it-time-for-ecdsa-certificates

scosman
  • 203
  • 1
  • 8

5 Answers5

21

The immediately obvious solution would be to do a simple proof-of-work scheme. For example:

  • The server selects two random bitstrings $A$ and $B$, and computes $\text{Hash}(A || B)$.

  • The server sends $B$, $\text{Hash}(A || B)$, and the length of $A$.

  • The client does a search for $A$; when it finds it, it sends it

  • The server validates it.

This is obviously cheap on the server side, and can be made arbitrarily expensive on the client side (by adjusting the length of $A$).

Now, as written, it is vulnerable to be accelerated by a GPU. That can be partially addressed by picking a memory intensive (but otherwise cheap) hash function.

BTW: to answer a question you asked:

However, I'm not sure if it's possible to hardware accelerate RSA

It is certainly quite possible - hardware RSA accelerators are available (and have been for decades).

poncho
  • 154,064
  • 12
  • 239
  • 382
3

I think you can safely scrap proof-of-work if your typical pattern is users using the service once per day. Instead you should focus on traditional methods of rate limiting and abuse prevention. Some ideas:

  • require a CAPTCHA for each use of the service
  • if that's not possible, at least require an account and an unique API key
    • require social login for registration (google, github, facebook) - offload the hard work to services that have it figured out already
    • SMS verification, e-mail verification with whitelisted domains to weed out temp mails
    • manually approving accounts, significant delay until account approval to demotivate the attackers
  • IP address insights - block proxies, tor exit nodes, data centers. Good residential IP addresses are quite expensive nowadays.
  • actively monitor bad traffic, block offending accounts, their IP ranges, browser fingerprints, etc.
Baruch
  • 31
  • 1
2

Why make things more complicated than necessary? Just have the server remember the last time the API call was allowed. If it's less than 12 hours ago, reject the call.

The attacker doesn't need to compute your expensive signature - he will just flood the server with wrong signatures, and make the server validate them, which costs the server more work than checking the current time.

1

I've implemented a PoW-based DoS protection PHP project some time ago. It meets the general requirement of the question, with a few caveats:

  1. it doesn't use nonce - because I believe massive number of request without valid proof might drain server storage due to large number of nonces,

  2. it uses cookies, which you need to prompt users for consent in some jurisdictions.

  3. You need to generate your own key for use in HMAC (which should be easy).

Project Link: https://github.com/dannyniu/powerhash

DannyNiu
  • 10,640
  • 2
  • 27
  • 64
0

The method I'd recommend is mutual-TLS (mTLS) authentication. Everyone's familiar with HTTPS and TLS certificates, which prove the identity of the server. Mutual TLS sets up the client to have a TLS certificate as well, so they can prove their own identity.

The idea here is that you can have your load balancer or web server validate the client's certificate before the request ever gets to your code. This "pushes security to the left" about as far as you can go.

If a client does not have a valid certificate[*], then redirect them to a sign-up page that takes a long time to load. There used to be a <keygen> element for HTML forms that would generate a public/private key pair, but now cryptograph primatives are handled by the Webcrypto API. For more on the subject, see "How we built Origin CA: Web Crypto" (from the CloudFlare Blog), and the Chromium layout tests for the Webcrypto API. Working example: FreeSSL.Tech.

After that's in place, you can rate-limit individual users and anonymous folks to whatever rates you please.

Footnote:

[*] Make sure to configure your server to only accept certificates that it has signed. If you don't remove the default CAs, then anyone with (e.g.) a free Let'sEncrypt certificate can get through.

PFudd
  • 103
  • 1