现在的位置: 首页 > 综合 > 正文

获取ip

2013年12月06日 ⁄ 综合 ⁄ 共 13665字 ⁄ 字号 评论关闭

    private string GetClientIP()
    {
        if (!string.IsNullOrEmpty(HttpContext.Current.Request.ServerVariables["HTTP_VIA"]))
        {
            if (!string.IsNullOrEmpty(HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"]))
            {
                return HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"];
            }
        }
        return HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"];
    }

 

以上是我获取的方法

ip(ipHead+ipData(tcpHead+tcpData(httpHead+httpData)))

 

 REMOTE_ADDR获取是ipHead中的数据,最后一个路由的ip

HTTP_VIA,HTTP_X_FORWARDED_FOR获取的是httpHead中的数据,因为ip由物理网络自动生成,所以比较安全,

而http是应用层的东东,可修改性比较强。

 

=============================

以下转帖
 

 

 

前面我写的“ASP.net 获得客户端的IP相关知识”博客中,有一个简单的例子,演示了如何客户端编码,修改 HTTP_VIA 和HTTP_X_FORWARDED_FOR ,进而让服务器无法了解你到底是否启用的代理服务器,以及启用的是代理服务器之后的你的真实IP地址。 结合上面的技术,编码使用代理服务器,其实是非常简单的。下面就是客户段的演示代码。比起上篇博客,只修改了几行。

       下面演示代码中的代理服务器地址,可能在你试验的时候,已经不通了,请更换新的代理服务器地址。

    class Program
{
static void Main(string[] args)
{
// 最新代理服务器的地址,可以参看下面的列表
// http://www.proxycn.com/html_proxy/http-1.html

proxyTest("http://81.181.45.25:3128");
proxyTest("http://202.105.182.13:80");
Console.ReadLine();
}

public static void proxyTest(string proxyInfo)
{
WebProxy proxy = new WebProxy();
proxy.Address = new Uri(proxyInfo);

HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(http://******/userip.aspx);
request.Headers.Add("VIA", "");
request.Headers.Add("X_FORWARDED_FOR", "");

request.Proxy = proxy;
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
StreamReader stream = new StreamReader(response.GetResponseStream());
string info = stream.ReadToEnd();
stream.Close();
response.Close();
request = null;

Console.Write(info);
Console.WriteLine("***************************************************");
}
}

.net 中的 WebProxy   类,替我们封装了代理的处理逻辑。

小结:

       通过这两篇博客:ASP.net 获得客户端的IP相关知识那些HTTP头会被增加HTTP_前缀,以及本文,我们会看到,服务器段获得IP地址,是非常脆弱的。通过编码绕过IP限制的门槛是越来越底了。通过IP做一些限制时,很多时候是非常脆弱的。当你使用IP限制策略的时候。要意识到这并不是一个强壮的限制策略。

posted on 2008-02-21 14:53:00 by ghj1976  评论(4) 阅读(5012)

那些HTTP头会被增加HTTP_前缀

       上一篇博客:ASP.net 获得客户端的IP相关知识 中我提到了,如果你想编码更改 HTTP_VIA、HTTP_X_FORWARDED_FOR 的值,你需要客户端增加的HTTP Head为:VIA、X_FORWARDED_FOR。即,少个 "HTTP_" 前缀。那么,到底读取这些值时,那些HTTP头增加时候需要增加HTTP_前缀,那些又不需要呢?

        简单来说,出了一些系统预先定义的,有特殊意义的HTTP头外,其他都需要增加 "HTTP_" 前缀。这是W3C 的 The Common Gateway Interface (CGI) 规范的定义。这些预定义的变量如下:

变量 说明
APPL_MD_PATH 检索 ISAPI DLL 的 (WAM) Application 的元数据库路径。
APPL_PHYSICAL_PATH 检索与元数据库路径相应的物理路径。IIS 通过将 APPL_MD_PATH 转换为物理(目录)路径以返回值。
AUTH_PASSWORD 该值输入到客户端的鉴定对话中。只有使用基本鉴定时,该变量才可用。
AUTH_TYPE 这是用户访问受保护的脚本时,服务器用于检验用户的验证方法。
AUTH_USER 未被鉴定的用户名。
CERT_COOKIE 客户端验证的唯一 ID,以字符串方式返回。可作为整个客户端验证的签字。
CERT_FLAGS

如有客户端验证,则 bit0 为 1。
如果客户端验证的验证人无效(不在服务器承认的 CA 列表中),bit1 被设置为 1。

CERT_ISSUER

用户验证中的颁布者字段(O=MS,OU=IAS,CN=user name,C=USA)。

CERT_KEYSIZE

安全套接字层连接关键字的位数,如 128。

CERT_SECRETKEYSIZE

服务器验证私人关键字的位数。如 1024。

CERT_SERIALNUMBER

用户验证的序列号字段。

CERT_SERVER_ISSUER 服务器验证的颁发者字段。
CERT_SERVER_SUBJECT 服务器验证的主字段。
CERT_SUBJECT 客户端验证的主字段。
CONTENT_LENGTH 客户端发出内容的长度。
CONTENT_TYPE 内容的数据类型。同附加信息的查询一起使用,如 HTTP 查询 GET、 POST 和 PUT。
GATEWAY_INTERFACE 服务器使用的 CGI 规格的修订。格式为 CGI/revision。
HTTPS 如果请求穿过安全通道(SSL),则返回 ON。如果请求来自非安全通道,则返回 OFF。
HTTPS_KEYSIZE 安全套接字层连接关键字的位数,如 128。
HTTPS_SECRETKEYSIZE 服务器验证私人关键字的位数。如 1024。
HTTPS_SERVER_ISSUER 服务器验证的颁发者字段。
HTTPS_SERVER_SUBJECT 服务器验证的主字段。
INSTANCE_ID 文本格式 IIS 实例的 ID。如果实例 ID 为 1,则以字符形式出现。使用该变量可以检索请求所属的(元数据库中)Web 服务器实例的 ID。
INSTANCE_META_PATH 响应请求的 IIS 实例的元数据库路径。
LOCAL_ADDR 返回接受请求的服务器地址。如果在绑定多个 IP 地址的多宿主机器上查找请求所使用的地址时,这条变量非常重要。
LOGON_USER

用户登录 Windows NT? 的帐号。

PATH_INFO 客户端提供的额外路径信息。可以使用这些虚拟路径和 PATH_INFO 服务器变量访问脚本。如果该信息来自 URL,在到达 CGI 脚本前就已经由服务器解码了。
PATH_TRANSLATED PATH_INFO 转换后的版本,该变量获取路径并进行必要的由虚拟至物理的映射。
QUERY_STRING 查询 HTTP 请求中问号(?)后的信息。 
REMOTE_ADDR 发出请求的远程主机的 IP 地址。 
REMOTE_HOST 发出请求的主机名称。如果服务器无此信息,它将设置为空的 MOTE_ADDR 变量。
REMOTE_USER 用户发送的未映射的用户名字符串。该名称是用户实际发送的名称,与服务器上验证过滤器修改过后的名称相对。
REQUEST_METHOD 该方法用于提出请求。相当于用于 HTTP 的 GET、HEAD、POST 等等。
SCRIPT_NAME 执行脚本的虚拟路径。用于自引用的 URL。
SERVER_NAME 出现在自引用 UAL 中的服务器主机名、DNS 化名或 IP 地址。
SERVER_PORT 发送请求的端口号。
SERVER_PORT_SECURE 包含 0 或 1 的字符串。如果安全端口处理了请求,则为 1,否则为 0。
SERVER_PROTOCOL 请求信息协议的名称和修订。格式为 protocol/revision 。
SERVER_SOFTWARE 应答请求并运行网关的服务器软件的名称和版本。格式为 name/version 。
URL

提供 URL 的基本部分。

其他几个跟HTTP_前缀有关的变量
ALL_HTTP 客户端发送的所有带 HTTP_ 前缀的变量。
ALL_RAW 客户端发送的所有HTTP标头,其结果和客户端发送时一样,没有前缀HTTP_ 。
HTTP_<HeaderName>

HeaderName 存储在标题文件中的值。未列入该表的标题文件必须以 HTTP_ 作为前缀,以使 ServerVariables 集合检索其值。
注意 服务器将 HeaderName 中的下划线(_)解释为实际标题中的破折号。例如,如果您指定 HTTP_MY_HEADER,服务器将搜索以 MY-HEADER 为名发送的标题文件。

我们通过.net 的开源代码也可以看到上面的逻辑,这部分的核心代码在 System.Web.HttpRequest 类的 FillInServerVariablesCollection 方法

        internal void FillInServerVariablesCollection() {
            if (_wr == null)
                return;

            //  Add from hardcoded list

            AddServerVariableToCollection("ALL_HTTP",           CombineAllHeaders(false));
            AddServerVariableToCollection("ALL_RAW",            CombineAllHeaders(true));

            AddServerVariableToCollection("APPL_MD_PATH");

            AddServerVariableToCollection("APPL_PHYSICAL_PATH", _wr.GetAppPathTranslated());

            AddServerVariableToCollection("AUTH_TYPE",          DynamicServerVariable.AUTH_TYPE);
            AddServerVariableToCollection("AUTH_USER",          DynamicServerVariable.AUTH_USER);

            AddServerVariableToCollection("AUTH_PASSWORD");

            AddServerVariableToCollection("LOGON_USER");
            AddServerVariableToCollection("REMOTE_USER",        DynamicServerVariable.AUTH_USER);

            AddServerVariableToCollection("CERT_COOKIE");
            AddServerVariableToCollection("CERT_FLAGS");
            AddServerVariableToCollection("CERT_ISSUER");
            AddServerVariableToCollection("CERT_KEYSIZE");
            AddServerVariableToCollection("CERT_SECRETKEYSIZE");
            AddServerVariableToCollection("CERT_SERIALNUMBER");
            AddServerVariableToCollection("CERT_SERVER_ISSUER");
            AddServerVariableToCollection("CERT_SERVER_SUBJECT");
            AddServerVariableToCollection("CERT_SUBJECT");

            String clString = _wr.GetKnownRequestHeader(HttpWorkerRequest.HeaderContentLength);
            AddServerVariableToCollection("CONTENT_LENGTH",     (clString != null) ? clString : "0");

            AddServerVariableToCollection("CONTENT_TYPE",       this.ContentType);

            AddServerVariableToCollection("GATEWAY_INTERFACE");

            AddServerVariableToCollection("HTTPS");
            AddServerVariableToCollection("HTTPS_KEYSIZE");
            AddServerVariableToCollection("HTTPS_SECRETKEYSIZE");
            AddServerVariableToCollection("HTTPS_SERVER_ISSUER");
            AddServerVariableToCollection("HTTPS_SERVER_SUBJECT");

            AddServerVariableToCollection("INSTANCE_ID");
            AddServerVariableToCollection("INSTANCE_META_PATH");

            AddServerVariableToCollection("LOCAL_ADDR",         _wr.GetLocalAddress());

            AddServerVariableToCollection("PATH_INFO",          DynamicServerVariable.PATH_INFO);
            AddServerVariableToCollection("PATH_TRANSLATED",    DynamicServerVariable.PATH_TRANSLATED);

            AddServerVariableToCollection("QUERY_STRING",       DynamicServerVariable.QUERY_STRING);

            AddServerVariableToCollection("REMOTE_ADDR",        this.UserHostAddress);
            AddServerVariableToCollection("REMOTE_HOST",        this.UserHostName);

            AddServerVariableToCollection("REMOTE_PORT");

            AddServerVariableToCollection("REQUEST_METHOD",     this.HttpMethod);

            AddServerVariableToCollection("SCRIPT_NAME",        DynamicServerVariable.SCRIPT_NAME);

            AddServerVariableToCollection("SERVER_NAME",        _wr.GetServerName());
            AddServerVariableToCollection("SERVER_PORT",        _wr.GetLocalPortAsString());

            AddServerVariableToCollection("SERVER_PORT_SECURE", _wr.IsSecure() ? "1" : "0");

            AddServerVariableToCollection("SERVER_PROTOCOL",    _wr.GetHttpVersion());
            AddServerVariableToCollection("SERVER_SOFTWARE");

            AddServerVariableToCollection("URL",                DynamicServerVariable.SCRIPT_NAME);

            // Add all headers in HTTP_XXX format

            for (int i = 0; i < HttpWorkerRequest.RequestHeaderMaximum; i++) {
                String h = _wr.GetKnownRequestHeader(i);
                if (!String.IsNullOrEmpty(h))
                    AddServerVariableToCollection(HttpWorkerRequest.GetServerVariableNameFromKnownRequestHeaderIndex(i), h);
            }

            String[][] hh = _wr.GetUnknownRequestHeaders();

            if (hh != null) {
                for (int i = 0; i < hh.Length; i++)
                    AddServerVariableToCollection(ServerVariableNameFromHeader(hh[i][0]), hh[i][1]);
            }
        }

小结:

       通过上面的代码和说明可以看到:

       在客户端发送的HTTP Head 信息中, 是原模原样发送的,并没有增加 HTTP_ 前缀。 服务器段接受到时,也是原模原样的。
       按照 W3C 的规范, 除了上述头信息外,其他都需要在服务器端访问时候增加HTTP_ 前缀。 ASP.net 中更极端,除了正常的值获得外。所有值又额外多加了一遍 HTTP_ 前缀。

 

另外,对于客户段来说,并不是所有 HTTP 头都是可以设置的,下面的是受限制的标头。它们或者直接由 API(如 Content-Type)公开,或者受到系统保护,不能被更改:

Accept
Connection
Content-Length
Content-Type
Date
Expect
Host
If-Modified-Since
Range
Referer
Transfer-Encoding
User-Agent
Proxy-Connection

posted on 2008-02-21 14:30:00 by ghj1976  评论(4) 阅读(4627)

ASP.net 获得客户端的IP相关知识

ASP.net 获得客户端的IP,最常见的是使用下述代码:

string user_IP = System.Web.HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"];

对于了解代理服务器情况的人,我们会知道,如果用户使用了代理服务器,上述代码获得的是代理服务器的IP地址;如果用户使用了多个代理服务器,则是到达服务器的最后一个代理服务器的IP地址。

 

REMOTE_ADDR 说明:

访问客户端的 IP 地址。
此项信息用户不可以修改。
如果真的给改了的话,你也和服务器连接不了了,服务器就是按照这个来与客户端建立连接并进行通讯的。实际我测试修改这个 ServerVariables , 一点效果都没有。仍然获得是实际的值。
另: Request.UserHostAddress 和 Request.ServerVariables["REMOTE_ADDR"] 实际是同一个值。

 

如何绕过代理服务器获得用户真实的IP地址呢? 这时候我们一般是类似如下的代码(这里我简单起见,没有作一些边界判断)

private static string getIp()
{
if (System.Web.HttpContext.Current.Request.ServerVariables["HTTP_VIA"] != null)
return System.Web.HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"].Split(new char[]{','})[0];
else
return System.Web.HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"];
}

这样就足够了么? 这样是有问题的,HTTP_X_FORWARDED_FORHTTP_VIA 是可以被冒名的。如果正好这里有SQL注入问题的话,那可非常严重了。

 

下面我们就来具体看HTTP_VIAHTTP_X_FORWARDED_FOR 这两个 ServerVariables。

HTTP_VIA 

如果有该条信息, 就证明您使用了代理服务器,代理服务器的地址就是后面的数值。

HTTP_X_FORWARDED_FOR 

如果有该条信息, 也证明了您使用了代理服务器代理服务器的地址就是后面的数值。

需要注意的,HTTP_X_FORWARDED_FOR  的值,并不一定是只有一个IP地址,下面的信息也是可能的,每行一条记录。下面数据取材于CSDN 实际的数据。
10.194.73.11
unknown, unknown, 211.100.22.30
203.98.182.163, 203.98.182.163, 203.129.72.215
172.16.20.110, 202.116.64.196, 203.81.21.61
10.194.75.83, 10.194.73.11, 10.194.73.11, unknown
192.168.120.57, unknown, unknown, 211.10.10.195
10.2.4.211, 219.141.250.3
3.242.165.168, 218.108.22.164
unknown, 211.100.22.30
192.168.83.56, 210.21.224.233
218.94.136.176, 203.81.21.61
unknown, 210.75.1.181
10.161.196.218, 202.104.134.23
222.216.6.148, 222.216.6.146
155.161.59.47, unknown

需要注意的是这两个值都是可以被改掉的。

 

对于这三个值:REMOTE_ADDRHTTP_VIAHTTP_X_FORWARDED_FOR  来说,可以分以下五种情况:

一、没有使用代理服务器的情况:

      REMOTE_ADDR = 您的 IP
      HTTP_VIA = 没数值或不显示
      HTTP_X_FORWARDED_FOR = 没数值或不显示

二、使用透明代理服务器的情况:Transparent Proxies

      REMOTE_ADDR = 最后一个代理服务器 IP
      HTTP_VIA = 代理服务器 IP
      HTTP_X_FORWARDED_FOR = 您的真实 IP ,经过多个代理服务器时,这个值类似如下:203.98.182.163, 203.98.182.163, 203.129.72.215。

   这类代理服务器还是将您的信息转发给您的访问对象,无法达到隐藏真实身份的目的。

三、使用普通匿名代理服务器的情况:Anonymous Proxies

      REMOTE_ADDR = 最后一个代理服务器 IP
      HTTP_VIA = 代理服务器 IP
      HTTP_X_FORWARDED_FOR = 代理服务器 IP ,经过多个代理服务器时,这个值类似如下:203.98.182.163, 203.98.182.163, 203.129.72.215。

   隐藏了您的真实IP,但是向访问对象透露了您是使用代理服务器访问他们的。

四、使用欺骗性代理服务器的情况:Distorting Proxies

      REMOTE_ADDR = 代理服务器 IP
      HTTP_VIA = 代理服务器 IP
      HTTP_X_FORWARDED_FOR = 随机的 IP ,经过多个代理服务器时,这个值类似如下:203.98.182.163, 203.98.182.163, 203.129.72.215。

   告诉了访问对象您使用了代理服务器,但编造了一个虚假的随机IP代替您的真实IP欺骗它。

五、使用高匿名代理服务器的情况:High Anonymity Proxies (Elite proxies)

      REMOTE_ADDR = 代理服务器 IP
      HTTP_VIA = 没数值或不显示
      HTTP_X_FORWARDED_FOR = 没数值或不显示 ,经过多个代理服务器时,这个值类似如下:203.98.182.163, 203.98.182.163, 203.129.72.215。

   完全用代理服务器的信息替代了您的所有信息,就象您就是完全使用那台代理服务器直接访问对象。

  

下面是一个简单的代码,来演示冒名上述信息,改造自 http://www.cnblogs.com/kingthy/archive/2007/11/24/970783.html 博客的测试代码。

 

服务器端的 UserIP.ASPX 页面的代码:

protected void Page_Load(object sender, EventArgs e)
{
StringBuilder info = new StringBuilder();

// 我们关注的三个 ServerVariables
info.AppendFormat("HTTP_VIA = {0} <br />/r/n",
Request.ServerVariables["HTTP_VIA"]);
info.AppendFormat("HTTP_X_FORWARDED_FOR = {0} <br />/r/n",
Request.ServerVariables["HTTP_X_FORWARDED_FOR"]);
info.AppendFormat("REMOTE_ADDR = {0} <br />/r/n",
Request.ServerVariables["REMOTE_ADDR"]);
info.AppendLine("*********** /r/n<br />");

// 其他有参考价值的 ServerVariables
foreach (string key in Request.ServerVariables.AllKeys)
{
info.AppendFormat("{0} = {1} <br />/r/n", key, Request.ServerVariables[key]);
}

Response.Clear();
Response.Write(info.ToString());
Response.End();
}
 

客户端发送请求的代码:

static void Main(string[] args)
{
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(
"http://localhost:7867/MyTestWebSite/UserIP.aspx");
request.Headers.Add("REMOTE_ADDR", "192.168.5.88");
request.Headers.Add("VIA", "ghj1976");
request.Headers.Add("X_FORWARDED_FOR", "0.0.0.0");

HttpWebResponse response = (HttpWebResponse)request.GetResponse();
StreamReader stream = new StreamReader(response.GetResponseStream());
string info = stream.ReadToEnd();
stream.Close();
response.Close();
request = null;


Console.Write(info);
Console.ReadLine();
}
测试的结果中的重要信息:

测试的结果数据比较多,我这里只罗列了几个重要的。

HTTP_VIA = ghj1976 <br />
HTTP_X_FORWARDED_FOR = 0.0.0.0 <br />
REMOTE_ADDR = 127.0.0.1 <br />
***********
REMOTE_ADDR = 127.0.0.1 <br />
HTTP_VIA = ghj1976 <br />
HTTP_REMOTE_ADDR = 192.168.5.88 <br />
HTTP_X_FORWARDED_FOR = 0.0.0.0 <br />

上面测试代码需要注意的是:

我们在客户端代码中设置了三个HTTP头信息,分别是: 

REMOTE_ADDRVIAX_FORWARDED_FOR
实际在服务器段,这三个值应该通过下面三个属性来读取

HTTP_REMOTE_ADDRHTTP_VIA HTTP_X_FORWARDED_FOR  注意他们的区别!!

REMOTE_ADDR 属性是无法设置的。或者说,设置的不是我们所希望的。

 

小结:

1、REMOTE_ADDR 不可被修改,但是可能会获得代理服务器的IP,而不是实际客户端的IP。

2、通过 HTTP_VIAHTTP_X_FORWARDED_FOR 我们可以获得代理服务器所代理的信息,但是这依靠代理服务器的支持。另外,这两个值可以被修改。我们通过它获得的信息可能是不真实的。另,HTTP_X_FORWARDED_FOR 的信息可能是一个集合,不含 REMOTE_ADDR 中的代理服务器IP。

没有一个完美的解决获得客户端IP地址的方法,我们只能在上面2个信息中取舍。

 

参考资料:

LEAD提效之socks代理
http://blog.sina.com.cn/s/blog_497f6c5501000c2a.html

获取客户端的真实ip
http://www.cnblogs.com/ovliverlin/archive/2007/06/15/784890.html

真正的取真实IP地址及利弊
http://www.cnblogs.com/chinhr/archive/2008/01/24/1051873.html 

使用HTTP_X_FORWARDED_FOR获取客户端IP的严重后果
http://www.cnblogs.com/kingthy/archive/2007/11/24/970783.html

posted on 2008-02-20 17:28:00 by ghj1976  评论(8) 阅读(7797)

 

==============================

http://blog.joycode.com/ghj/archive/2008/02.aspx

抱歉!评论已关闭.