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


387

我々は持っているRequest.UserHostAddressASP.NETでIPアドレスを取得するが、これは通常、ユーザーのISPのIPアドレス、例えばリンクをクリックされていない正確にユーザーのマシンのIPアドレスです。実際のIPアドレスを取得するにはどうすればよいですか?

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

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

よくわかりましたか?


4
通常、これらは同じことを行い、共有IPアドレスに対しては正しく機能しません。この領域でできることは多くありません。
Mehrdad Afshari、

ここで解決しようとしている問題は何ですか?なぜIPアドレスが必要だと思いますか?
スティーブ、

3
特定のリンクのクリックをチェックするアプリケーションがあり、特定のユーザー(IPによる)が1日に5回を超えてリンクをクリックできない。問題は、Request.UserHostAddressがISPまたはネットワークの範囲のユーザーの場合特定のユーザーのもの?
Mehdi、

回答:


142

他の人が言っているように、あなたが求めていることを行うことはできません。あなたが解決しようとしている問題について説明した場合、誰かが助けることができますか?

例えば

  • ユーザーを一意に識別しようとしていますか?
  • IPアドレスの代わりにCookieまたはセッションIDを使用できますか?

編集するサーバー上に表示されるアドレスは、ISPのアドレスであってはなりません。これは、非常に大きな範囲となるからです。ブロードバンドのホームユーザーのアドレスはルーターのアドレスになるため、家の中のすべてのデバイスは同じように外側に表示されますが、ルーターはNATを使用してトラフィックが各デバイスに正しくルーティングされるようにします。オフィス環境からアクセスするユーザーの場合、アドレスはすべてのユーザーで同じになる可能性があります。IDにIPアドレスを使用するサイトは、それを非常に間違ってしまうリスクを冒します-あなたが与える例は良いものであり、しばしば失敗します。たとえば、私のオフィスは英国にあり、ブレイクアウトポイント(インターネット上にあるように見えます)は、主要なIT施設がある別の国にあるため、私のオフィスからはIPアドレスが英国にないようです。このため、英国のWebコンテンツのみにアクセスすることはできません。BBC iPlayerなど)。私の会社では、同じIPアドレスからWebにアクセスしているように見える何百人、または何千人ものユーザーが常に存在します。

サーバーコードを記述しているときは、表示されているIPアドレスが何を指しているのかはわかりません。一部のユーザーはこのようにそれを好みます。一部の人々は、あなたをさらに混乱させるために、意図的にプロキシまたはVPNを使用します。

マシンアドレスがStackOverflowに表示されるIPアドレスと異なると言うとき、どのようにマシンアドレスを見つけますか?ローカルで使用しているだけのipconfigような場合は、上記で概説した理由により、異なるものになると思います。外部の世界の考えを再確認したい場合はwhatismyipaddress.com/をご覧ください

NATに関するこのWikipediaのリンクは、これに関するいくつかの背景を提供します。


サーバー側のアプリケーションでは、IPアドレスについて確信が持てないことを理解しました。それはクライアント側のプログラミングが解決策であることを意味しますか?たとえば、一部のJavaScriptコードを使用すると、それを実行できますか?
Mehdi、

12
いいえ、これは無意味です。クライアントが「考える」IPアドレスは、自宅やオフィスの内部にあり、外の世界では意味がありません。たとえば、ほとんどのホームルーターは192.168.1.xxxの範囲のIPアドレスを配布するため、何千ものマシンが独自のネットワークで同じアドレスを持っています。
スティーブ、

12
いいえ、ユニークではありません。NATを使用する同じルーターの背後にいる2人のユーザーは、同じIPアドレスを持っています。私は本当にこれを読む必要があると思います、私の編集のリンクを参照してください。
スティーブ

1
では、AWS、Azureなどの企業がセキュリティグループルールでIPアドレスを使用し、そのIPアドレスのみがVMに接続することを許可するのはなぜですか?

2
@ user5950947:Azureは静的なパブリックIPアドレスを持つ会社であると想定しているためです。会社はパブリックIPアドレスからのみアクセスすることを想定しているので安全です。そのため、これは優れたセキュリティ機能です。しかし、IPアドレスが偽造されたり、ネットワークがハッキングされたりする可能性があるため、唯一のセキュリティであってはなりません。
Deantwo、

449

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

その理由は...

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

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

この方法は確実ではありませんが、より良い結果をもたらす可能性があります。以下は、James Crowleyのブログ投稿「Gotcha:HTTP_X_FORWARDED_FOR returns multiple IP addresses」からのVB.NETのASP.NETコードです

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

24
誰もがHTTP_X_FORWARDED_FORまたは同様のヘッダーを偽造できるため、セキュリティの目的でこのコードを使用しないでください。したがって、これをセキュリティ関連のロギングまたはセキュリティチェックに使用すると、攻撃者は簡単にこれをバイパスできます。
dr。邪悪な

4
あなたのリンクからwhat we actually needed to be doing was take the last IP address、しかしあなたのコードは最初のものを得ますaddresses[0]。どちらが正しい?
ネルソンロザーメル2014

4
@NelsonRothermel en.wikipedia.org/wiki/X-Forwarded-For#Formatに基づいて、(前のプロキシではなく)クライアントが必要な場合は、最初のを使用します。
Richard

4
@ dr.evilでは、代わりに何を提案しますか?指定したIPでWCFサービスのアクセスを設定したいので。
krypru 2015

7
addresses.Length != 0それが0になることはありませんから、必要はありません
ジェームズウィルキンス

78

更新: 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"];
    }

3
別の回答で述べたように、HTTP_X_FORWARDED_FORは、コンマで区切られたIPのリストにすることができます。
ブルーノロペス2012

関数に応答して、毎回:: 1を取得します。完全なIPアドレスを取得できませんか???
ファルハンドン

1
ローカルホストで:: 1を返します。productino環境でそれを試してみて、それは問題ないはずです。
Benny Margalit

1
@ farhangdon、@ Bat_Programmerが下に書いたように、次のコードはローカルホストのIPアドレスを返しますSystem.Net.Dns.GetHostEntry(System.Net.Dns.GetHostName()).AddressList[1].ToString();
Benny Margalit

これをしないでください!リストの最初のIPアドレスを単純に使用しないように注意してください。中間者攻撃やヘッダースプーフィングを回避するために、右端のエントリから始まる既知のプロキシIPのみをスキップする必要があります。
Jpsy

24

C#の場合、このように表示され、非常に簡単です

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

8
両方のサーバー変数がnullになる可能性がある場合、例外がスローされる可能性があります。
Michael Freidgeim 2016

ここでのリクエスト参照とは何ですか?ServerVariablesが見つかりません
Brownbagger11

23

ユーザーIPアドレスは他に何を考慮しますか?ネットワークアダプターのIPアドレスが必要な場合は、Webアプリで実行する方法はありません。ユーザーがNATなどの背後にいる場合、IPも取得できません。

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


22

私の経験を皆さんと共有したいと思います。まあ、状況によっては、REMOTE_ADDRが目的の情報を取得できないこともあります。たとえば、舞台裏にロードバランサーがあり、クライアントのIPを取得しようとしている場合、問題が発生します。私は自分のIPマスキングソフトウェアでそれをチェックし、さらに別の大陸にいる同僚もチェックしました。これが私の解決策です。

クライアントのIPを知りたい場合は、可能な限りすべての証拠を選択して、それらが一意であるかどうかを判断できるようにします。

ここで、クライアント側の正確なIPを取得したい場合に役立つすべてのsever-varを見つけました。だから私は使用しています:HTTP_X_CLUSTER_CLIENT_IP

HTTP_X_CLUSTER_CLIENT_IPは常にクライアントの正確なIPを取得します。いずれにしても、値がられない場合は、HTTP_X_FORWARDED_FORを探す必要があります。これは、クライアントIPを取得する2番目に最適な候補であり、次にREMOTE_ADDR 変数が IPを返す場合と返さない場合がありますが、これらすべてを持っているためです。 3つは、それらを監視するのに最適なものです。

これが一部の人に役立つことを願っています。


http_x _...ヘッダーは、remote_addr変数に対して簡単に偽装される可能性があると言う必要があります。したがって、remote_addrは引き続きクライアントIPアドレスの最も信頼できるソースです。
Ciro Corvino 2017年

1
@CiroCorvinoは正しいですが、ロードバランサーの背後で実行されているサーバーでWebサイトをホストしている場合(既に投稿で述べたように)、remote_addrは探しているIPを提供しません。私はあなたが言っていることを経験しましたが、私が解決策を掘ったとき、私が述べたことが私にとって最もうまくいきます。
KMX

申し訳ありませんが、@ KMX、実際には、remote_addrとhttp_x_forwardedの組み合わせを使用して、要求の発信元についていくつかの仮定を推測しています。投稿を編集した場合、私の投票を更新します
Ciro Corvino '22

15

以下を使用できます。

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

1
おかげで、私にとってこれは本当にローカルホストで私のIPを返す唯一の方法です。
Benny Margalit

実際、私がローカルホストのIPアドレスを取得するために使用しているのはSystem.Net.Dns.GetHostEntry(System.Net.Dns.GetHostName()).AddressList[1].ToString();
Benny Margalit

1
このコードは私にのみ機能し、GetValue(0)およびGetValue(1)をそれぞれ使用してIPv6およびIPv4を取得できます。投票ありがとうございます!
Raj Baral 2018年

ただし、フィドルで実行中にエラーが発生します Request for the permission of type 'System.Net.DnsPermission, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' failed.
vibs2006

OPは、自分のローカルホストのアドレスではなく、リモートWebユーザーのIPを取得する方法を尋ねます。
t.durden

13

IPアドレスは、「7層スタック」のネットワーク層の一部です。ネットワーク層は、IPアドレスを使用してやりたいことをすべて実行できます。これが、プロキシサーバー、NAT、リレーなどで起こります。

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


1
これで問題ありませんが、マルチテナントシステムの1人の顧客が、ユーザーのアカウントが指定されたIPアドレスからのみログインできるように要求した場合はどうしますか?
ロニーオーバーバイ2012

1
次に、サーバーが表示するIPアドレスを通知する必要があります。特定のアドレスが必要な場合、NATなどの背後にいることはできません。
ジョンサンダース

@RonnieOverby私も同じ状況です。彼らがどのIPから接続しているのかを知る必要があり、それが私のホワイトリストに含まれている必要があります。その後、アプリはIPに基づいて特定の機能をオンまたはオフにできます。これがお客様の希望です。
t.durden

10

これまでのすべての応答では、標準化されていないが非常に一般的な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; }
        }
    }
}

9

CloudFlareを使用している場合は、この拡張メソッドを試すことができます。

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();

そして、F5またはパロアルトを使用していますか?
Kiquenet 2018

8
string IP = HttpContext.Current.Request.Params["HTTP_CLIENT_IP"] ?? HttpContext.Current.Request.UserHostAddress;

7

できることは、ユーザーのルーターIPと転送されたIPを保存し、両方のIP [外部パブリックと内部プライベート]を使用して信頼できるようにすることです。しかし、数日後、クライアントにはルーターから新しい内部IPが割り当てられる可能性がありますが、信頼性は向上します。


5

@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;
    }
}

なぜあなたは使用しないHTTP_X_FORWARDED_FORではありませんかX_FORWARDED_FOR?彼らは同じですか?
Igor Yalovoy

3

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"];
}

2
public static class Utility
{
    public static string GetClientIP(this System.Web.UI.Page page)
    {
        string _ipList = page.Request.Headers["CF-CONNECTING-IP"].ToString();
        if (!string.IsNullOrWhiteSpace(_ipList))
        {
            return _ipList.Split(',')[0].Trim();
        }
        else
        {
            _ipList = page.Request.ServerVariables["HTTP_X_CLUSTER_CLIENT_IP"];
            if (!string.IsNullOrWhiteSpace(_ipList))
            {
                return _ipList.Split(',')[0].Trim();
            }
            else
            {
                _ipList = page.Request.ServerVariables["HTTP_X_FORWARDED_FOR"];
                if (!string.IsNullOrWhiteSpace(_ipList))
                {
                    return _ipList.Split(',')[0].Trim();
                }
                else
                {
                    return page.Request.ServerVariables["REMOTE_ADDR"].ToString().Trim();
                }
            }
        }
    }
}

使用する;

string _ip = this.GetClientIP();

0

簡単です。お試しください。

var remoteIpAddress = Request.HttpContext.Connection.RemoteIpAddress;

それだけ :))


1
参考までに、上記のコードはAsp.Net Coreでのみ機能し、通常のAsp.Net リンクで
Dobin

-1

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

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

JavaScriptを使用してローカルIPアドレスを取得するには、このコードをスクリプトタグ内に配置します

<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アドレスを取得するには、このコードをスクリプトタグ内に配置します

  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>


-7

試してください:

using System.Net;

public static string GetIpAddress()  // Get IP Address
{
    string ip = "";     
    IPHostEntry ipEntry = Dns.GetHostEntry(GetCompCode());
    IPAddress[] addr = ipEntry.AddressList;
    ip = addr[2].ToString();
    return ip;
}
public static string GetCompCode()  // Get Computer Name
{   
    string strHostName = "";
    strHostName = Dns.GetHostName();
    return strHostName;
}

これはサーバーのIPアドレスを返します
Sreekumar P

これは、ユーザーのコンピューターではなくサーバー上で実行されるWebアプリケーションであるasp.netに関するものです。
doekman
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.