ASP.NET MVC에서 클라이언트의 IP 주소를 어떻게 얻을 수 있습니까?


311

ASP.NET MVC 스택을 처음 접했을 때 간단한 Page 개체와 Request ServerVariables 개체가 어떻게되는지 궁금했습니다.

기본적으로 클라이언트 PC의 IP 주소를 꺼내고 싶지만 현재 MVC 구조가 어떻게이 모든 것을 변경했는지 이해하지 못합니다.

내가 이해할 수있는 한, 대부분의 변수 객체는 HttpRequest variant로 대체되었습니다 .

누구나 자원을 공유하고 싶어? ASP.NET MVC 세계에는 실제로 배울 것이 많습니다. :)

예를 들어이 현재 함수가있는 정적 클래스가 있습니다. ASP.NET MVC를 사용하여 동일한 결과를 얻으려면 어떻게해야합니까?

public static int getCountry(Page page)
{
    return getCountryFromIP(getIPAddress(page));
}

public static string getIPAddress(Page page)
{
    string szRemoteAddr = page.Request.ServerVariables["REMOTE_ADDR"];
    string szXForwardedFor = page.Request.ServerVariables["X_FORWARDED_FOR"];
    string szIP = "";

    if (szXForwardedFor == null)
    {
        szIP = szRemoteAddr;
    }
    else
    {
        szIP = szXForwardedFor;

        if (szIP.IndexOf(",") > 0)
        {
            string [] arIPs = szIP.Split(',');

            foreach (string item in arIPs)
            {
                if (!isPrivateIP(item))
                {
                    return item;
                }
            }
        }
    }
    return szIP;
}

컨트롤러 페이지에서이 함수를 어떻게 호출합니까?



답변:


427

간단한 대답은 HttpRequest.UserHostAddress 속성 을 사용하는 것 입니다.

예 : 컨트롤러 내에서 :

using System;
using System.Web.Mvc;

namespace Mvc.Controllers
{
    public class HomeController : ClientController
    {
        public ActionResult Index()
        {
            string ip = Request.UserHostAddress;

            ...
        }
    }
}

예 : 도우미 클래스 내에서 :

using System.Web;

namespace Mvc.Helpers
{
    public static class HelperClass
    {
        public static string GetIPHelper()
        {
            string ip = HttpContext.Current.Request.UserHostAddress;
            ..
        }
    }
}

그러나 요청이 하나 이상의 프록시 서버 에 의해 전달 된 경우 HttpRequest.UserHostAddress 특성에 의해 리턴 된 IP 주소는 요청을 릴레이 한 마지막 프록시 서버의 IP 주소가됩니다.

프록시 서버는 수도 를 사용하는 사실상의 에서 클라이언트의 IP 주소를 배치의 표준 X-전달-를 들어 HTTP 헤더를. 요청에 X-Forwarded-For 헤더가 있다는 보장은 없지만 X-Forwarded-For가 SPOOFED 되지 않았다는 보장도 없습니다 .


원래 답변

Request.UserHostAddress

위의 코드는 모음을 조회하지 않고도 클라이언트의 IP 주소를 제공합니다. 요청 속성은 컨트롤러 (또는 뷰) 내에서 사용할 수 있습니다. 따라서 Page 클래스를 함수에 전달하는 대신 Request 객체를 전달하여 동일한 결과를 얻을 수 있습니다.

public static string getIPAddress(HttpRequestBase request)
{
    string szRemoteAddr = request.UserHostAddress;
    string szXForwardedFor = request.ServerVariables["X_FORWARDED_FOR"];
    string szIP = "";

    if (szXForwardedFor == null)
    {
        szIP = szRemoteAddr;
    }
    else
    {
        szIP = szXForwardedFor;
        if (szIP.IndexOf(",") > 0)
        {
            string [] arIPs = szIP.Split(',');

            foreach (string item in arIPs)
            {
                if (!isPrivateIP(item))
                {
                    return item;
                }
            }
        }
    }
    return szIP;
}

6
@ makerofthings7 : 여러 프록시 서버가 클라이언트의 HTTP 요청을 따라 전달 될 수 있으므로 여러 값이있을 수 있습니다. 프록시 서버가 의도적으로 익명 프록시 나 잘못 프로그래밍 된 프록시와 달리 "잘 동작"하면 각각 XFF 헤더에서 이전 프록시의 IP에 고정됩니다.
Eric J.

14
isPrivateIP 메소드는 무엇을합니까?
eddiegroves

19
":: 1"은 localhost를 의미합니다. 간단한 메모입니다.
tomg

5
X-Forwarded-For 헤더는 패킷을 분석하고 중간에 사람 역할을하는 방화벽 및로드 밸런서에 의해 추가됩니다. 원래 사용자의 IP 주소를 유지하기 위해이 헤더가 추가되어 원래 정보를 검색 할 수 있습니다. 패킷을 다시 쓸 때 새 IP 주소는 일반적으로 내부 IP이며 그다지 유용하지 않습니다.
Marko

2
고마워요.
잭 페어 필드

168

Request.ServerVariables["REMOTE_ADDR"] 뷰 또는 컨트롤러 조치 메소드 본문에서 직접 작동해야합니다 (요청은 페이지가 아닌 MVC에서 컨트롤러 클래스의 특성 임).

작동하지만. 가상 IIS가 아닌 실제 IIS에 게시해야합니다.


컨트롤러 쪽에서 어떻게 호출합니까?
melaos

롤, 이봐, 작동합니다, 위와 같이 클래스 객체에 넣으려면 어떻게됩니까? 여전히 페이지 개체가 필요합니까?
melaos

11
난 당신이 HttpContext.Current.Request를 사용할 수 있다고 생각
ovolko

23
Adrian의 대답 (아래)이 훨씬 낫습니다. 마법 문자열로 조회 할 필요가 없습니다. Request.UserHostAddress 사용
csauve

항상 내 앱을 실행하는 서버의 IP 주소를 반환합니다. 이유가 무엇입니까?
Jack Marchetti

101

여기에있는 많은 코드가 매우 도움이되었지만 목적을 위해 정리하고 테스트를 추가했습니다. 내가 끝내었던 것은 다음과 같습니다.

using System;
using System.Linq;
using System.Net;
using System.Web;

public class RequestHelpers
{
    public static string GetClientIpAddress(HttpRequestBase request)
    {
        try
        {
            var userHostAddress = request.UserHostAddress;

            // Attempt to parse.  If it fails, we catch below and return "0.0.0.0"
            // Could use TryParse instead, but I wanted to catch all exceptions
            IPAddress.Parse(userHostAddress);

            var xForwardedFor = request.ServerVariables["X_FORWARDED_FOR"];

            if (string.IsNullOrEmpty(xForwardedFor))
                return userHostAddress;

            // Get a list of public ip addresses in the X_FORWARDED_FOR variable
            var publicForwardingIps = xForwardedFor.Split(',').Where(ip => !IsPrivateIpAddress(ip)).ToList();

            // If we found any, return the last one, otherwise return the user host address
            return publicForwardingIps.Any() ? publicForwardingIps.Last() : userHostAddress;
        }
        catch (Exception)
        {
            // Always return all zeroes for any failure (my calling code expects it)
            return "0.0.0.0";
        }
    }

    private static bool IsPrivateIpAddress(string ipAddress)
    {
        // http://en.wikipedia.org/wiki/Private_network
        // Private IP Addresses are: 
        //  24-bit block: 10.0.0.0 through 10.255.255.255
        //  20-bit block: 172.16.0.0 through 172.31.255.255
        //  16-bit block: 192.168.0.0 through 192.168.255.255
        //  Link-local addresses: 169.254.0.0 through 169.254.255.255 (http://en.wikipedia.org/wiki/Link-local_address)

        var ip = IPAddress.Parse(ipAddress);
        var octets = ip.GetAddressBytes();

        var is24BitBlock = octets[0] == 10;
        if (is24BitBlock) return true; // Return to prevent further processing

        var is20BitBlock = octets[0] == 172 && octets[1] >= 16 && octets[1] <= 31;
        if (is20BitBlock) return true; // Return to prevent further processing

        var is16BitBlock = octets[0] == 192 && octets[1] == 168;
        if (is16BitBlock) return true; // Return to prevent further processing

        var isLinkLocalAddress = octets[0] == 169 && octets[1] == 254;
        return isLinkLocalAddress;
    }
}

그리고 그 코드에 대한 NUnit 테스트가 있습니다 (Rhino Mocks를 사용하여 아래의 M <HttpRequestBase> 호출 인 HttpRequestBase를 조롱합니다).

using System.Web;
using NUnit.Framework;
using Rhino.Mocks;
using Should;

[TestFixture]
public class HelpersTests : TestBase
{
    HttpRequestBase _httpRequest;

    private const string XForwardedFor = "X_FORWARDED_FOR";
    private const string MalformedIpAddress = "MALFORMED";
    private const string DefaultIpAddress = "0.0.0.0";
    private const string GoogleIpAddress = "74.125.224.224";
    private const string MicrosoftIpAddress = "65.55.58.201";
    private const string Private24Bit = "10.0.0.0";
    private const string Private20Bit = "172.16.0.0";
    private const string Private16Bit = "192.168.0.0";
    private const string PrivateLinkLocal = "169.254.0.0";

    [SetUp]
    public void Setup()
    {
        _httpRequest = M<HttpRequestBase>();
    }

    [TearDown]
    public void Teardown()
    {
        _httpRequest = null;
    }

    [Test]
    public void PublicIpAndNullXForwardedFor_Returns_CorrectIp()
    {
        // Arrange
        _httpRequest.Stub(x => x.UserHostAddress).Return(GoogleIpAddress);
        _httpRequest.Stub(x => x.ServerVariables[XForwardedFor]).Return(null);

        // Act
        var ip = RequestHelpers.GetClientIpAddress(_httpRequest);

        // Assert
        ip.ShouldEqual(GoogleIpAddress);
    }

    [Test]
    public void PublicIpAndEmptyXForwardedFor_Returns_CorrectIp()
    {
        // Arrange
        _httpRequest.Stub(x => x.UserHostAddress).Return(GoogleIpAddress);
        _httpRequest.Stub(x => x.ServerVariables[XForwardedFor]).Return(string.Empty);

        // Act
        var ip = RequestHelpers.GetClientIpAddress(_httpRequest);

        // Assert
        ip.ShouldEqual(GoogleIpAddress);
    }

    [Test]
    public void MalformedUserHostAddress_Returns_DefaultIpAddress()
    {
        // Arrange
        _httpRequest.Stub(x => x.UserHostAddress).Return(MalformedIpAddress);
        _httpRequest.Stub(x => x.ServerVariables[XForwardedFor]).Return(null);

        // Act
        var ip = RequestHelpers.GetClientIpAddress(_httpRequest);

        // Assert
        ip.ShouldEqual(DefaultIpAddress);
    }

    [Test]
    public void MalformedXForwardedFor_Returns_DefaultIpAddress()
    {
        // Arrange
        _httpRequest.Stub(x => x.UserHostAddress).Return(GoogleIpAddress);
        _httpRequest.Stub(x => x.ServerVariables[XForwardedFor]).Return(MalformedIpAddress);

        // Act
        var ip = RequestHelpers.GetClientIpAddress(_httpRequest);

        // Assert
        ip.ShouldEqual(DefaultIpAddress);
    }

    [Test]
    public void SingleValidPublicXForwardedFor_Returns_XForwardedFor()
    {
        // Arrange
        _httpRequest.Stub(x => x.UserHostAddress).Return(GoogleIpAddress);
        _httpRequest.Stub(x => x.ServerVariables[XForwardedFor]).Return(MicrosoftIpAddress);

        // Act
        var ip = RequestHelpers.GetClientIpAddress(_httpRequest);

        // Assert
        ip.ShouldEqual(MicrosoftIpAddress);
    }

    [Test]
    public void MultipleValidPublicXForwardedFor_Returns_LastXForwardedFor()
    {
        // Arrange
        _httpRequest.Stub(x => x.UserHostAddress).Return(GoogleIpAddress);
        _httpRequest.Stub(x => x.ServerVariables[XForwardedFor]).Return(GoogleIpAddress + "," + MicrosoftIpAddress);

        // Act
        var ip = RequestHelpers.GetClientIpAddress(_httpRequest);

        // Assert
        ip.ShouldEqual(MicrosoftIpAddress);
    }

    [Test]
    public void SinglePrivateXForwardedFor_Returns_UserHostAddress()
    {
        // Arrange
        _httpRequest.Stub(x => x.UserHostAddress).Return(GoogleIpAddress);
        _httpRequest.Stub(x => x.ServerVariables[XForwardedFor]).Return(Private24Bit);

        // Act
        var ip = RequestHelpers.GetClientIpAddress(_httpRequest);

        // Assert
        ip.ShouldEqual(GoogleIpAddress);
    }

    [Test]
    public void MultiplePrivateXForwardedFor_Returns_UserHostAddress()
    {
        // Arrange
        _httpRequest.Stub(x => x.UserHostAddress).Return(GoogleIpAddress);
        const string privateIpList = Private24Bit + "," + Private20Bit + "," + Private16Bit + "," + PrivateLinkLocal;
        _httpRequest.Stub(x => x.ServerVariables[XForwardedFor]).Return(privateIpList);

        // Act
        var ip = RequestHelpers.GetClientIpAddress(_httpRequest);

        // Assert
        ip.ShouldEqual(GoogleIpAddress);
    }

    [Test]
    public void MultiplePublicXForwardedForWithPrivateLast_Returns_LastPublic()
    {
        // Arrange
        _httpRequest.Stub(x => x.UserHostAddress).Return(GoogleIpAddress);
        const string privateIpList = Private24Bit + "," + Private20Bit + "," + MicrosoftIpAddress + "," + PrivateLinkLocal;
        _httpRequest.Stub(x => x.ServerVariables[XForwardedFor]).Return(privateIpList);

        // Act
        var ip = RequestHelpers.GetClientIpAddress(_httpRequest);

        // Assert
        ip.ShouldEqual(MicrosoftIpAddress);
    }
}

2
이것은 항상 내 응용 프로그램을 실행하는 서버의 IP 주소를 반환합니다.
Jack Marchetti

1
publicForwardingIps.First()?를 반환하지 않아야 합니까?
andy250

1
@Noah IPv6 주소에서는 작동하지 않는 것 같습니다.
AidanO

좋은 해결책! 다른 IP 주소에서도 IPAddress.Parse ()를 사용해야합니까?
Co-der

21

위의 내용을 사용하는 데 문제가 있었고 컨트롤러의 IP 주소가 필요했습니다. 결국 다음을 사용했습니다.

System.Web.HttpContext.Current.Request.UserHostAddress

2
컨트롤러에서 할 일은HttpContext.Request.UserHostAddress
Serj Sagan

감사. 컨트롤러 또는 뷰 컨텍스트가 아닌 도우미 클래스에 필요한 것. 이것은 좋은 보편적 인 답변입니다. +1
Piotr Kula 2016 년

@gander 무슨 뜻인가요? 호, 나는 진술을 써야합니까?
Piotr Kula

1
헬퍼 클래스의 맨 위에 "using System.Web;"을 작성하면 "HttpContext.Current.Request.UserHostAddress"만 작성하면됩니다. 나 같은 게으른 프로그래머를
위해서만

19

클래스에서는 다음과 같이 호출 할 수 있습니다.

public static string GetIPAddress(HttpRequestBase request) 
{
    string ip;
    try
    {
        ip = request.ServerVariables["HTTP_X_FORWARDED_FOR"];
        if (!string.IsNullOrEmpty(ip))
        {
            if (ip.IndexOf(",") > 0)
            {
                string[] ipRange = ip.Split(',');
                int le = ipRange.Length - 1;
                ip = ipRange[le];
            }
        } else
        {
            ip = request.UserHostAddress;
        }
    } catch { ip = null; }

    return ip; 
}

나는 이것을 면도기 앱에서 사용하여 훌륭한 결과를 얻었습니다.


왜 HTTP_X_FORWARDED_FOR에서 마지막 주소를 반환합니까? 클라이언트 주소가 첫 번째 주소가 아닙니까?
Igor Yalovoy

1

내 사이트가 Amazon AWS Elastic Load Balancer (ELB) 뒤에있는 이유 는 무엇입니까?

public class GetPublicIp {

    /// <summary>
    /// account for possbility of ELB sheilding the public IP address
    /// </summary>
    /// <returns></returns>
    public static string Execute() {
        try {
            Console.WriteLine(string.Join("|", new List<object> {
                    HttpContext.Current.Request.UserHostAddress,
                    HttpContext.Current.Request.Headers["X-Forwarded-For"],
                    HttpContext.Current.Request.Headers["REMOTE_ADDR"]
                })
            );

            var ip = HttpContext.Current.Request.UserHostAddress;
            if (HttpContext.Current.Request.Headers["X-Forwarded-For"] != null) {
                ip = HttpContext.Current.Request.Headers["X-Forwarded-For"];
                Console.WriteLine(ip + "|X-Forwarded-For");
            }
            else if (HttpContext.Current.Request.Headers["REMOTE_ADDR"] != null) {
                ip = HttpContext.Current.Request.Headers["REMOTE_ADDR"];
                Console.WriteLine(ip + "|REMOTE_ADDR");
            }
            return ip;
        }
        catch (Exception ex) {
            Console.Error.WriteLine(ex.Message);
        }
        return null;
    }
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.