In this page we present a few ways to mitigate DoS attacks currently. All these approaches can be combined. However there is no single one-size-fits-all solution for this problem at the moment. Defending a site under attack requires creativity and a custom-tailored approach.

An overview of implemented defenses at the tor daemon is given in the Overview section from the Denial-of-service prevention mechanisms in Tor specification, and here we give some practical tips.

Rate limiting at the Introduction Points

Since Proposal 305 was implemented, some torrc options were added to help mitigating DoS attacks at the introduction points:

  • HiddenServiceEnableIntroDoSDefense: Enable DoS defense at the intropoint level. When this is enabled, the rate and burst parameter will be sent to the intro point which will then use them to apply rate limiting for introduction request to this service.

  • HiddenServiceEnableIntroDoSBurstPerSec: The allowed client introduction burst per second at the introduction point. If this option is 0, it is considered infinite and thus if HiddenServiceEnableIntroDoSDefense is set, it then effectively disables the defenses.

  • HiddenServiceEnableIntroDoSRatePerSec: The allowed client introduction rate per second at the introduction point. If this option is 0, it is considered infinite and thus if HiddenServiceEnableIntroDoSDefense is set, it then effectively disables the defenses.

For more information on how they work, check the tor(1) manpage and the Denial-of-Service defense extension (DOS_PARAMS) section of the Onion Services v3 specification.

Proof of Work (PoW) before establishing Rendezvous Circuits

A Proof of Work (PoW) defense mechanism is explained in length at the PoW FAQ, and can be configured for each Onion Service with the following torrc options:

  • HiddenServicePoWDefensesEnabled: Enable proof-of-work based service DoS mitigation. When enabled, tor will include parameters for an optional client puzzle in the encrypted portion of this hidden service's descriptor. Incoming rendezvous requests will be prioritized based on the amount of effort a client chooses to make when computing a solution to the puzzle. The service will periodically update a suggested amount of effort, based on attack load, and disable the puzzle entirely when the service is not overloaded.

  • HiddenServicePoWQueueRate: The sustained rate of rendezvous requests to dispatch per second from the priority queue.

  • HiddenServicePoWQueueBurst: The maximum burst size for rendezvous requests handled from the priority queue at once.

The following global option is applicable to both onion services and their clients:

  • CompiledProofOfWorkHash: When proof-of-work DoS mitigation is active, both the services themselves and the clients which connect will use a dynamically generated hash function as part of the puzzle computation.

PoW is enabled by default on C Tor versions 0.4.8.1-alpha onwards (but can be disabled if compiled with --disable-module-pow). Basic PoW support can be checked by running this command:

tor --list-modules
relay: yes
dirauth: yes
dircache: yes
pow: yes

If you have pow: yes, then you have the PoW defense mechanism built into C Tor.

Due to license requirements, the PoW v1 client puzzle libraries (Equi-X and HashX by tevador, both under the LGPL-3.0) are enabled only if tor is compiled with --enable-gpl. This can be confirmed by running the following command:

tor --version
Tor version 0.4.8.3-rc.
This build of Tor is covered by the GNU General Public License (https://www.gnu.org/licenses/gpl-3.0.en.html)
Tor is running on Linux with Libevent 2.1.12-stable, OpenSSL 3.0.9, Zlib 1.2.13, Liblzma 5.4.1, Libzstd N/A and Glibc 2.36 as libc.
Tor compiled with GCC version 12.2.0

If your installed C Tor does not have PoW enabled or is not built with GNU GPL support, then you'll have to look for other packages or compile it yourself.

Stream limits in the established Rendezvous Circuits

The following configuration options can be used to limit connections in the rendezvous circuits:

  • HiddenServiceMaxStreams: The maximum number of simultaneous streams (connections) per rendezvous circuit. The maximum value allowed is 65535. (Setting this to 0 will allow an unlimited number of simultaneous streams.)

  • HiddenServiceMaxStreamsCloseCircuit: If set to 1, then exceeding HiddenServiceMaxStreams will cause the offending rendezvous circuit to be torn down, as opposed to stream creation requests that exceed the limit being silently ignored.

Onionbalance

Onionbalance allows Onion Service operators to achieve the property of high availability by allowing multiple machines to handle requests for an Onion Service. You can use Onionbalance to scale horizontally. The more you scale, the harder it is for attackers to overwhelm you. Onionbalance is available for v3 Onion Services.

Webserver rate limiting

If attackers are overwhelming you with aggressive circuits that perform too many queries, try to detect that overuse and kill them using the HiddenServiceExportCircuitID torrc option. You can use your own heuristics or use your web server's rate limiting module.

The above tips should help you keep afloat in turbulent times. At the same time we are working on more advanced defenses, so that less manual configuration and tinkering is needed by onion operators.

Caching

Another way to reduce the load on your service is to implement content caching, either directly at the backend application or by setting up a caching proxy frontend.

Client authorization or multiple onion addresses to compartmentalize your users

If you have users you trust, give them dedicated Onion Service and client authorization credentials so that it can always be available. For users you don't trust, split them into multiple addresses. That said, having too many onion addresses is actually bad for your security (because of the use of many guard nodes), so try to use client authorization when possible.

Captchas and cookies

If you need to further rate-limit users, split your infrastructure into layers and put Captchas near the frontend. This way attackers will have to solve Captchas before they are able to attack deeper into your infrastructure.

Captchas are a way to mitigate DDoS attacks. When a request comes from a client checks if the client contains the correct secure cookie otherwise redirects to the recaptcha page. The client inputs the captcha letters. Nginx sends this input letters to recaptcha server for verification.

The correct answer from recaptcha server with beginning of "true...", else it's beginning with "false...". Add the secure cookie for the correct verified client, redirect the client to the page which he wants to view.

It is possible to implement Captchas directly at your webserver with Nginx and OpenResty using Lua to generate and verify the captcha images. This implementation isn't easy to configure.

An alternative might be to just implement a test-cookie challenge. At your webserver check that clients can set valid cookies, malicious clients often do not have this feature. In Nginx, Cloudflare provide a library to interact with cookies.

Other methods include making sure that clients connecting to your .onion have valid User-Agent header and the Referer header is not set to a value you can associate with the attack.