Developer forum

Forum » CMS - Standard features » Users Banned, but not in _BannedIPs.txt

Users Banned, but not in _BannedIPs.txt

Nuno Aguiar Dynamicweb Employee
Nuno Aguiar
Reply

Hi,

 

We have 2 customers (9.14.10 and 9.16.7) that have both reported a very odd experience wtih IP Banner.

 

  • They claim to be banned
  • Their IP is NOT in GeneralLog nor in _BannedIPs.txt
  • But whenever we completely clear the _BannedIPs.txt file, they are unblocked

 

The only similar thing between the two is that some IPv6 were banned, but they don't look right, storing only the first 4 digits of the IP.

 

Any thoughts on what could be causing this? If it's best, I can reach out through Care so that I can provide the customer's names and the banned IPs

 

Best Regards,

Nuno Aguiar


Replies

 
Nicolai Pedersen Dynamicweb Employee
Nicolai Pedersen
Reply

Could they be use some sort of proxy on their net. x-forwarded-for header vs. the IP?

 
Nicolai Pedersen Dynamicweb Employee
Nicolai Pedersen
Reply

Could they be use some sort of proxy on their net. x-forwarded-for header vs. the IP?

 
Nicolai Pedersen Dynamicweb Employee
Nicolai Pedersen
Reply

Havin an IPv6 in their banned IPs is very odd as there should not be ipv6 on their webserver. That could indicate that they internally run ipv6, and that is forwarded in a header DW understands...

 
Nuno Aguiar Dynamicweb Employee
Nuno Aguiar
Reply

Hi Nicolai,

 

I'll see if I can meet with the customer and through screen sharing try to capture more information. If you have any other ideas on how I could even capture this, I'd appreciate it.

 

In regards to the IPv6 (which may or may not be related), here's what we're seeing

 
Nicolai Pedersen Dynamicweb Employee
Nicolai Pedersen
Reply

Cloudflare configuration issue? ipBanner is looking at x-forwarded-for headers - and they could contain something that DW misunderstand...

I guess this kind of request is not coming from inside their organisation

/products?ProductType=2%27%29+AND+1%3D1+UNION+ALL+SELECT+1%2CNULL%2C%27%3Cscript%3Ealert%28%5C%22XSS%5C%22%29%3C%2Fscript%3E%27%2Ctable_name+FROM+information_schema.tables+WHERE+2%3E1--%2F%2A%2A%2F%3B+EXEC+xp_cmdshell%28%27cat+..%2F..%2F..%2Fetc%2Fpasswd%27%29%23

 
Nuno Aguiar Dynamicweb Employee
Nuno Aguiar
Reply

Hi Nicolai,

 

I haven't been able to meet with both customers to see what they are getting. Cloudflare is a possibility, but we'll have to see.

 

Clearly what you highlighted is not coming from within their organization (a clear SQL Injection and XSS attempt). I guess I wondered if there could be something in DW that once if finds a banned IP of type IPv6, the code acts up and does not validate them accurately (since our customers stop getting banned once we completetly delete everything in _BannedIps.txt despite not seeing their IP there - at least that's been how our Support Desk people reported it on both occasions). I'll get to the bottom of the mistery :) 

 

Thank you for your insights,

Nuno Aguiar

 
Nuno Aguiar Dynamicweb Employee
Nuno Aguiar
Reply

Hi Nicolai,

 

At least we figured why IP v6 are getting logged badly (it's coming up more and more)

        public static string GetClientIpAddress()
        {
            try
            {
                string userHostAddress = Context.Current.Request.UserHostAddress;
                // Could use TryParse instead, but I wanted to catch all exceptions
                IPAddress.Parse(userHostAddress);
                string forwardIp = Context.Current.Request?.Headers?["X-FORWARDED-FOR"];
                if (string.IsNullOrEmpty(forwardIp))
                {
                    forwardIp = Context.Current.Request?.Headers?["X-CLIENT-IP"];
                }
                if (string.IsNullOrEmpty(forwardIp))
                {
                    return userHostAddress;
                }
                // Get a list of public ip addresses in the X-FORWARDED-FOR and X-CLIENT-IP headers
                var publicForwardingIps = new List<string>();
                var array = forwardIp.Split(',');
                for (int i = 0, loopTo = array.Length - 1; i <= loopTo; i++)
                {
                    string ipString = array[i];
                    if (ipString.Contains(":"))
                    {
                        ipString = ipString.Split(':')[0];
                    }
                    if (!IsPrivateIpAddress(ipString) && !publicForwardingIps.Contains(ipString))
                    {
                        publicForwardingIps.Add(ipString);
                    }
                }
                // If we found any, return the last one, otherwise return the user host address
                return publicForwardingIps.Any() ? publicForwardingIps.First() : userHostAddress;
            }
            catch
            {
                return null;
            }
        }

 

If this could be changed, would at least help support them in future versions.

 

I found a few way to go about it. Here's a suggestion without a lot of refactoring

        public static string GetClientIpAddress()
        {
            try
            {
                string userHostAddress = Context.Current.Request.UserHostAddress;
                // Could use TryParse instead, but I wanted to catch all exceptions
                IPAddress.Parse(userHostAddress);
                string forwardIp = Context.Current.Request?.Headers?["X-FORWARDED-FOR"];
                if (string.IsNullOrEmpty(forwardIp))
                {
                    forwardIp = Context.Current.Request?.Headers?["X-CLIENT-IP"];
                }
                if (string.IsNullOrEmpty(forwardIp))
                {
                    return userHostAddress;
                }
                // Get a list of public ip addresses in the X-FORWARDED-FOR and X-CLIENT-IP headers
                var publicForwardingIps = new List<string>();
                var array = forwardIp.Split(',');
                for (int i = 0, loopTo = array.Length - 1; i <= loopTo; i++)
                {
                    IPAddress address;
                    if (IPAddress.TryParse(array[i], out address))
                    {
                        string ipString = array[i];
                        if (ipString.Contains(":") && address == System.Net.Sockets.AddressFamily.InterNetwork)
                        {
                            ipString = ipString.Split(':')[0];
                        }
                        if (!IsPrivateIpAddress(ipString) && !publicForwardingIps.Contains(ipString))
                        {
                            publicForwardingIps.Add(ipString);
                        }
                    }
                }
                // If we found any, return the last one, otherwise return the user host address
                return publicForwardingIps.Any() ? publicForwardingIps.First() : userHostAddress;
            }
            catch
            {
                return null;
            }
        }

 

Best Regards,

Nuno Aguiar

 
Nicolai Pedersen Dynamicweb Employee
Nicolai Pedersen
Reply

I suggest this:

public static string? GetClientIpAddress(this IRequest request)
{
    try
    {
        // Attempt to parse.
        if (IPAddress.TryParse(request.UserHostAddress, out var iPAddress))
            return iPAddress.ToString();

        return null;
    }
    catch
    {
        return null;
    }
}

Looking at headers like this is a security breach anyways...

 
Nuno Aguiar Dynamicweb Employee
Nuno Aguiar
Reply

Hi Nicolai,

 

Sure, I'm happy either way. Can this change be made to:

  • DW9 - /src/88 - Content/Dynamicweb/SystemTools/Security/IpBanner.cs
  • DW10 - /src/Features/Content/Dynamicweb/SystemTools/Security/IpBanner.cs
 
Nicolai Pedersen Dynamicweb Employee
Nicolai Pedersen
Reply

Registered as a feature change - devops#23002 - pull already made for DW10

 
Anouk van der Veer
Reply

Hi guys,

What was the culprit in your case Nuno? We are running into similar problems since about ten days and are still looking for a solution.

 

Kind regards,

Anouk

 
Nuno Aguiar Dynamicweb Employee
Nuno Aguiar
Reply

Hi Anouk,

 

Do you use a WAF much like Cloudflare? Our issue is that Cloudflare would move the client's IP to a new header (CF-Connecting-IP) and, most importantly, added it's own IP to the X-Forwarded-For.

 

The problem was that DW was using the X-Forwarded-For header's first IP it finds, which is what we were getting in Banned IPs. We assumed CloudFlare does a good job keeping those mappings (i.e. my real ip would always get the same CF IP), but I could never find that mapping anywhere, so I was stuck.

 

We tried to implement this https://developers.cloudflare.com/support/troubleshooting/restoring-visitor-ips/restoring-original-visitor-ips/ without success

 

I know the IPBanner code has changed now, but I haven't tested it yet. I know it's not looking at specific headers anymore.

Our issues were also related to IPv6 (some devices only communicated with IPv6), that were not being properly logged. It considered only the first group (4 digits), so it was likely that thousands of IPs would be considered banned as well. This has also been fixed in recent versions.

 

What we did was to mimic (as much as possible) the regex's from DW as WAF rules in CloudFlare. That way, CF only blocks the requests (and never reaches DW). That reduced our issues, because what we were having were infected computers (or bots, or malicious attempts, or ethical hacking classes) from Universities, which blocked their IPs, and other departments were trying to purchase on the site and were Banned.

 

Hope this helps.

 

Best Regards,

Nuno Aguiar

 
Nicolai Pedersen Dynamicweb Employee
Nicolai Pedersen
Reply

We changed DW9 so it will not read from the header directly as that can go wrong - so now there is an explicit setting for which header to read from if any.

In Dynamicweb 10.13 we have implemented ForwardedHeadersMiddleware  https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.httpoverrides.forwardedheadersmiddleware?view=aspnetcore-9.0

 
Nuno Aguiar Dynamicweb Employee
Nuno Aguiar
Reply

Hi Nicolai,

 

I don't see any change in DW9 (looking at the History of IpBanner.cs for DW9). I also checked active PRs for DW9 that could suggest it.

 

Are you sure someone changed it for DW9? Or you meant DW10?

 

Best Regards,

Nuno Aguiar

 

You must be logged in to post in the forum