示例#1
0
        private void RunConfigBanTest(string key, string value, string banIP, string noBanIP)
        {
            // turn on clear failed logins upon success login
            using IPBanConfig.TempConfigChanger configChanger = new IPBanConfig.TempConfigChanger(service, xml =>
            {
                return(IPBanConfig.ChangeConfigAppSetting(xml, key, value));
            }, out string newConfig);

            service.AddIPAddressLogEvents(new IPAddressLogEvent[]
            {
                // should be banned
                new IPAddressLogEvent(banIP, "user1", "RDP", 999, IPAddressEventType.FailedLogin),

                // whitelisted
                new IPAddressLogEvent(noBanIP, "user2", "RDP", 999, IPAddressEventType.FailedLogin),
            });

            // process failed logins
            service.RunCycle().Sync();

            Assert.IsTrue(service.Firewall.IsIPAddressBlocked(banIP, out _));
            Assert.IsFalse(service.Firewall.IsIPAddressBlocked(noBanIP, out _));
            Assert.IsTrue(service.DB.TryGetIPAddress(banIP, out IPBanDB.IPAddressEntry e1));
            Assert.IsFalse(service.DB.TryGetIPAddress(noBanIP, out IPBanDB.IPAddressEntry e2));
        }
示例#2
0
        public async Task TestFailedLoginsClearOnSuccessfulLogin()
        {
            // turn on clear failed logins upon success login
            using IPBanConfig.TempConfigChanger configChanger = new IPBanConfig.TempConfigChanger(service, xml =>
            {
                return(IPBanConfig.ChangeConfigAppSetting(xml, nameof(IPBanConfig.ClearFailedLoginsOnSuccessfulLogin), "true"));
            }, out string newConfig);

            string ip = "99.88.77.66";

            for (int i = 0; i < 2; i++)
            {
                service.AddIPAddressLogEvents(new IPAddressLogEvent[]
                {
                    // fail login
                    new IPAddressLogEvent(ip, "user1", "RDP", 1, IPAddressEventType.FailedLogin),
                });
            }

            await service.RunCycle();

            service.AddIPAddressLogEvents(new IPAddressLogEvent[]
            {
                new IPAddressLogEvent(ip, "user1", "RDP", 1, IPAddressEventType.SuccessfulLogin),
            });

            await service.RunCycle();

            Assert.IsFalse(service.DB.TryGetIPAddress(ip, out _));
        }
示例#3
0
        public void TestUserNameWhitelistBan()
        {
            using IPBanConfig.TempConfigChanger configChanger = new IPBanConfig.TempConfigChanger(service, xml =>
            {
                return(IPBanConfig.ChangeConfigAppSetting(xml, "UserNameWhitelist", "OnlyMe"));
            }, out string newConfig);

            // TODO: ensure non OnlyMe users are banned immediately
            // TODO: ensure OnlyMe user gets 20 failed logins before ban
        }
示例#4
0
        public async Task TestUserNameWhitelistRegexBan()
        {
            using IPBanConfig.TempConfigChanger configChanger = new IPBanConfig.TempConfigChanger(service, xml =>
            {
                return(IPBanConfig.ChangeConfigAppSetting(xml, "UserNameWhitelistRegex", "ftp_[0-9]+"));
            }, out string newConfig);

            service.AddIPAddressLogEvents(new IPAddressLogEvent[]
            {
                // a single failed login with a non-blacklisted user name should not get banned
                new IPAddressLogEvent("99.99.99.99", "ftp_1", "RDP", 1, IPAddressEventType.FailedLogin),

                // a single failed login with a failed user name whitelist regex should get banned
                new IPAddressLogEvent("99.99.99.90", "NaughtyUserName", "RDP", 1, IPAddressEventType.FailedLogin)
            });
            await service.RunCycle();

            Assert.IsTrue(service.Firewall.IsIPAddressBlocked("99.99.99.90", out _));
            Assert.IsFalse(service.Firewall.IsIPAddressBlocked("99.99.99.99", out _));
        }
示例#5
0
        private void RunConfigBanTest(string key, string value, string banIP, string noBanIP, int noBanIPCount = 999)
        {
            // turn on clear failed logins upon success login
            using IPBanConfig.TempConfigChanger configChanger = new IPBanConfig.TempConfigChanger(service, xml =>
            {
                return(IPBanConfig.ChangeConfigAppSetting(xml, key, value));
            }, out string newConfig);

            List <IPAddressLogEvent> events = new List <IPAddressLogEvent>
            {
                new IPAddressLogEvent(banIP, "user1", "RDP", 999, IPAddressEventType.FailedLogin)
            };

            if (!string.IsNullOrWhiteSpace(noBanIP))
            {
                events.Add(new IPAddressLogEvent(noBanIP, "user2", "RDP", noBanIPCount, IPAddressEventType.FailedLogin));
            }
            service.AddIPAddressLogEvents(events);

            // process failed logins
            service.RunCycle().Sync();

            Assert.IsTrue(service.Firewall.IsIPAddressBlocked(banIP, out _));
            Assert.IsTrue(service.DB.TryGetIPAddress(banIP, out IPBanDB.IPAddressEntry e1));
            Assert.AreEqual(e1.FailedLoginCount, 999);
            if (!string.IsNullOrWhiteSpace(noBanIP))
            {
                Assert.IsFalse(service.Firewall.IsIPAddressBlocked(noBanIP, out _));
                if (noBanIPCount > 0)
                {
                    Assert.IsTrue(service.DB.TryGetIPAddress(noBanIP, out IPBanDB.IPAddressEntry e2));
                    Assert.AreEqual(e2.FailedLoginCount, noBanIPCount);
                }
                else
                {
                    Assert.IsFalse(service.DB.TryGetIPAddress(noBanIP, out _));
                }
            }
        }
示例#6
0
        public void TestExtraFirewallRules()
        {
            using IPBanConfig.TempConfigChanger configChanger = new IPBanConfig.TempConfigChanger(service, xml =>
            {
                return(IPBanConfig.ChangeConfigAppSetting(xml, "FirewallRules", @"
                    ReddisAllowIP;allow;10.0.0.1,10.0.0.2,192.168.1.168/24;6379;.
                    WebOnly;block;0.0.0.0/1,128.0.0.0/1,::/1,8000::/1;22,80,443,3389;^(?:(?!Windows).)+$"));
            }, out string newConfig);

            List <string> rules      = service.Firewall.GetRuleNames().ToList();
            string        reddisRule = service.Firewall.RulePrefix + "EXTRA_ReddisAllowIP";
            string        webRule    = service.Firewall.RulePrefix + "EXTRA_WebOnly";

            if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
            {
                // on Windows, block is the default, so only the allow rules should show up
                Assert.IsTrue(rules.Exists((s) => s.StartsWith(reddisRule)));
                Assert.IsFalse(rules.Exists((s) => s.StartsWith(webRule)));
                Assert.AreEqual(1, service.Config.ExtraRules.Count);
                IPBanFirewallRule rule1       = service.Config.ExtraRules[0];
                string            regexString = rule1.ToString();
                Assert.AreEqual("EXTRA_ReddisAllowIP;allow;10.0.0.1/32,10.0.0.2/32,192.168.1.0/24;6379;.", regexString);
            }
            else
            {
                // on Linux, both rules are needed
                Assert.AreEqual(2, service.Config.ExtraRules.Count);
                Assert.IsTrue(rules.Exists((s) => s.StartsWith(reddisRule)));
                Assert.IsTrue(rules.Exists((s) => s.StartsWith(webRule)));
                IPBanFirewallRule rule1        = service.Config.ExtraRules[0];
                IPBanFirewallRule rule2        = service.Config.ExtraRules[1];
                string            regexString1 = rule1.ToString();
                string            regexString2 = rule2.ToString();
                Assert.AreEqual("EXTRA_ReddisAllowIP;allow;10.0.0.1/32,10.0.0.2/32,192.168.1.0/24;6379;.", regexString1);
                Assert.AreEqual("EXTRA_WebOnly;block;0.0.0.0/1,128.0.0.0/1,::/1,8000::/1;22,80,443,3389;^(?:(?!Windows).)+$", regexString2);
            }
        }
示例#7
0
        private async Task TestMultipleBanTimespansAsync(bool resetFailedLogin)
        {
            using IPBanConfig.TempConfigChanger configChanger = new IPBanConfig.TempConfigChanger(service, xml =>
            {
                xml = IPBanConfig.ChangeConfigAppSetting(xml, "BanTime", "00:00:01:00,00:00:02:00,00:00:03:00");
                xml = IPBanConfig.ChangeConfigAppSetting(xml, "ResetFailedLoginCountForUnbannedIPAddresses", resetFailedLogin.ToString());
                return(xml);
            }, out string newConfig);

            Assert.AreEqual(3, service.Config.BanTimes.Length);
            Assert.AreEqual(resetFailedLogin, service.Config.ResetFailedLoginCountForUnbannedIPAddresses);
            for (int i = 1; i <= 3; i++)
            {
                Assert.AreEqual(TimeSpan.FromMinutes(i), service.Config.BanTimes[i - 1]);
            }

            for (int i = 0; i < 4; i++)
            {
                // forget all the bans, but they should still be in the database due to the multiple timespans as failed logins
                IPBanService.UtcNow += TimeSpan.FromDays(14.0);
                await service.RunCycle();

                if (i < 3)
                {
                    if (i > 0)
                    {
                        // the ips should exist but not be banned
                        AssertIPAddressesAreNotBanned(true, true);
                    }

                    AddFailedLogins((i == 0 ? -1 : 1));

                    if (resetFailedLogin)
                    {
                        if (i > 0)
                        {
                            // after one failed login, should not be banned
                            AssertIPAddressesAreNotBanned(true, true);
                        }

                        // add more failed logins
                        AddFailedLogins();

                        // now they should be banned, failed login counts are reset upon ban
                        AssertIPAddressesAreBanned(0, 0);
                    }
                    else
                    {
                        // should have gotten back in with just a single failed login
                        AssertIPAddressesAreBanned(info1.Count + i, info2.Count + i);
                    }

                    Assert.IsTrue(service.DB.TryGetIPAddress(ip1, out IPBanDB.IPAddressEntry e1));
                    Assert.IsTrue(service.DB.TryGetIPAddress(ip2, out IPBanDB.IPAddressEntry e2));

                    // i == 3 means wrap around from 3 minutes back to 1 minute
                    TimeSpan expectedBanDuration = (i < 3 ? expectedBanDuration = TimeSpan.FromMinutes(i + 1) : TimeSpan.FromMinutes(1.0));
                    Assert.AreEqual(expectedBanDuration, e1.BanEndDate - e1.BanStartDate);
                    Assert.AreEqual(expectedBanDuration, e2.BanEndDate - e2.BanStartDate);
                    if (resetFailedLogin)
                    {
                        Assert.AreEqual(0, e1.FailedLoginCount);
                        Assert.AreEqual(0, e2.FailedLoginCount);
                    }
                    else
                    {
                        Assert.AreNotEqual(0, e1.FailedLoginCount);
                        Assert.AreNotEqual(0, e2.FailedLoginCount);
                    }
                }
                else
                {
                    // the cycle will run and remove the expired ip first as they have finished the loop through the ban times, they should all have a single failed login count
                    AddFailedLogins(1);

                    // ips should exist but not be banned
                    AssertIPAddressesAreNotBanned(true, true);
                    Assert.IsTrue(service.DB.TryGetIPAddress(ip1, out IPBanDB.IPAddressEntry e1));
                    Assert.IsTrue(service.DB.TryGetIPAddress(ip2, out IPBanDB.IPAddressEntry e2));
                    Assert.IsNull(e1.BanStartDate);
                    Assert.IsNull(e2.BanStartDate);
                    Assert.IsNull(e1.BanEndDate);
                    Assert.IsNull(e2.BanEndDate);
                    Assert.AreEqual(1, e1.FailedLoginCount);
                    Assert.AreEqual(1, e2.FailedLoginCount);

                    // now add a bunch of fail logins, ip should ban with a time span of 1 minute
                    AddFailedLogins();
                    if (resetFailedLogin)
                    {
                        AssertIPAddressesAreBanned(0, 0);
                    }
                    else
                    {
                        AssertIPAddressesAreBanned(info1.Count + 1, info2.Count + 1);
                    }
                    Assert.IsTrue(service.DB.TryGetIPAddress(ip1, out e1));
                    Assert.IsTrue(service.DB.TryGetIPAddress(ip2, out e2));
                    TimeSpan expectedBanDuration = TimeSpan.FromMinutes(1.0);
                    Assert.AreEqual(expectedBanDuration, e1.BanEndDate - e1.BanStartDate);
                    Assert.AreEqual(expectedBanDuration, e2.BanEndDate - e2.BanStartDate);
                    if (resetFailedLogin)
                    {
                        Assert.AreEqual(0, e1.FailedLoginCount);
                        Assert.AreEqual(0, e2.FailedLoginCount);
                    }
                    else
                    {
                        Assert.AreEqual(info1.Count + 1, e1.FailedLoginCount);
                        Assert.AreEqual(info2.Count + 1, e2.FailedLoginCount);
                    }
                }
            }
        }
示例#8
0
        private async Task TestMultipleBanTimespansExternalBlockAsync(bool resetFailedLogin)
        {
            const string                        ipAddress = "99.99.99.99";
            const string                        userName  = "******";
            const string                        source    = "RDP";
            const IPAddressEventType            type      = IPAddressEventType.FailedLogin;
            KeyValuePair <DateTime?, DateTime?> banDates;

            service.IPBanDelegate = new ExternalBlocker(service);

            IPAddressLogEvent[] events = new IPAddressLogEvent[1];

            using IPBanConfig.TempConfigChanger configChanger = new IPBanConfig.TempConfigChanger(service, xml =>
            {
                xml = IPBanConfig.ChangeConfigAppSetting(xml, "BanTime", "00:00:01:00,00:00:05:00,00:00:15:00,89:00:00:00");
                xml = IPBanConfig.ChangeConfigAppSetting(xml, "ResetFailedLoginCountForUnbannedIPAddresses", resetFailedLogin.ToString());
                return(xml);
            }, out string newConfig);
            Assert.AreEqual(4, service.Config.BanTimes.Length);

            // send a block event, should get banned for 1 minute
            IPBanService.UtcNow = new DateTime(2020, 1, 1, 1, 1, 1, DateTimeKind.Utc);

            for (int i = 0; i < 2; i++)
            {
                events[0] = new IPAddressLogEvent(ipAddress, userName, source, 1, type, IPBanService.UtcNow);
                service.AddIPAddressLogEvents(events);
                await service.RunCycle();

                Assert.IsFalse(service.Firewall.IsIPAddressBlocked(ipAddress));

                // run cycle again, should get pinged by external blocker and ip should be blocked
                await service.RunCycle();

                Assert.IsTrue(service.Firewall.IsIPAddressBlocked(ipAddress));
                Assert.IsTrue(service.DB.TryGetBanDates(ipAddress, out banDates));
                Assert.AreEqual(IPBanService.UtcNow, banDates.Key);
                Assert.AreEqual(IPBanService.UtcNow.AddMinutes(1.0), banDates.Value);

                // short step, should still be blocked
                IPBanService.UtcNow += TimeSpan.FromSeconds(1.0);
                await service.RunCycle();

                Assert.IsTrue(service.Firewall.IsIPAddressBlocked(ipAddress));

                IPBanService.UtcNow += TimeSpan.FromMinutes(1.0);
                await service.RunCycle();

                Assert.IsFalse(service.Firewall.IsIPAddressBlocked(ipAddress));

                // send a fail login event, should get banned for 5 minutes
                events[0] = new IPAddressLogEvent(ipAddress, userName, source, 1, type, IPBanService.UtcNow);
                service.AddIPAddressLogEvents(events);
                await service.RunCycle();

                Assert.IsFalse(service.Firewall.IsIPAddressBlocked(ipAddress));

                DateTime savedBanDate = IPBanService.UtcNow;

                // add a failed and blocked login event, should not interfere with the ban cycle
                events[0] = new IPAddressLogEvent(ipAddress, userName, source, 1, IPAddressEventType.FailedLogin, IPBanService.UtcNow);
                service.AddIPAddressLogEvents(events);
                await service.RunCycle();

                events[0] = new IPAddressLogEvent(ipAddress, userName, source, 1, IPAddressEventType.Blocked, IPBanService.UtcNow, true);
                service.AddIPAddressLogEvents(events);
                await service.RunCycle();

                // throw in some chaos
                IPBanService.UtcNow += TimeSpan.FromSeconds(7.213);

                // blocker will ban the ip
                await service.RunCycle();

                Assert.IsTrue(service.Firewall.IsIPAddressBlocked(ipAddress));
                Assert.IsTrue(service.DB.TryGetBanDates(ipAddress, out banDates));
                Assert.AreEqual(savedBanDate, banDates.Key);
                Assert.AreEqual(savedBanDate.AddMinutes(5.0), banDates.Value);

                IPBanService.UtcNow += TimeSpan.FromMinutes(20.0);
                await service.RunCycle();

                Assert.IsFalse(service.Firewall.IsIPAddressBlocked(ipAddress));

                // send a failed login event, should get banned for 15 minutes
                events[0] = new IPAddressLogEvent(ipAddress, userName, source, 1, type, IPBanService.UtcNow);
                service.AddIPAddressLogEvents(events);
                await service.RunCycle();

                Assert.IsFalse(service.Firewall.IsIPAddressBlocked(ipAddress));

                // cycle again, blocker will ban
                await service.RunCycle();

                Assert.IsTrue(service.Firewall.IsIPAddressBlocked(ipAddress));
                Assert.IsTrue(service.DB.TryGetBanDates(ipAddress, out banDates));
                Assert.AreEqual(IPBanService.UtcNow, banDates.Key);
                Assert.AreEqual(IPBanService.UtcNow.AddMinutes(15.0), banDates.Value);

                IPBanService.UtcNow += TimeSpan.FromMinutes(30.0);
                await service.RunCycle();

                Assert.IsFalse(service.Firewall.IsIPAddressBlocked(ipAddress));

                // send a block event, should get banned for 89 days
                events[0] = new IPAddressLogEvent(ipAddress, userName, source, 1, type, IPBanService.UtcNow);
                service.AddIPAddressLogEvents(events);
                await service.RunCycle();

                Assert.IsFalse(service.Firewall.IsIPAddressBlocked(ipAddress));

                // cycle again, blocker will ban
                await service.RunCycle();

                Assert.IsTrue(service.Firewall.IsIPAddressBlocked(ipAddress));
                Assert.IsTrue(service.DB.TryGetBanDates(ipAddress, out banDates));
                Assert.AreEqual(IPBanService.UtcNow, banDates.Key);
                Assert.AreEqual(IPBanService.UtcNow.AddDays(89.0), banDates.Value);

                IPBanService.UtcNow += TimeSpan.FromDays(91.0);
                await service.RunCycle();

                Assert.IsFalse(service.Firewall.IsIPAddressBlocked(ipAddress));
            }
        }