标题:代理穿透技术
内容:以下内容是根据我在写远程控制工具时的工作日记整理而成的,一些方法思路是借鉴了前辈的,在此感谢,同时有一点心得,拿出来与大家分享,希望对大家有用。
正文:
1、现状简介
当今大型机构、企业为了保障网络安全、实现统一的安全管理,多采用域控、代理、网关等相关的手段,因此对于这些环境下的网络通信必然会面临代理穿透的问题。代理软件主要用于网页浏览、下载文件、邮件收发等多种用途。
常见的代理类型有:
FTP
HTTP
HTTPS
SOCKS
Gropher
其中最常用的代理主要有Http、Https和Socks,以下将以http为例说明代理穿透技术。
2、HTTP代理穿透
2.1 HTTP CONNECT
HTTP代理服务器中能够提供一种HTTP CONNECT代理服务,能够允许用户建立TCP连接到任何端口。进一步讲,这种代理不仅可用于HTTP,还包括FTP、IRC、RM流服务等,甚至扫描、攻击。
通过CONNECT方法穿透代理的实现步骤为:
connect代理服务器的代理端口(如:8080);
如果成功返回就可以按照正常的Socket进行通讯。
注:ISA防火墙会默认封阻SSL端口以外的其它connect端口,以防被人滥用作扫描,攻击或发送垃圾邮件。因此穿透ISA,我们可以connect 443端口,然后把443映射为我们需要连接的真正端口。
2.2 HTTP GET/POST
Http GET/POST代理穿透的原理都是通过发送HTTP协议的数据报文来实现,所要传输的数据隐含在HTTP的请求/应答报文中,即网络数据的通信被HTTP协议封装,并且传输的过程遵循HTTP协议本身。
2.2.1HTTP报文格式
(1)请求报文
HTTP请求报文格式为:
请求消息 = 请求行(实体头信息)CRLF[实体内容]
请求行 = 方法 URL HTTP版本号 CRLF
方法 = GET|HEAD|POST|扩展方法
URL = 协议名称 + 宿主名 + 目录与文件名
其中"CRLF"表示回车换行。
"请求行"中的"方法"描述了对指定资源执行的动作,常用的方法"GET"、"HEAD"和"POST"等3种,它们的含义如表
表 1 HTTP请求方法
取值 描述
GET 从WEB服务器中获取对象,不同类型的对象将获取不同的信息,比如:
· 文件类型对象,获取该文件的内容。
· 程序类型对象,获取该程序执行的结果。
· 数据库查询类型对象,获取该查询的结果。
POST 从客户端向WEB服务器发送数据。
HEAD 要求服务器查找对象的元信息。
"实体头信息"中记载了报文的属性,利用这些信息可以实现客户端与WEB服务器之间的请求或应答,它包括报文的数据类型、压缩方法、语言、长度、压缩方法、最后一次修改时间、数据有效期等信息。实体内容是报文传送的附加信息,一般供POST请求填写。
以下是GET请求报文的例子:
GET http://192.168.0.1/test.asp?value=testinfo HTTP/1.1
Accept: */*
Accept-Language: zh-cn
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)
Host: http://192.168.0.1/
Connection: Keep-Alive
其中"/test.php?value=testinfo"是URL信息,语句"ACCEPT:*/*"及其后的语句是"实体头信息"。
注意:在语句"Connection:Keep-Alive"下的空行是必须的。
以下是POST请求报文的例子:
POST /test.cgi HTTP/1.0 /* 请求行,服务程序为test.cgi */
/* 以下为实体头信息 */
Host: 192.168.0.1
Authorization: Basic <Base64 串>
Content-Length: <Content-Length>
/* 以下为POST请求的实体信息 */
<CommandId>=<4>
<CommandValue>=<44>
一般情况下,采用POST报文传送信息的数据存储在"实体"部分中。
(2)应答报文
HTTP协议的应答报文格式为:
应答报文 = 状态行(实体头信息)CRLF [实体内容]
状态行 = HTTP版本号 状态码 原因叙述
状态码描述了WEB服务器执行客户机请求的状态信息,其取值含义如表
表 2 HTTP响应应答码含义
取值 描述
1xx 保留
2xx 成功接收
3xx 客户需进一步细化请求
4xx 客户错误
5xx 服务错误
GET应答报文例子
HTTP/1.1 200 OK
Connection: keep-alive
Date: Thu, 26 Jul 2007 14:00:02 GMT
Server: Microsoft-IIS/6.0
X-Powered-By: ASP.NET
Content-Length: 190
Content-Type: text/html
Set-Cookie: ASPSESSIONIDSAATTCSQ=JOPPKDCAMHHBEOICJPGPBJOB; path=/
Cache-control: private
<html>
<head>
<title>TestPage</title>
</head>
<body>
<font size=4>HelleWorld!</font>
</body>
</html>
语句"HTTP/1.1 200 OK"中,"200"是响应码,"OK"是原因描述。
POST应答报文例子
HTTP/1.0 200 OK /* 状态行,应答成功 */
/* 以下为实体头信息 */
Date: Tue, 13 Mar 2001 02:45:12 GMT
Server: Apache/1.3.12 (Unix)
Content-Type: text/html
Connection: close
/* 以下为POST应答的实体信息 */
<CommandId>=<94>
<CommandValue>=<9494>
<Result>=<0>
一般情况下,POST应答报文的"实体"部分存储实际传输的信息。
(3)GET和POST数据报文的区别:
GET和POST若用作数据传输时,响应报文的数据存放区别不大,重点在于请求报文中数据的存放。
首先GET方式提交的数据存放在URL中,根据HTTP协议规范,并没有对URL的长度进行限制,但是特定的浏览器和服务器对它有限制,如IE对URL的限制长度为2083字节(2K+35),而其它浏览器(如:Netscape、FireFox等)理论上没有长度限制,但限制取决于操作系统的支持。
注:上述的限制是整个URL长度,而不仅仅是你的参数值数据长度。
再者理论上讲POST是没有大小限制的,HTTP协议规范也没有大小限制,但服务器的处理程序的处理能力限制了其大小。如:对于ASP程序,Request对象处理每个表单域时存在100K的数据长度限制,但如果使用Request.BinaryRead则没有这个限制。
对于IIS6.0,MS出于安全考虑,加大了限制:
IIS6.0默认ASP POST数据量最大为200KB,每个表单域限制是100KB;
IIS6.0默认上传文件大小是4MB;
IIS6.0默认最大请求头是16KB;
注:IIS6.0之前没有这些限制,并且这些参数可以自己设置,具体参见IIS配置文档。
2.2.2 GET和POST数据包的构造
(1)伪装GET请求数据包
由于GET请求的数据会附在URL之后(HTTP协议头中),以"?"分割URL和传输数据,参数之间以"&"连接。如果数据是英文字母/数字,则直接发送,如果是空格,转化为"+",如果是中文/其它字符串,则用BASE64加密。以下是用GET进行数据传输的举例说明:
GET http://192.168.0.1/test.asp?value=Test Request HTTP/1.1
Accept: */*
Accept-Language: zh-cn
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)
Host: http://192.168.0.1/
Connection: Keep-Alive
其中"Test Request"就是我们要传输的数据
(2)伪装GET响应数据包
伪转GET响应包比较简单,直接将数据写入HTTP包的实体中,举例如下:
HTTP/1.1 200 OK
Connection: keep-alive
Date: Thu, 26 Jul 2007 14:00:02 GMT
Server: Microsoft-IIS/6.0
X-Powered-By: ASP.NET
Content-Length: 190
Content-Type: text/html
Cache-control: private
TestResponseInfo
其中"TestResponseInfo"为响应的数据,当然为了保证较好的安全性可以将真正的数据放入特定的网页标记中如下:
<html>
<head>
<title>TestPage</title>
</head>
<body>
<font size=4>TestResponseInfo!</font>
</body>
</html>
(3)伪装POST请求数据包
POST把需要传输的数据直接放在HTTP包的实体中,如下:
POST /test.php HTTP/1.0
Host: 192.168.0.1
Authorization: Basic <Base64 串>
Content-Length: <Content-Length>
<RequestCommand>=<TestRequest>
<RequestCommandValue>=<44>
其中"TestRequest"和"44"就是两个请求的数据
(4)伪装POST响应数据包
POST的响应数据与请求数据的存放相似,如下:
HTTP/1.0 200 OK
Date: Tue, 13 Mar 2001 02:45:12 GMT
Server: Apache/1.3.12 (Unix)
Content-Type: text/html
Connection: close
<ResponseCommand>=<TestResponse>
<ResponseValue>=<9494>
<Result>=<0>
其中其中"TestResponse"和"9494"就是两个响应的数据,而"<Result>=<0>"此处用作传输结束标志,主要用于大量数据传输时,判断数据包是否是最后一个报文。
2.2.3 HTTP GET/POST代理穿透的实现
(1)Sockers实现
Socket实现的Http代理穿透的流程使用关键字"GET"和"POST"的过程一样,只是提取数据的时候,需要解析HTTP头部、对应的定制标志或字符,而整个发送过程与普通的Socket网络通讯一样,首先创建socket套接字,然后connect代理服务器和端口,接着send构造的特殊请求数据包,之后就等待接受数据包。此时还需要做的就是伪造相应的HTTP服务端。在接受特定的HTTP相应后,解析请求,然后将响应的HTTP头加上特定的响应数据发送回请求端。
(2)WinInet实现
WinInet允许应用程序向Internet服务器增加连接,而不用考虑基本的通信协议,它是程序员可以在较高的层次上建立Internet客户应用程序,提供专业性客户端程序支持,较Winsock有许多的优点。而此处说的WinInet包括WinInet类、WinInet API和MFC WinInet类,其中WinInet类封装了WinInet API但不全面,WinInet API提供了全部的接口操作,而MFC WinInet类也是封装WinInet API,但其为用户提供了更加方便的编程接口。
而WinInet编程从数据包收发的角度上说是和Winsock的实现是等价的,以下以WinInet API为例说明请求数据包的发送和接收过程:
// 1、建立与服务端的连接,并测试
InternetOpen()
InternetConnect()
InternetAttemptConnect()
// 2、添加HTTP请求头和URI
HttpOpenRequest()
HttpAddRequestHeaders()
// 3、接受数据
InternetReadFile()
当然使用哪种构造的WinInet可由具体的需求灵活决定。
WinInet只能用户编写Internet的客户端程序,不能用于服务端的编写,因此伪装的服务端还是由Winsock来完成。
2.3 总结
本文总结出的HTTP代理的穿透方法主要分为两种方法来实现,即"CONNECT"和"GET/POST",前者主要利用代理服务可以建立到指定端口的连接来实现,后者主要的思想就是如何伪装成正常的HTTP程序和服务,并进行网络数据的通信。另外,HTTP GET/POST代理穿透的实现的前提条件是开启了Http代理服务,再者有时可能还要看具体代理设置的情况,如有的代理服务不允许"POST"请求。