Alle bisherigen Antworten berücksichtigen den nicht standardisierten, aber sehr verbreiteten X-Forwarded-For
-Header. Es gibt einen standardisierten Forwarded
-Header, der etwas schwieriger auszulesen ist. Einige Beispiele sind wie folgt:
Forwarded: for="_gazonk"
Forwarded: For="[2001:db8:cafe::17]:4711"
Forwarded: for=192.0.2.60;proto=http;by=203.0.113.43
Forwarded: for=192.0.2.43, for=198.51.100.17
Ich habe eine Klasse geschrieben, die beide dieser Header berücksichtigt, um die IP-Adresse des Clients zu bestimmen.
using System;
using System.Web;
namespace Util
{
public static class IP
{
public static string GetIPAddress()
{
return GetIPAddress(new HttpRequestWrapper(HttpContext.Current.Request));
}
internal static string GetIPAddress(HttpRequestBase request)
{
// Behandlung des standardisierten 'Forwarded'-Headers
string forwarded = request.Headers["Forwarded"];
if (!String.IsNullOrEmpty(forwarded))
{
foreach (string segment in forwarded.Split(',')[0].Split(';'))
{
string[] pair = segment.Trim().Split('=');
if (pair.Length == 2 && pair[0].Equals("for", StringComparison.OrdinalIgnoreCase))
{
string ip = pair[1].Trim('"');
// IPv6-Adressen sind immer in eckigen Klammern eingebettet
int left = ip.IndexOf('['), right = ip.IndexOf(']');
if (left == 0 && right > 0)
{
return ip.Substring(1, right - 1);
}
// Entfernen des Ports von IPv4-Adressen
int colon = ip.IndexOf(':');
if (colon != -1)
{
return ip.Substring(0, colon);
}
// Diese werden IPv4-, "unknown"- und obfuszierte Adressen zurückgeben
return ip;
}
}
}
// Behandlung des nicht standardisierten 'X-Forwarded-For'-Headers
string xForwardedFor = request.Headers["X-Forwarded-For"];
if (!String.IsNullOrEmpty(xForwardedFor))
{
return xForwardedFor.Split(',')[0];
}
return request.UserHostAddress;
}
}
}
Unten sind einige Unit-Tests aufgeführt, die ich zur Validierung meiner Lösung verwendet habe:
using System.Collections.Specialized;
using System.Web;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace UtilTests
{
[TestClass]
public class IPTests
{
[TestMethod]
public void TestForwardedObfuscated()
{
var request = new HttpRequestMock("for=\"_gazonk\"");
Assert.AreEqual("_gazonk", Util.IP.GetIPAddress(request));
}
[TestMethod]
public void TestForwardedIPv6()
{
var request = new HttpRequestMock("For=\"[2001:db8:cafe::17]:4711\"");
Assert.AreEqual("2001:db8:cafe::17", Util.IP.GetIPAddress(request));
}
[TestMethod]
public void TestForwardedIPv4()
{
var request = new HttpRequestMock("for=192.0.2.60;proto=http;by=203.0.113.43");
Assert.AreEqual("192.0.2.60", Util.IP.GetIPAddress(request));
}
[TestMethod]
public void TestForwardedIPv4WithPort()
{
var request = new HttpRequestMock("for=192.0.2.60:443;proto=http;by=203.0.113.43");
Assert.AreEqual("192.0.2.60", Util.IP.GetIPAddress(request));
}
[TestMethod]
public void TestForwardedMultiple()
{
var request = new HttpRequestMock("for=192.0.2.43, for=198.51.100.17");
Assert.AreEqual("192.0.2.43", Util.IP.GetIPAddress(request));
}
}
public class HttpRequestMock : HttpRequestBase
{
private NameValueCollection headers = new NameValueCollection();
public HttpRequestMock(string forwarded)
{
headers["Forwarded"] = forwarded;
}
public override NameValueCollection Headers
{
get { return this.headers; }
}
}
}
4 Stimmen
Sie tun in der Regel dasselbe und funktionieren nicht korrekt für gemeinsam genutzte IP-Adressen. In diesem Bereich kann nicht viel getan werden.
0 Stimmen
Was ist das Problem, das Sie hier lösen möchten, warum glauben Sie, dass Sie die IP-Adresse benötigen?
4 Stimmen
Ich habe eine Anwendung, die spezifische Link-Klicks überprüft, und ein spezifischer Benutzer (nach IP) kann den Link an einem Tag nicht mehr als 5 Mal klicken. Das Problem ist, ob Request.UserHostAddress für eine Gruppe von Benutzern unter einem ISP oder Netzwerk oder für einen bestimmten Benutzer ist.