web-dev-qa-db-ja.com

ASP.NETでユーザーのクライアントIPアドレスを取得する方法

ASP.NETでIPアドレスを取得するためのRequest.UserHostAddressがありますが、これは通常ユーザーのISPのIPアドレスであり、たとえばリンクをクリックしたユーザーのコンピュータのIPアドレスではありません。実際のIPアドレスを取得する方法

たとえば、Stack Overflowユーザープロファイルでは、"前回のアカウントアクティビティ:86.123.127.8から4時間前"ですが、私のマシンのIPアドレスは少し異なります。 Stack Overflowはこのアドレスをどのように取得しますか?

いくつかのWebシステムでは、いくつかの目的のためにIPアドレスチェックがあります。たとえば、特定のIPアドレスで、24時間ごとにダウンロードリンクを5回クリックするだけでいいのですか。このIPアドレスは一意である必要があります。広範囲のクライアントやインターネットユーザーがいるISPには使用しないでください。

私はよく理解しましたか?

358
Mehdi

他の人が言っているように、あなたはあなたが求めていることをすることはできません。あなたが解決しようとしている問題について説明しているなら、多分誰かが助けることができるでしょうか?例えば。あなたのユーザーを一意に識別しようとしていますか? IPアドレスの代わりにクッキー、またはおそらくセッションIDを使用できますか?

編集 あなたがそれが巨大な範囲になるだろうと言うようにあなたがサーバーで見るアドレスはISPのアドレスであるべきではありません。ブロードバンドでのホームユーザーのアドレスはルーターのアドレスになるため、家の中にあるすべてのデバイスは同じ外見でも同じように見えますが、ルーターはNATを使用してトラフィックを確実にルーティングします。各機器を正しく接続してください。オフィス環境からアクセスするユーザーの場合、アドレスはすべてのユーザーにとって同じである可能性があります。 IDにIPアドレスを使用するサイトでは、IPアドレスを誤って取得する危険性があります。あなたが挙げた例は良い例であり、しばしば失敗します。たとえば、私のオフィスはイギリスにあり、ブレークアウトポイント(インターネット上にあるように見える)は、私たちの主要なIT施設がある別の国にあるので、私のオフィスからは私のIPアドレスはイギリスにはないようです。このため、BBC iPlayerのように英国のみのWebコンテンツにはアクセスできません。私の会社には、同じIPアドレスからWebにアクセスしているように見える人々が何百人、何千人もいるでしょう。

あなたがサーバコードを書いているとき、あなたはあなたが見るIPアドレスが何を参照しているかを決して確かめることはできません。一部のユーザーはこのようにそれを好む。さらに混乱させるために故意にプロキシまたはVPNを使用している人もいます。

あなたのマシンアドレスがStackOverflowに表示されているIPアドレスと異なると言うとき、あなたはどのようにあなたのマシンアドレスを見つけていますか?あなたがipconfigまたはそのようなものを使ってローカルに見ているだけであれば、私が上で概説した理由のためにそれが異なることを期待するでしょう。外の世界が何を考えているのかを二重チェックしたい場合は、 whatismyipaddress.com/ を参照してください。

この ウィキペディアでNAT へのリンクを設定すると、これに関する背景情報が得られます。

133
Steve Haigh

多くの場合、あなたのウェブサイトを訪問している誰かのIPアドレスを知りたいでしょう。 ASP.NETには、これを行うためのいくつかの方法がありますが、私たちが見た中で最も良い方法の1つは、ServerVariablesコレクションの "HTTP_X_FORWARDED_FOR"を使用することです。

その理由は...

訪問者がプロキシサーバーまたはルーターの背後にいる場合、標準のRequest.UserHostAddressはプロキシサーバーまたはルーターのIPアドレスのみをキャプチャします。この場合、ユーザーのIPアドレスはサーバー変数( "HTTP_X_FORWARDED_FOR")に保存されます。

そのため、最初に「HTTP_X_FORWARDED_FOR」を確認し、空の場合は単にServerVariables("REMOTE_ADDR")を返します。

この方法は万全ではありませんが、より良い結果につながる可能性があります。以下は、VB.NETのASP.NETコードで、 James Crowleyのブログ投稿「Gotcha:HTTP_X_FORWARDED_FORは複数のIPアドレスを返します」

C#

protected string GetIPAddress()
{
    System.Web.HttpContext context = System.Web.HttpContext.Current; 
    string ipAddress = context.Request.ServerVariables["HTTP_X_FORWARDED_FOR"];

    if (!string.IsNullOrEmpty(ipAddress))
    {
        string[] addresses = ipAddress.Split(',');
        if (addresses.Length != 0)
        {
            return addresses[0];
        }
    }

    return context.Request.ServerVariables["REMOTE_ADDR"];
}

VB.NET

Public Shared Function GetIPAddress() As String
    Dim context As System.Web.HttpContext = System.Web.HttpContext.Current
    Dim sIPAddress As String = context.Request.ServerVariables("HTTP_X_FORWARDED_FOR")
    If String.IsNullOrEmpty(sIPAddress) Then
        Return context.Request.ServerVariables("REMOTE_ADDR")
    Else
        Dim ipArray As String() = sIPAddress.Split(New [Char]() {","c})
        Return ipArray(0)
    End If
End Function
426
mangokun

更新: Bruno Lopesに感謝します。複数のIPアドレスが来る可能性がある場合は、この方法を使用する必要があります。

    private string GetUserIP()
    {
        string ipList = Request.ServerVariables["HTTP_X_FORWARDED_FOR"];

        if (!string.IsNullOrEmpty(ipList))
        {
            return ipList.Split(',')[0];
        }

        return Request.ServerVariables["REMOTE_ADDR"];
    }
70
algreat

ユーザーIPアドレスについて他に何を検討しますか?ネットワークアダプタのIPアドレスが必要な場合は、Webアプリでそれを実行することは不可能です。あなたのユーザーがNATや他のものの背後にいる場合、あなたもIPを手に入れることができません。

更新 :(rapidshareのように)ユーザーを制限するためにIPを使用するWebサイトがありますが、NAT環境では正しく機能しません。

23
Mehrdad Afshari

このようにC#見れば、非常に簡単です

string clientIp = (Request.ServerVariables["HTTP_X_FORWARDED_FOR"] ?? 
                   Request.ServerVariables["REMOTE_ADDR"]).Split(',')[0].Trim();

私はあなたのすべてと私の経験を共有すべきだと思います。ええと、状況によってはREMOTE_ADDRはあなたが探しているものを手に入れられないでしょう。例えば、あなたがロードバランサを背後に持っていてクライアントのIPを手に入れようとしているなら、あなたは困っているでしょう。私は自分のIPマスキングソフトウェアでそれをチェックし、さらに私の同僚が異なる大陸にいることもチェックしました。

クライアントのIPを知りたいときは、可能性のあるすべての証拠を選び、それらが固有のものであるかどうかを判断します。

ここで私はあなたがクライアント側の正確なIPを取得したい場合あなた全員を助けることができるもう一つのサーバー変数を見つけました。だから私は使用しています:HTTP_X_CLUSTER_CLIENT_IP

HTTP_X_CLUSTER_CLIENT_IPは常にクライアントの正確なIPを取得します。値が表示されない場合は、クライアントIPを取得するための2番目に最適な候補としてHTTP_X_FORWARDED_FOR)を検索する必要があります。それからREMOTE_ADDRvar)あなたにIPを返すかもしれないし返さないかもしれませんが私にこれらの3つすべてを持っていることは私がそれらを監視するための最良のものを見つけるものです。

私はこれが何人かの人々に役立つことを願っています。

21
KMX

あなたが使用することができます:

System.Net.Dns.GetHostEntry(System.Net.Dns.GetHostName()).AddressList.GetValue(0).ToString();
15
Bat_Programmer

IPアドレスは、「7層スタック」内のネットワーク層の一部です。ネットワーク層は、IPアドレスを使ってやりたいことなら何でもできます。それが、プロキシサーバー、NAT、リレー、その他何でも起こります。

アプリケーション層はいかなる方法でもIPアドレスに依存してはいけません。特に、IPアドレスは、ネットワーク接続の一端の識別子以外の識別子になることを意味していません。接続が閉じられるとすぐに、(同じユーザーの)IPアドレスが変わることを期待する必要があります。

13
John Saunders

あなたがCloudFlareを使っているなら、あなたはこれを試すことができます Extension Method

public static class IPhelper
{
    public static string GetIPAddress(this HttpRequest Request)
    {
        if (Request.Headers["CF-CONNECTING-IP"] != null) return Request.Headers["CF-CONNECTING-IP"].ToString();

        if (Request.ServerVariables["HTTP_X_FORWARDED_FOR"] != null) return Request.ServerVariables["HTTP_X_FORWARDED_FOR"].ToString();

        return Request.UserHostAddress;
    }
}

それから

string IPAddress = Request.GetIPAddress();
9
Tony

これまでのすべての応答では、標準化されていないが very common、X-Forwarded-Forヘッダーが考慮されています。標準化された Forwarded ヘッダーがあり、これはもう少し解析が困難です。例をいくつか示します。

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

私はクライアントのIPアドレスを決定するときこれらのヘッダの両方を考慮に入れるクラスを書きました。

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)
        {
            // handle standardized 'Forwarded' header
            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 addresses are always enclosed in square brackets
                        int left = ip.IndexOf('['), right = ip.IndexOf(']');
                        if (left == 0 && right > 0)
                        {
                            return ip.Substring(1, right - 1);
                        }

                        // strip port of IPv4 addresses
                        int colon = ip.IndexOf(':');
                        if (colon != -1)
                        {
                            return ip.Substring(0, colon);
                        }

                        // this will return IPv4, "unknown", and obfuscated addresses
                        return ip;
                    }
                }
            }

            // handle non-standardized 'X-Forwarded-For' header
            string xForwardedFor = request.Headers["X-Forwarded-For"];
            if (!String.IsNullOrEmpty(xForwardedFor))
            {
                return xForwardedFor.Split(',')[0];
            }

            return request.UserHostAddress;
        }
    }
}

以下は、私が自分のソリューションを検証するために使用したいくつかの単体テストです。

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; }
        }
    }
}
8
dana
string IP = HttpContext.Current.Request.Params["HTTP_CLIENT_IP"] ?? HttpContext.Current.Request.UserHostAddress;
8
GorkemHalulu

あなたができることはあなたのユーザのルータIPと転送されたIPを保存し、両方のIPを使用してそれを信頼できるものにすることです[外部公衆と内部私有]。しかし、数日後にクライアントにもルーターから新しい内部IPが割り当てられる可能性がありますが、信頼性は高くなります。

7
Shahid

@Tony@mangokun の回答を組み合わせて、次の拡張メソッドを作成しました。

public static class RequestExtensions
{
    public static string GetIPAddress(this HttpRequest Request)
    {
        if (Request.Headers["CF-CONNECTING-IP"] != null) return Request.Headers["CF-CONNECTING-IP"].ToString();

        if (Request.ServerVariables["HTTP_X_FORWARDED_FOR"] != null)
        {
            string ipAddress = Request.ServerVariables["HTTP_X_FORWARDED_FOR"];

            if (!string.IsNullOrEmpty(ipAddress))
            {
                string[] addresses = ipAddress.Split(',');
                if (addresses.Length != 0)
                {
                    return addresses[0];
                }
            }
        }

        return Request.UserHostAddress;
    }
}
4
Nitesh

ashxファイルで使用

public string getIP(HttpContext c)
{
    string ips = c.Request.ServerVariables["HTTP_X_FORWARDED_FOR"];
    if (!string.IsNullOrEmpty(ips))
    {
        return ips.Split(',')[0];
    }
    return c.Request.ServerVariables["REMOTE_ADDR"];
}
3

こんにちはみんなあなたが見つけるコードのほとんどはあなたのクライアントのIPアドレスではなく、サーバーのIPアドレスを返します。ただし、このコードは正しいクライアントのIPアドレスを返します。試してみてください。詳細はこちらをチェック

https://www.youtube.com/watch?v=Nkf37DsxYjI

javascriptを使ってあなたのローカルIPアドレスを取得するためにあなたはあなたのscriptタグの中にこのコードを入れて使うことができます

<script>
    var RTCPeerConnection = /*window.RTCPeerConnection ||*/
     window.webkitRTCPeerConnection || window.mozRTCPeerConnection;

         if (RTCPeerConnection) (function () {
             var rtc = new RTCPeerConnection({ iceServers: [] });
             if (1 || window.mozRTCPeerConnection) {      
                 rtc.createDataChannel('', { reliable: false });
             };

             rtc.onicecandidate = function (evt) {

                 if (evt.candidate)
                     grepSDP("a=" + evt.candidate.candidate);
             };
             rtc.createOffer(function (offerDesc) {
                 grepSDP(offerDesc.sdp);
                 rtc.setLocalDescription(offerDesc);
             }, function (e) { console.warn("offer failed", e); });


             var addrs = Object.create(null);
             addrs["0.0.0.0"] = false;
             function updateDisplay(newAddr) {
                 if (newAddr in addrs) return;
                 else addrs[newAddr] = true;
                 var displayAddrs = Object.keys(addrs).filter(function
(k) { return addrs[k]; });
                 document.getElementById('list').textContent =
displayAddrs.join(" or perhaps ") || "n/a";
             }

             function grepSDP(sdp) {
                 var hosts = [];
                 sdp.split('\r\n').forEach(function (line) { 
                     if (~line.indexOf("a=candidate")) {   
                         var parts = line.split(' '),   
                             addr = parts[4],
                             type = parts[7];
                         if (type === 'Host') updateDisplay(addr);
                     } else if (~line.indexOf("c=")) {      
                         var parts = line.split(' '),
                             addr = parts[2];
                         updateDisplay(addr);
                     }
                 });
             }
         })(); else
         {
             document.getElementById('list').innerHTML = "<code>ifconfig| grep inet | grep -v inet6 | cut -d\" \" -f2 | tail -n1</code>";
             document.getElementById('list').nextSibling.textContent = "In Chrome and Firefox your IP should display automatically, by the power of WebRTCskull.";

         }




</script>
<body>
<div id="list"></div>
</body>

あなたのパブリックIPアドレスを取得するためには、あなたのscriptタグの中にこのコードを入れて使うことができます

  function getIP(json) {
    document.write("My public IP address is: ", json.ip);
  }


<script type="application/javascript" src="https://api.ipify.org?format=jsonp&callback=getIP"></script>
0
Shubham