一个比欺骗表单更高级和复杂的攻击方式是HTTP请求欺骗。这给了攻击者完全的控制权与灵活性,它进一步证明了不能盲目信任用户提交的任何数据。
为了演示这是如何进行的,请看下面位于http://example.org/form.php的表单:
1 | <form action= "process.php" method= "POST" > |
2 | <p>Please select a color: |
3 | <select name= "color" > |
4 | <option value= "red" >Red</option> |
5 | <option value= "green" >Green</option> |
6 | <option value= "blue" >Blue</option> |
7 | </select><br /> |
8 | <input type= "submit" value= "Select" /></p> |
9 | </form> |
如果用户选择了Red并点击了Select按钮后,浏览器会发出下面的HTTP请求:
1 | POST /process.php HTTP/1.1 |
2 | Host: example.org |
3 | User-Agent: Mozilla/5.0 (X11; U; Linux i686) |
4 | Referer: http: //example.org/form.php |
5 | Content-Type: application/x-www-form-urlencoded |
6 | Content-Length: 9 |
7 |
8 | color=red |
看到大多数浏览器会包含一个来源的URL值,你可能会试图使用$_SERVER['HTTP_REFERER']变量去防止欺骗。确实,这可以用于对付利用标准浏览器发起的攻击,但攻击者是不会被这个小麻烦给挡住的。通过编辑HTTP请求的原始信息,攻击者可以完全控制HTTP头部的值,GET和POST的数据,以及所有在HTTP请求的内容。
攻击者如何更改原始的?过程非常简单。通过在大多数系统平台上都提供的Telnet实用程序,你就可以通过连接网站服务器的侦听端口(典型的端口为80)来与Web服务器直接通信。下面就是使用这个技巧请求http://example.org/页面的例子:
01 | $ telnet example.org 80 |
02 | Trying 192.0.34.166... |
03 | Connected to example.org (192.0.34.166). |
04 | Escape character is '^]' . |
05 | GET / HTTP/1.1 |
06 | Host: example.org |
07 |
08 | HTTP/1.1 200 OK |
09 | Date : Sat, 21 May 2005 12:34:56 GMT |
10 | Server: Apache/1.3.31 (Unix) |
11 | Accept-Ranges: bytes |
12 | Content-Length: 410 |
13 | Connection: close |
14 | Content-Type: text/html |
15 |
16 | <html> |
17 | <head> |
18 | <title>Example Web Page</title> |
19 | </head> |
20 | <body> |
21 | <p>You have reached this web page by typing "example.com" , |
22 | "example.net" , or "example.org" into your web browser.</p> |
23 | <p>These domain names are reserved for use in documentation and are not |
24 | available for registration. See |
25 | <a href= "" >RFC 2606</a>, Section |
26 | 3.</p> |
27 | </body> |
28 | </html> |
29 |
30 | Connection closed by foreign host. |
31 | $ |
上例中所显示的请求是符合HTTP/1.1规范的最简单的请求,这是因为Host信息是头部信息中所必须有的。一旦你输入了表示请求结束的连续两个换行符,整个HTML的回应即显示在屏幕上。
Telnet实用程序不是与Web服务器直接通信的唯一方法,但它常常是最方便的。可是如果你用PHP编码同样的请求,你可以就可以实现自动操作了。前面的请求可以用下面的PHP代码实现:
01 | <?php |
02 | |
03 | $http_response = '' ; |
04 | |
05 | $fp = fsockopen ( 'example.org' , 80); |
06 | fputs ( $fp , "GET / HTTP/1.1\r\n" ); |
07 | fputs ( $fp , "Host: example.org\r\n\r\n" ); |
08 | |
09 | while (! feof ( $fp )) |
10 | { |
11 | $http_response .= fgets ( $fp , 128); |
12 | } |
13 | |
14 | fclose( $fp ); |
15 | |
16 | echo nl2br (htmlentities( $http_response , ENT_QUOTES, 'UTF-8' )); |
17 | |
18 | ?> |
当然,还有很多方法去达到上面的目的,但其要点是HTTP是一个广为人知的标准协议,稍有经验的攻击者都会对它非常熟悉,并且对常见的安全漏洞的攻击方法也很熟悉。
相对于表单,欺骗HTTP请求的做法并不多,对它不应该过多关注。我讲述这些技巧的原因是为了更好的演示一个攻击者在向你的应用输入恶意信息时是如何地方便。这再次强调了过滤输入的重要性和HTTP请求提供的任何信息都是不可信的这个事实。