67 votes

Obtenir l'adresse IP du client : REMOTE_ADDR, HTTP_X_FORWARDED_FOR, quoi d'autre pourrait être utile ?

Je comprends que c'est une pratique standard de regarder ces deux variables. Bien sûr, elles peuvent facilement être falsifiées. Je suis curieux de savoir à quelle fréquence on peut s'attendre à ce que ces valeurs (en particulier la variable HTTP_X_FORWARDED_FOR ) pour contenir de véritables informations et ne pas être simplement brouillées ou vidées de leurs valeurs ?

Quelqu'un a une expérience ou des statistiques sur ce sujet ?

Y a-t-il autre chose qui puisse être utile pour obtenir l'adresse IP du client ?

1 votes

Notez que la question et les réponses utilisent toutes deux le préfixe HTTP_, qui est un détail de mise en œuvre particulier d'ASP.NET v1.0-v4.x, lorsque les en-têtes de requête HTTP sont ajoutés à la collection ServerVariables. Un autre exemple est REMOTE_ADDR, qui a sa propre API dans ASP.NET Core. stackoverflow.com/questions/28664686/

65voto

ejunker Points 3442

En plus de REMOTE_ADDR y HTTP_X_FORWARDED_FOR il y a d'autres en-têtes qui peuvent être définis comme :

  • HTTP_CLIENT_IP
  • HTTP_X_FORWARDED_FOR peut être une liste d'IPs délimitée par des virgules.
  • HTTP_X_FORWARDED
  • HTTP_X_CLUSTER_CLIENT_IP
  • HTTP_FORWARDED_FOR
  • HTTP_FORWARDED

J'ai trouvé le code sur le site suivant utile :
http://www.grantburton.com/?p=97

0 votes

Cette liste est-elle en quelque sorte complète, c'est-à-dire qu'elle couvre plus de 90 % de tous les proxys ?

8 votes

Je ne pense pas que ces en-têtes devraient avoir le préfixe HTTP_... une petite recherche a permis d'aboutir à stackoverflow.com/questions/3834083/

0 votes

Il y a aussi un Referer maintenant, comme dans RFC 7239

32voto

annakata Points 42676

Cela dépend de la nature de votre site.

Il se trouve que je travaille sur un logiciel pour lequel le suivi des adresses IP est important, et dans un domaine consommé par des sites partenaires, je dirais que 20 à 40 % des demandes sont soit des adresses IP usurpées détectables, soit des en-têtes masqués, selon l'heure de la journée et leur provenance. Pour un site qui reçoit du trafic organique (c'est-à-dire qui ne passe pas par des partenaires), je m'attendrais à un ratio beaucoup plus élevé de bonnes IP.

Comme l'a dit Kosi, faites attention à ce que vous faites avec cela - les IP ne sont en aucun cas un moyen fiable d'identifier des visiteurs uniques.

10voto

IDisposable Points 1164

J'ai porté le code PHP de Grant Burton vers une méthode statique ASP.Net appelable par la HttpRequestBase. Il passera optionnellement par toutes les plages d'adresses IP privées.

public static class ClientIP
{
    // based on http://www.grantburton.com/2008/11/30/fix-for-incorrect-ip-addresses-in-wordpress-comments/
    public static string ClientIPFromRequest(this HttpRequestBase request, bool skipPrivate)
    {
        foreach (var item in s_HeaderItems)
        {
            var ipString = request.Headers[item.Key];

        if (String.IsNullOrEmpty(ipString))
            continue;

        if (item.Split)
        {
            foreach (var ip in ipString.Split(','))
                if (ValidIP(ip, skipPrivate))
                    return ip;
        }
        else
        {
            if (ValidIP(ipString, skipPrivate))
                return ipString;
        }
    }

    return request.UserHostAddress;
}

private static bool ValidIP(string ip, bool skipPrivate)
{
    IPAddress ipAddr;

    ip = ip == null ? String.Empty : ip.Trim();

    if (0 == ip.Length
        || false == IPAddress.TryParse(ip, out ipAddr)
        || (ipAddr.AddressFamily != AddressFamily.InterNetwork
            && ipAddr.AddressFamily != AddressFamily.InterNetworkV6))
        return false;

    if (skipPrivate && ipAddr.AddressFamily == AddressFamily.InterNetwork)
    {
        var addr = IpRange.AddrToUInt64(ipAddr);
        foreach (var range in s_PrivateRanges)
        {
            if (range.Encompasses(addr))
                return false;
        }
    }

    return true;
}

/// <summary>
/// Provides a simple class that understands how to parse and
/// compare IP addresses (IPV4) ranges.
/// </summary>
private sealed class IpRange
{
    private readonly UInt64 _start;
    private readonly UInt64 _end;

    public IpRange(string startStr, string endStr)
    {
        _start = ParseToUInt64(startStr);
        _end = ParseToUInt64(endStr);
    }

    public static UInt64 AddrToUInt64(IPAddress ip)
    {
        var ipBytes = ip.GetAddressBytes();
        UInt64 value = 0;

        foreach (var abyte in ipBytes)
        {
            value <<= 8;    // shift
            value += abyte;
        }

        return value;
    }

    public static UInt64 ParseToUInt64(string ipStr)
    {
        var ip = IPAddress.Parse(ipStr);
        return AddrToUInt64(ip);
    }

    public bool Encompasses(UInt64 addrValue)
    {
        return _start <= addrValue && addrValue <= _end;
    }

    public bool Encompasses(IPAddress addr)
    {
        var value = AddrToUInt64(addr);
        return Encompasses(value);
    }
};

private static readonly IpRange[] s_PrivateRanges =
    new IpRange[] { 
            new IpRange("0.0.0.0","2.255.255.255"),
            new IpRange("10.0.0.0","10.255.255.255"),
            new IpRange("127.0.0.0","127.255.255.255"),
            new IpRange("169.254.0.0","169.254.255.255"),
            new IpRange("172.16.0.0","172.31.255.255"),
            new IpRange("192.0.2.0","192.0.2.255"),
            new IpRange("192.168.0.0","192.168.255.255"),
            new IpRange("255.255.255.0","255.255.255.255")
    };

/// <summary>
/// Describes a header item (key) and if it is expected to be 
/// a comma-delimited string
/// </summary>
private sealed class HeaderItem
{
    public readonly string Key;
    public readonly bool Split;

    public HeaderItem(string key, bool split)
    {
        Key = key;
        Split = split;
    }
}

// order is in trust/use order top to bottom
private static readonly HeaderItem[] s_HeaderItems =
    new HeaderItem[] { 
            new HeaderItem("HTTP_CLIENT_IP",false),
            new HeaderItem("HTTP_X_FORWARDED_FOR",true),
            new HeaderItem("HTTP_X_FORWARDED",false),
            new HeaderItem("HTTP_X_CLUSTER_CLIENT_IP",false),
            new HeaderItem("HTTP_FORWARDED_FOR",false),
            new HeaderItem("HTTP_FORWARDED",false),
            new HeaderItem("HTTP_VIA",false),
            new HeaderItem("REMOTE_ADDR",false)
    };
}

2 votes

Merci pour le code. Il y a cependant un certain nombre de problèmes. Premièrement, il y a un élément supplémentaire return false; en ValidIP . Deuxièmement, la classe IpRange ne gère pas vraiment l'IPV6 puisque les adresses IPV6 sont de 128 bits. Peut-être que System.Numerics.BigInteger de .NET 4 pourrait être utilisé, mais il est également possible que les plages privées soient moins intéressantes avec IPV6 de toute façon ( ?).

2 votes

Oh, et un autre problème : au lieu de vérifier les en-têtes à partir de request.Headers, je pense que vous voulez request.ServerVariables. Ce dernier a des clés comme HTTP_X_FORWARDED_FOR alors que la première serait simplement X-Forwarded-For .

0 votes

Ce serait formidable si cela était également pris en charge RFC 7239 :D

7voto

Kosi2801 Points 9487

Je ne réponds pas vraiment à votre question mais :
En général, se baser sur l'adresse IP des clients n'est pas, à mon avis, une bonne pratique car elle ne permet pas d'identifier les clients de manière unique.

Les problèmes sur la route sont qu'il y a beaucoup de scénarios où l'IP ne correspond pas vraiment à un client :

  • Proxy/Webfilter (mangle presque tout)
  • Réseau d'anonymisation (aucune chance ici non plus)
  • NAT (une IP interne n'est pas très utile pour vous)
  • ...

Je ne peux pas offrir de statistiques sur le nombre d'adresses IP qui sont en moyenne fiable mais ce que je peux vous dire c'est qu'il est presque impossible de dire si une adresse IP donnée est la véritable adresse du client.

2voto

Mahesh Points 474

IP + "User Agent" pourrait être une meilleure solution pour un visiteur unique.

0 votes

Non, les agents utilisateurs ne sont pas très diversifiés et largement usurpés de toute façon.

6 votes

Largement usurpés, mais généralement ils ne changent pas d'une demande à l'autre - panopticlick.eff.org

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X