SkillAgentSearch skills...

HackerSpray

Repel hackers with this library by blocking brute force and malicious attempts on sensitive URLs

Install / Use

/learn @oazabir/HackerSpray
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

HackerSpray

HackerSprayLogo.png

A .NET library to defend websites and web APIs against brute force and Denial-of-Service attacks.

It comes as .NET 4 and .NET Core library.

Features:

  • Protect login, registration, password reset pages against brute force and DOS attacks.
  • Block users from performing any action too many times.
  • Prevent too many hits from any IP or IP Range.
  • Blacklist/Whitelist specific IP, IP range, username, URLs, transactions for a period.

An example scenario is a Bank Login page, where brute force password attempts on user accounts and DOS attack on Login page are a regular event. Using this library, you can protect login page from brute force attacks, blocking too many usernames from certain IPs, or too many hits from a range of IP trying to do DOS attack, or even simple 3 invalid login attempts per username, per 15 mins.

This high performance, very lightweight library protects you from hitting the database too many times on pages or APIs that are target for attacks, thus lowering web server and database CPU, increasing the scalability of the overall application.

Show me the speed

Let's compare the performance of a Login page which does authentication with a database.

Server throughput increase

When attack is going on and expensive .net code is getting hit, you get high CPU and low throughput. But as soon as HackerSpray starts blocking traffic, CPU on webserve goes down and server throughput shots high up.

Server%20throughput.png

Response time

When ASP.NET code is executing, response time is avg 36ms, as you see on the top 2 lines. But when HackerSpray is blocking requests, response time is low, at around 8ms.

Response%20Time%20Graph.png

Prevent code execution

When HackerSpray starts blocking requests, it blocks from HttpModule responding with Http Response Code 406. In the below graph, you can see when requests are getting blocked, Login code is no longer getting hit.

Response%20Code%20Graph.png

How it works

HackerSpray uses Redis to maintain high-performance counters for actions and origin IPs. You call Hacker.Defend(key, ip) to check if a certain key or IP has made too many hits. You can maintain blacklists for key, IP or IP Range. HackerSpray checks against too many hits on a key, too many hits on an IP, or IP falling within blacklists. It also allows blacklisting a certain key for a certain IP or blocking a certain key for all IPs on-the-fly. Handy when you want to block a user out of certain URLs.

It comes with a HttpModule, which protects your entire website.

Example calls:

var result = await Hacker.DefendAsync("/Account/LogOn", Request.UserHostAddress);
if (result == Hacker.Result.TooManyHitsFromOrigin)
    await Hacker.BlacklistOriginAsync(Request.UserHostAddress, TimeSpan.FromMinutes(10));
else if (result == Hacker.Result.TooManyHitsOnKey)
    await Hacker.BlacklistKeyAsync("/Account/LogOn", TimeSpan.FromMinutes(10));

.
.
.
Hacker.DefendAsync("/Account/PasswordReset", Request.UserHostAddress, TimeSpan.FromMinutes(5), 100);
Hacker.DefendAsync("Username" + username, Request.UserHostAddress);
Hacker.DefendAsync("Comment", Request.UserHostAddress);

HackerSpray is a fully non-blocking IO, .NET 4.5 async library, maximizing use of Redis pipeline to produce least amount of network traffic and latency. It uses the StackExchange.Redis client.

There's a convenient DefendAsync overload for ASP.NET Controllers. Here's an example how you can protect the Login() method:

[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
{
    if (!ModelState.IsValid)
    {
        return View(model);
    }

    return await Hacker.DefendAsync<ActionResult>(async (success, fail) =>
    {
        // This doesn't count login failures towards account lockout
        // To enable password failures to trigger account lockout, change to shouldLockout: true
        var result = await SignInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, shouldLockout: false);
        switch (result)
        {
            case SignInStatus.Success:
                return await success(RedirectToLocal(returnUrl));
            case SignInStatus.LockedOut:
                return await fail(View("Lockout"));
            case SignInStatus.RequiresVerification:
                return await success(RedirectToAction("SendCode", new { ReturnUrl = returnUrl, RememberMe = model.RememberMe }));
            case SignInStatus.Failure:
            default:
                ModelState.AddModelError("", "Invalid login attempt.");
                return await fail(View(model));
        }
    },
    blocked => new HttpStatusCodeResult(HttpStatusCode.Forbidden),
        "ValidLogin:" + model.Email, 3, TimeSpan.FromMinutes(5),
        "InvalidLogin:" + model.Email, 4, TimeSpan.FromMinutes(5),
        Request.GetClientIp()
    );
}

This DefendAsync allows you to wrap your existing Controller code with the defence. You put the existing code in your Controller methods inside the async (success, fail) delegate. Then while returning the response object, you wrap the return object with success() or fail(). HackerSpray will then maintain success and failure counters. If there are too many success or failed attempt as per the configuration, it will block further execution of the code inside the delegate, thus protecting your expensive business logic from attacks.

Why not use a firewall?

Couple of reasons:

  • Firewalls have no intelligence on what business transaction is being performed. Thus you cannot implement brute force check against transactions. It is either URL or IP.
  • If a firewall has to implement brute force attack detection, it has to read the whole payload and then inspect for patterns. This requires high CPU Á Memory usage on Firewall. In case of https, it requires you to terminate https at firewall level so that it can read the received data.
  • Most firewalls have basic scripting language to configure rules. Some do support javascript like language, but check the CPU cost of that and the price tag. With HackerSpray, you get .net code, so the sky is the limit.
  • Firewalls have limited storage for logs and shipping logs from firewall to analysis engines puts stress on the firewall, especially when you are under attack. Many a times we experience Firewall CPU exhaustion when it is blocking DOS, while it is writing all those attacks in a log and also shipping the logs to our analysis servers.

With that being said, you should use Firewall for certain cases and HackerSpray for different cases. You should use Firewall to limit maximum number of connections per IP, maximum number of connections opened to a webserver, rate limit, blacklisted IP and URLs. More than that, go for HackerSpray. It is better to perform CPU intensive operations at webserver level, because you have plenty of them. Usually you have only one active firewall and thus best not to put CPU intensive operation on them.

Getting Started

.NET 4

Get the HackerSpray library and HTTP Module to defend your website using:

Install-Package HackerSpray

It will do all the configuration to enable HackerSpray for your web project.

.NET core

For .NET Core, use:

Install-Package HackerSprayCore

It will do nothing to enable HackerSpray for your web project. You need to do the following:

Step 1: Add hackerspray.json in the configuration

{
  "HackerSpray": {
    "Redis": "127.0.0.1",
    "Prefix": "AuthTest-Core:",
    "Keys": [
      "POST /Account/Login 100 00:10:00 key+origin",
      "GET /Account/Login 100 00:10:00 key+origin",
      "GET /Home/ 10000 00:10:00 key+origin"
    ]
  }
}

On your Startup.cs, load this config file:

var builder = new ConfigurationBuilder()
                .SetBasePath(env.ContentRootPath)
                .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
Add this line--> .AddJsonFile("hackerspray.json", optional: true, reloadOnChange: true)
                .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true);

Step 2: Add the HackerSpray service in Startup.cs

public void ConfigureServices(IServiceCollection services)
{
    
    .
    .
    services.AddHackerSpray(Configuration.GetSection("HackerSpray"));
}

Step 3: Add HackerSpray middleware in Startup.service

Add app.UseXForwardedFor(); and app.UseHackerSpray(); right after UseStaticFiles() and before UseMvc();

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
    .
    .
    .

    app.UseStaticFiles();
    
    app.UseXForwardedFor();
    app.UseHackerSpray();

    .
    .
    .
    
    app.UseMvc(routes =>
    {
        routes.MapRoute(
            name: "default",
            template: "{controller=Home}/{action=Index}/{id?}");
    });
    
}

Run Redis server

If you have installed from Nuget, redis will be downloaded and stored in packages folder.

Configuring HackerSpray

In the web.config or hackerspray.json you need to specify which paths to protect using the HttpModule or Middleware:

<HackerSprayConfig redis="localhost" prefix="AuthTest:">
    <keys>
      <add name="/Account/LogOn/" post="true" maxAttempts="100" interval="00:10:00" mode="perkeyperorigin" />
      <add name="/Home/" post="false" maxAttempts="10000" interval="00:01:00" mode="perorigin" />
      <add name="/" post="false" maxAttempts="10000" inte

Related Skills

View on GitHub
GitHub Stars115
CategoryDevelopment
Updated8mo ago
Forks25

Languages

C#

Security Score

72/100

Audited on Jul 17, 2025

No findings