public void TestOriginBlacklisting()
        {
            var key = GetRandomKey();
            var ip  = GetRandomIP();

            var interval = TimeSpan.FromMinutes(1);

            Assert.AreEqual(
                false,
                HackerSprayer.isOriginBlacklistedAsync(ip).Run(),
                "Origin must not be blacklisted");

            var startTime = DateTime.Now;

            HackerSprayer.BlacklistOriginAsync(ip, interval).Run();

            Assert.AreEqual(
                true,
                HackerSprayer.isOriginBlacklistedAsync(ip).Run(),
                "Origin must be blacklisted");

            WaitForIntervalToElapse(interval, startTime);

            Assert.AreEqual(
                false,
                HackerSprayer.isOriginBlacklistedAsync(ip).Run(),
                "Origin must not be blacklisted after expiration time");
        }
        public void TestKeyBlacklistingAndWhitelisting()
        {
            var ip  = GetRandomIP();
            var key = GetRandomKey();

            Assert.AreEqual(
                HackerSprayer.Result.Allowed,
                HackerSprayer.DefendAsync(key, ip).Run(),
                string.Format("Allow traffic on {0} from {1}", key, ip));

            HackerSprayer.BlacklistKeyAsync(key, TimeSpan.FromMinutes(5)).Run();

            Assert.AreEqual(
                HackerSprayer.Result.KeyBlocked,
                HackerSprayer.DefendAsync(key, ip).Run(),
                string.Format("Block traffic on {0} from {1}", key, ip));

            Assert.AreEqual(
                HackerSprayer.Result.KeyBlocked,
                HackerSprayer.DefendAsync(key, GetRandomIP()).Run(),
                string.Format("Allow any traffic from {1}", key, ip));

            HackerSprayer.WhitelistKeyAsync(key).Run();

            Assert.AreEqual(
                HackerSprayer.Result.Allowed,
                HackerSprayer.DefendAsync(key, ip).Run(),
                string.Format("Allow traffic on {0} from {1} after whitelist", key, ip));
        }
        public void TestKeyBlacklisting()
        {
            var key = GetRandomKey();
            var ip  = GetRandomIP();

            var interval = TimeSpan.FromMinutes(1);

            Assert.AreEqual(
                false,
                HackerSprayer.IsKeyBlacklistedAsync(key).Run(),
                "Key must not be blacklisted");

            var startTime = DateTime.Now;

            HackerSprayer.BlacklistKeyAsync(key, interval).Run();

            Assert.AreEqual(
                true,
                HackerSprayer.IsKeyBlacklistedAsync(key).Run(),
                "Key must be blacklisted");

            string [] blacklistedKeys = HackerSprayer.GetKeyBlacklists().Run();
            Assert.IsTrue(Array.Exists(blacklistedKeys, k => k == key),
                          "Key must be in the blacklist");

            WaitForIntervalToElapse(interval, startTime);

            Assert.AreEqual(
                false,
                HackerSprayer.IsKeyBlacklistedAsync(key).Run(),
                "Key must not be blacklisted after expiration time");
        }
        public void TestOriginBlaclistingAndWhitelisting()
        {
            var ip  = GetRandomIP();
            var key = GetRandomKey();

            Assert.AreEqual(
                HackerSprayer.Result.Allowed,
                HackerSprayer.DefendAsync(key, ip).Run(),
                string.Format("Allow traffic on {0} from {1}", key, ip));

            HackerSprayer.BlacklistOriginAsync(ip).Run();

            Assert.AreEqual(
                HackerSprayer.Result.OriginBlocked,
                HackerSprayer.DefendAsync(key, ip).Run(),
                string.Format("Block traffic on {0} from {1}", key, ip));

            Assert.AreEqual(
                HackerSprayer.Result.OriginBlocked,
                HackerSprayer.DefendAsync(GetRandomKey(), ip).Run(),
                string.Format("Allow any traffic from {1}", key, ip));

            HackerSprayer.WhitelistOriginAsync(ip).Run();

            Assert.AreEqual(
                HackerSprayer.Result.Allowed,
                HackerSprayer.DefendAsync(key, ip).Run(),
                string.Format("Allow traffic on {0} from {1} after whitelist", key, ip));
        }
Esempio n. 5
0
        public async Task <IActionResult> ClearAllBlocks()
        {
            await HackerSprayer.ClearAllHitsAsync();

            await HackerSprayer.ClearBlacklistsAsync();

            return(await LogOff());
        }
Esempio n. 6
0
        //[ValidateAntiForgeryToken]
        public async Task <IActionResult> Login(LoginViewModel model, string returnUrl = null)
        {
            // This handles load balancers passing the original client IP
            // through this header.
            // WARNING: If you load balancer is not passing original client IP
            // through this header, then you will be blocking your load balancer,
            // causing a total outage. Also ensure this Header cannot be spoofed.
            var originIP = Request.Headers.ContainsKey("X-Forward-For") ?
                           IPAddress.Parse(Request.Headers["X-Forward-For"]).MapToIPv4()
                : Request.HttpContext.Connection.RemoteIpAddress.MapToIPv4();

            return(await HackerSprayer.DefendAsync <IActionResult>(async (success, fail) =>
            {
                // Don't forget to do this check! We use model.Email for key.
                if (string.IsNullOrWhiteSpace(model.Email) || string.IsNullOrWhiteSpace(model.Password))
                {
                    return await fail(View(model));
                }
                ViewData["ReturnUrl"] = returnUrl;
                if (ModelState.IsValid)
                {
                    // This doesn't count login failures towards account lockout
                    // To enable password failures to trigger account lockout, set lockoutOnFailure: true
                    var result = await _signInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, lockoutOnFailure: false);
                    if (result.Succeeded)
                    {
                        _logger.LogInformation(1, "User logged in.");
                        return await success(RedirectToLocal(returnUrl));
                    }
                    if (result.RequiresTwoFactor)
                    {
                        return await success(RedirectToAction(nameof(SendCode), new { ReturnUrl = returnUrl, RememberMe = model.RememberMe }));
                    }
                    if (result.IsLockedOut)
                    {
                        _logger.LogWarning(2, "User account locked out.");
                        return await fail(View("Lockout"));
                    }
                    else
                    {
                        ModelState.AddModelError(string.Empty, "Invalid login attempt.");
                        return await fail(View(model));
                    }
                }

                // If we got this far, something failed, redisplay form
                return await fail(View(model));
            },
                                                                   blocked => new StatusCodeResult((int)HttpStatusCode.Forbidden),
                                                                   "ValidLogin:"******"InvalidLogin:" + model.Email, 3, TimeSpan.FromMinutes(15),
                                                                   originIP));
        }
Esempio n. 7
0
        //[ValidateAntiForgeryToken]
        public async Task <IActionResult> Login(LoginViewModel model, string returnUrl = null)
        {
            SignInResult result = default(SignInResult);
            // This handles load balancers passing the original client IP
            // through this header.
            // WARNING: If you load balancer is not passing original client IP
            // through this header, then you will be blocking your load balancer,
            // causing a total outage. Also ensure this Header cannot be spoofed.
            var originIP = Request.Headers["X-Forward-For"] == null?Context.Connection.RemoteIpAddress.MapToIPv4()
                               : IPAddress.Parse(Request.Headers["X-Forward-For"]).MapToIPv4();

            return(await HackerSprayer.DefendAsync <IActionResult>(async (success, fail) =>
            {
                ViewData["ReturnUrl"] = returnUrl;
                if (ModelState.IsValid)
                {
                    // This doesn't count login failures towards account lockout
                    // To enable password failures to trigger account lockout, set lockoutOnFailure: true
                    result = await _signInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, lockoutOnFailure: false);
                    if (result.Succeeded)
                    {
                        return await success(RedirectToLocal(returnUrl));
                    }
                    if (result.RequiresTwoFactor)
                    {
                        return await success(RedirectToAction(nameof(SendCode), new { ReturnUrl = returnUrl, RememberMe = model.RememberMe }));
                    }
                    if (result.IsLockedOut)
                    {
                        return await fail(View("Lockout"));
                    }
                    else
                    {
                        ModelState.AddModelError(string.Empty, "Invalid login attempt.");
                        return await fail(View(model));
                    }
                }
                else
                {
                    return await fail(View(model));
                }
            },
                                                                   blocked => new HttpStatusCodeResult(405),
                                                                   "ValidLogin:"******"InvalidLogin:" + model.Email,
                                                                   MaxInvalidLogin,
                                                                   MaxInvalidLoginInterval,
                                                                   originIP
                                                                   ));
        }
        public void TestKeyCustomHitLimit()
        {
            HackerSprayer.Config.MaxHitsPerKey          = 100;
            HackerSprayer.Config.MaxHitsPerOrigin       = 100;
            HackerSprayer.Config.MaxHitsPerKeyPerOrigin = 100;

            var key       = "InvalidLogin-" + GetRandomKey();
            var ip        = GetRandomIP();
            var interval  = TimeSpan.FromMinutes(1);
            var maxHits   = 10;
            var startTime = DateTime.Now;

            Parallel.For(0, maxHits,
                         hit =>
            {
                Assert.AreEqual(
                    HackerSprayer.Result.Allowed,
                    HackerSprayer.DefendAsync(key, ip,
                                              interval, maxHits,
                                              TimeSpan.MaxValue, long.MaxValue,
                                              TimeSpan.MaxValue, long.MaxValue).Run(),
                    "Allow hits on key for custom interval");
            });

            Assert.AreEqual(
                HackerSprayer.Result.TooManyHitsOnKey,
                HackerSprayer.DefendAsync(key, ip,
                                          interval, maxHits,
                                          TimeSpan.MaxValue, long.MaxValue,
                                          TimeSpan.MaxValue, long.MaxValue).Run(),
                "Must not allow hits on key after custom interval");

            Assert.AreEqual(
                HackerSprayer.Result.Allowed,
                HackerSprayer.DefendAsync("InvalidLogin-" + GetRandomKey(), ip,
                                          interval, maxHits,
                                          TimeSpan.MaxValue, long.MaxValue,
                                          TimeSpan.MaxValue, long.MaxValue).Run(),
                "Allow hits on different key from same IP");

            WaitForIntervalToElapse(interval, startTime);

            Assert.AreEqual(
                HackerSprayer.Result.Allowed,
                HackerSprayer.DefendAsync(key, ip,
                                          interval, maxHits,
                                          TimeSpan.MaxValue, long.MaxValue,
                                          TimeSpan.MaxValue, long.MaxValue).Run(),
                "Allow hits on key for after interval has passed.");
        }
        public void TestMaxHitsPerOrigin()
        {
            HackerSprayer.Config.MaxHitsPerKey          = 20;
            HackerSprayer.Config.MaxHitsPerOrigin       = 10;
            HackerSprayer.Config.MaxHitsPerKeyPerOrigin = 20;

            var           ip           = GetRandomIP();
            Func <string> keyGenerator = () => { return("TestMaxHitsPerOrigin" + GetRandomKey()); };

            var startTime = DateTime.Now;
            var result    = Parallel.For(0, HackerSprayer.Config.MaxHitsPerOrigin,
                                         hit =>
            {
                Assert.AreEqual(
                    HackerSprayer.Result.Allowed,
                    HackerSprayer.DefendAsync(keyGenerator(), ip).Run()
                    );
            });

            while (!result.IsCompleted)
            {
                Thread.Sleep(100);
            }

            Assert.AreEqual(
                HackerSprayer.Config.MaxHitsPerOrigin,
                HackerSprayer.GetHitsFromOrigin(ip).Run(),
                "Number of hits recorded must match");


            // No more requests from same IP
            Assert.AreEqual(
                HackerSprayer.Result.TooManyHitsFromOrigin,
                HackerSprayer.DefendAsync(keyGenerator(), ip).Run()
                );

            // Allow requests from other IPs
            Assert.AreEqual(
                HackerSprayer.Result.Allowed,
                HackerSprayer.DefendAsync(keyGenerator(), GetRandomIP()).Run());


            WaitForIntervalToElapse(HackerSprayer.Config.MaxHitsPerOriginInterval, startTime);

            Assert.AreEqual(
                HackerSprayer.Result.Allowed,
                HackerSprayer.DefendAsync(keyGenerator(), ip).Run(),
                "Allow hits from same origin after expiration time."
                );
        }
Esempio n. 10
0
        public void TestMaxHitsOnKeyPerOrigin()
        {
            HackerSprayer.Config.MaxHitsPerKey          = 20;
            HackerSprayer.Config.MaxHitsPerOrigin       = 20;
            HackerSprayer.Config.MaxHitsPerKeyPerOrigin = 10;

            Func <string> keyGenerator = () => { return("TestMaxHitsOnKeyPerOrigin" + GetRandomKey()); };
            var           key          = keyGenerator();
            var           ip           = GetRandomIP();

            var startTime = DateTime.Now;

            Parallel.For(0, HackerSprayer.Config.MaxHitsPerKeyPerOrigin,
                         hit =>
            {
                Assert.AreEqual(
                    HackerSprayer.Result.Allowed,
                    HackerSprayer.DefendAsync(key, ip).Run(),
                    "Allow hits on same key and IP");
            });

            Assert.AreEqual(
                HackerSprayer.Config.MaxHitsPerKeyPerOrigin,
                HackerSprayer.GetHitsForKey(key).Run(),
                "Number of hits recorded must match");

            // No more requests from same key and IP
            Assert.AreEqual(
                HackerSprayer.Result.TooManyHitsOnKeyFromOrigin,
                HackerSprayer.DefendAsync(key, ip).Run());

            Assert.AreEqual(
                HackerSprayer.Result.Allowed,
                HackerSprayer.DefendAsync(keyGenerator(), ip).Run(),
                "From different key, same IP, allow");

            Assert.AreEqual(
                HackerSprayer.Result.Allowed,
                HackerSprayer.DefendAsync(key, GetRandomIP()).Run(),
                "From different IP, same key, allow");

            WaitForIntervalToElapse(HackerSprayer.Config.MaxHitsPerOriginInterval, startTime);

            Assert.AreEqual(
                HackerSprayer.Result.Allowed,
                HackerSprayer.DefendAsync(key, ip).Run(),
                "Allow hits on same key and IP after expiration");
        }
Esempio n. 11
0
        public void TestMaxHitsPerKey()
        {
            HackerSprayer.Config.MaxHitsPerKey          = 10;
            HackerSprayer.Config.MaxHitsPerOrigin       = 20;
            HackerSprayer.Config.MaxHitsPerKeyPerOrigin = 20;

            Func <string> keyGenerator = () => { return("TestMaxHitsPerKey" + GetRandomKey()); };
            var           fixedKey     = keyGenerator();

            var startTime = DateTime.Now;

            Parallel.For(0, HackerSprayer.Config.MaxHitsPerKey,
                         hit =>
            {
                Assert.AreEqual(
                    HackerSprayer.Result.Allowed,
                    HackerSprayer.DefendAsync(fixedKey, GetRandomIP()).Run()
                    );
            });

            Assert.AreEqual(
                HackerSprayer.Config.MaxHitsPerKey,
                HackerSprayer.GetHitsForKey(fixedKey).Run(),
                "Number of hits recorded must match");

            Assert.AreEqual(
                HackerSprayer.Result.TooManyHitsOnKey,
                HackerSprayer.DefendAsync(fixedKey, GetRandomIP()).Run());

            var ip = GetRandomIP();

            Assert.AreEqual(
                HackerSprayer.Result.Allowed,
                HackerSprayer.DefendAsync(keyGenerator(), ip).Run(),
                "Allow traffic from aonther key on same IP");

            WaitForIntervalToElapse(HackerSprayer.Config.MaxHitsPerKeyInterval, startTime);

            // Hit from another IP using same key should be allowed
            Assert.AreEqual(
                HackerSprayer.Result.Allowed,
                HackerSprayer.DefendAsync(fixedKey, GetRandomIP()).Run(),
                "After expiration time, key must be unblocked");
        }
Esempio n. 12
0
        public async Task <ActionResult> LogOn(string username, string password)
        {
            // This handles load balancers passing the original client IP
            // through this header.
            // WARNING: If you load balancer is not passing original client IP
            // through this header, then you will be blocking your load balancer,
            // causing a total outage. Also ensure this Header cannot be spoofed.
            var originIP = IPAddress.Parse(Request.Headers["X-Forward-For"]
                                           ?? Request.UserHostAddress).MapToIPv4();

            // Don't forget to do this check!
            if (string.IsNullOrWhiteSpace(username) || string.IsNullOrWhiteSpace(password))
            {
                TempData[TempDataConstants.ERROR_MESSAGE] = "Invalid username or password";
                return(View("~/Views/Account/LogOn.cshtml"));
            }

            return(await HackerSprayer.DefendAsync <ActionResult>(async (success, fail) =>
            {
                var user = DataStore.Users.Where(u => u.Username == username &&
                                                 u.Password == password).FirstOrDefault();
                if (user != null)
                {
                    Session[SessionConstants.USER] = user;
                    return await success(RedirectToAction("Index", "Home"));
                }
                else
                {
                    TempData[TempDataConstants.ERROR_MESSAGE] = "Invalid username or password";
                    return await fail(View("~/Views/Account/LogOn.cshtml"));
                }
            },
                                                                  blocked => new HttpStatusCodeResult(HttpStatusCode.Forbidden),
                                                                  "ValidLogin:"******"InvalidLogin:" + username, MaxInvalidLogin, MaxInvalidLoginInterval,
                                                                  originIP
                                                                  ));
        }
Esempio n. 13
0
        public void TestAllowed()
        {
            var result = HackerSprayer.DefendAsync("TestAllowed" + GetRandomKey(), GetRandomIP()).Run();

            Assert.AreEqual(HackerSprayer.Result.Allowed, result);
        }
Esempio n. 14
0
 public void Cleanup()
 {
     HackerSprayer.ClearAllHitsAsync().Run();
     HackerSprayer.ClearBlacklistsAsync().Run();
     HackerSprayer.Store.Dispose();
 }
Esempio n. 15
0
        public void TestOriginRangeBlocking()
        {
            HackerSprayer.ClearBlacklistsAsync().Run();
            HackerSprayer.ClearAllHitsAsync().Run();

            var ipsInRange = new[] {
                IPAddress.Parse("10.10.10.10"),
                IPAddress.Parse("10.10.10.11"),
                IPAddress.Parse("10.10.254.254"),
                IPAddress.Parse("10.11.10.9"),
                IPAddress.Parse("10.11.10.10"),
                IPAddress.Parse("9.1.1.1"),
                IPAddress.Parse("9.1.1.10"),
                IPAddress.Parse("9.10.10.9"),
                IPAddress.Parse("10.11.10.12"),
                IPAddress.Parse("127.254.254.254"),
                IPAddress.Parse("100.100.100.100"),
                IPAddress.Parse("128.10.10.12"),
                IPAddress.Parse("128.10.10.254"),
                IPAddress.Parse("128.10.10.128"),
            };

            var ipsOutofRange = new[] {
                IPAddress.Parse("10.10.10.9"),
                IPAddress.Parse("9.10.10.10"),
                IPAddress.Parse("10.11.10.11"),
                IPAddress.Parse("128.10.10.11"),
                IPAddress.Parse("200.200.200.200"),
                IPAddress.Parse("1.1.1.1"),
                IPAddress.Parse("10.0.0.0")
            };

            HackerSprayer.BlacklistOriginAsync(IPAddress.Parse("10.10.10.10"), IPAddress.Parse("10.11.10.10")).Run();
            HackerSprayer.BlacklistOriginAsync(IPAddress.Parse("9.1.1.1"), IPAddress.Parse("9.10.10.9")).Run();
            HackerSprayer.BlacklistOriginAsync(IPAddress.Parse("10.11.10.12"), IPAddress.Parse("127.254.254.254")).Run();
            HackerSprayer.BlacklistOriginAsync(IPAddress.Parse("128.10.10.12"), IPAddress.Parse("128.10.10.254")).Run();

            Array.ForEach(ipsInRange, ip =>
                          Assert.AreEqual(HackerSprayer.Result.OriginBlocked,
                                          HackerSprayer.DefendAsync("TestOriginRangeBlocking", ip).Run(),
                                          ip.ToString() + " must be blocked."));

            HackerSprayer.ClearAllHitsAsync().Run();

            Array.ForEach(ipsOutofRange, ip =>
                          Assert.AreEqual(HackerSprayer.Result.Allowed,
                                          HackerSprayer.DefendAsync("TestOriginRangeBlocking", ip).Run(),
                                          ip.ToString() + " must be allowed"));

            HackerSprayer.WhitelistOriginAsync(IPAddress.Parse("9.1.1.1"), IPAddress.Parse("9.10.10.9")).Run();

            Array.ForEach(new[]
            {
                IPAddress.Parse("9.1.1.1"),
                IPAddress.Parse("9.1.1.10"),
                IPAddress.Parse("9.10.10.9")
            },
                          ip =>
                          Assert.AreEqual(HackerSprayer.Result.Allowed,
                                          HackerSprayer.DefendAsync("TestOriginRangeBlocking", ip).Run(),
                                          ip.ToString() + " must be allowed"));

            HackerSprayer.ClearBlacklistsAsync().Run();
            HackerSprayer.ClearAllHitsAsync().Run();

            Array.ForEach(ipsInRange, ip =>
                          Assert.AreEqual(HackerSprayer.Result.Allowed,
                                          HackerSprayer.DefendAsync("TestOriginRangeBlocking", ip).Run(),
                                          ip.ToString() + " must be allowed when there's no blacklisting."));

            HackerSprayer.ClearAllHitsAsync().Run();

            Array.ForEach(ipsOutofRange, ip =>
                          Assert.AreEqual(HackerSprayer.Result.Allowed,
                                          HackerSprayer.DefendAsync("TestOriginRangeBlocking", ip).Run(),
                                          ip.ToString() + " must be allowed when there's no blacklisting"));
        }
        public static async Task <HackerSprayer.Result> DefendURL(HttpContext context)
        {
            HackerSprayer.Result result = HackerSprayer.Result.Allowed;

            if (!Initialized)
            {
                lock (lockObject)
                {
                    if (!Initialized)
                    {
                        Initialized         = true;
                        HackerSprayer.Store = new RedisDefenceStore(HackerSprayConfig.Settings.Redis,
                                                                    HackerSprayConfig.Settings.Prefix,
                                                                    HackerSprayer.Config);
                    }
                }
            }

            // This handles load balancers passing the original client IP
            // through this header.
            // WARNING: If your load balancer is not passing original client IP
            // through this header, then you will be blocking your load balancer,
            // causing a total outage. Also ensure this Header cannot be spoofed.
            // Your load balancer should be configured in a way that it does not accept
            // this header from the request, instead it always sets it itself.
            var originIP = IPAddress.Parse(context.Request.Headers["X-Forward-For"]
                                           ?? context.Request.UserHostAddress).MapToIPv4();

            foreach (var path in HackerSprayConfig.Settings.Paths)
            {
                if ((path.Post && context.Request.HttpMethod == "POST") ||
                    (!path.Post && context.Request.HttpMethod == "GET") &&
                    path.Name == context.Request.Path)
                {
                    if (path.Mode == "perkey")
                    {
                        result = await HackerSprayer.DefendAsync(context.Request.Path, originIP,
                                                                 path.Interval, path.MaxAttempts,
                                                                 TimeSpan.MaxValue, long.MaxValue,
                                                                 TimeSpan.MaxValue, long.MaxValue);
                    }
                    else if (path.Mode == "perorigin")
                    {
                        result = await HackerSprayer.DefendAsync(context.Request.Path, originIP,
                                                                 TimeSpan.MaxValue, long.MaxValue,
                                                                 path.Interval, path.MaxAttempts,
                                                                 TimeSpan.MaxValue, long.MaxValue);
                    }
                    else //(path.Mode == "perkeyorigin")
                    {
                        result = await HackerSprayer.DefendAsync(context.Request.Path, originIP,
                                                                 TimeSpan.MaxValue, long.MaxValue,
                                                                 TimeSpan.MaxValue, long.MaxValue,
                                                                 path.Interval, path.MaxAttempts);
                    }

                    // Blacklist origin. After that, it becomes least expensive to block requests
                    if (result == HackerSprayer.Result.TooManyHitsFromOrigin)
                    {
                        await HackerSprayer.BlacklistOriginAsync(originIP, path.Interval);
                    }
                    else if (result == HackerSprayer.Result.TooManyHitsOnKey)
                    {
                        await HackerSprayer.BlacklistKeyAsync(path.Name, path.Interval);
                    }
                    //else if (result == HackerSprayer.Result.TooManyHitsOnKeyFromOrigin)
                    // There is nothing for that, because we neither want to block the key for all ip,
                    // nor do we want to block the ip for all key. It just has to be checked each
                    // and every time. Thus this is the most expensive check.
                    break;
                }
            }

            return(result);
        }