Press "Enter" to skip to content

HTTPOXY漏洞说明

好久没写文章了, 博客都长草了, 早上起来本来想去上班, 一看这么大雨, 这要上路了不得堵死啊.
再加上有同学对我昨天转发的微博HTTPOXY漏洞表示不理解, 问会不会影响普通应用, 于是就写篇文章介绍下, 等早高峰过了吧;).....
不过要注意的是, 这里我只是介绍PHP这个角度, 关于Go和Python等其他角度的,因为我也不是"很"懂,你们还是看原文吧 🙂

漏洞原文在这里, https://httpoxy.org/, 没看懂的一定都是英语没过6级的 🙂
这里有一个核心的背景是, 长久一来我们习惯了使用一个名为"http_proxy"的环境变量来设置我们的请求代理, 比如在命令行我们经常这么用:

http_proxy=127.0.0.1:9999 wget http://www.laruence.com/

通过设置一个http_proxy的环境变量, 让wget使用代理请求http://www.laruence.com/
有据可考的是, 这样的设定最初来自1994年的CERN libwww 2.15, 我猜测大概是当时很多工具是基于这个类库做的, 于是就慢慢成了一个既定标准吧. 只不过这些应用都要求http_proxy是全部小写的, 还不足以造成今天这个漏洞.
但估计是因为环境变量习惯都是大写的原因吧, 后来有的类库开始支持大写的HTTP_PROXY, 比如yum: https://www.centos.org/docs/5/html/yum/sn-yum-proxy-server.html
再后来很多的类库, 各种语言的, 都开始支持这种配置, 有的支持大写的, 有的支持小写的, 还有的都支持.

包括我们自己, 也很有可能在日常的工作中写出如下的代码(我就曾经在写爬虫的时候写过):

<?php
$http_proxy = getenv("HTTP_PROXY");
if ($http_proxy) {
    $context = array(
        'http' => array(
            'proxy' => $http_proxy,
            'request_fulluri' => true,
        ),
    );
    $s_context = stream_context_create($context);
} else {
    $s_context = NULL;
}
$ret = file_get_contents("http://www.laruence.com/", false, $s_context);

那么问题来了, 在CGI(RFC 3875)的模式的时候, 会把请求中的Header, 加上HTTP_ 前缀, 注册为环境变量, 所以如果你在Header中发送一个Proxy:xxxxxx, 那么PHP就会把他注册为HTTP_PROXY环境变量, 于是getenv("HTTP_PROXY")就变成可被控制的了. 那么如果你的所有类似的请求, 都会被代理到攻击者想要的地址,之后攻击者就可以伪造,监听,篡改你的请求了...
比如:

 curl -H "Proxy:127.0.0.1:8000" http://host.com/httpoxy.php

所以, 这个漏洞要影响你, 有几个核心前提是:

  • 你的服务会对外请求资源
  • 你的服务使用了HTTP_PROXY(大写的)环境变量来代理你的请求(可能是你自己写,或是使用一些有缺陷的类库)
  • 你的服务跑在PHP的CGI模式下(cgi, php-fpm)

如果你没有满足上面的条件, 那么恭喜你,你不受此次漏洞影响 :).

后记: 在微博上有同学提醒, 我可能把这个问题的影响潜意识的让大家觉得危害不大, 但实际上, 延伸一下: 所有HTTP_开头的环境变量在CGI下都是不可信的, 千万不要用于敏感操作, 另外一点就是, 我深刻的体会过, 做安全的同学想象力非常丰富, 虽然看似很小的一个点, 但到了安全的同学手里, 配合他们丰富的想象力, 强大的社工能力, 也是能做出巨大攻击效果的....

那知道了原理修复起来也很简单了, 以Nginx为例, 在配置中加入:

   fastcgi_param HTTP_PROXY "";

所以建议, 即使你不受此次漏洞影响, 也应该加入这个配置.
而如果你是一个类库的作者,或者你因为什么原因没有办法修改服务配置, 那么你就需要在代码中加入对sapi的判断, 除非是cli模式, 否则永远不要相信http_proxy环境变量,

<?php
if (php_sapi_name() == 'cli' && getenv('HTTP_PROXY')) {
   //只有CLI模式下, HTTP_PROXY环境变量才是可控的
}

就好比Guzzle的这个修复:Addressing HTTP_PROXY security vulnerability
补充: 从PHP5.5.38开始, getenv增加了第二个参数, local_only = false, 如果这个参数为true, 则只会从系统本地的环境变量表中获取, 从而修复这个问题, 并且默认的PHP将拦截HTTP_PROXY: fix
thanks

65 Comments

  1. danielbro
    danielbro March 8, 2023

    Thank you for your helpful post, There is no need to go to the future, the future is coming to with you friv 1001

  2. ClydeTheApplianceGuy
    ClydeTheApplianceGuy November 11, 2020

    Thanks for sharing this informative info! Our team value the importance of being active and physically healthy! http://www.clydetheapplianceguy.com

  3. Spotlessly Clean
    Spotlessly Clean December 31, 2019

    If i didn’t visit this site then i must be missed this.

  4. boxnovel
    boxnovel November 30, 2019

    I have read and read a lot of your posts, great, your article has a good and very useful content, thank you for sharing.

  5. Kavin
    Kavin August 15, 2019

    nice Post…..I like it

  6. Heropoo
    Heropoo June 17, 2019

    虽然没用到代理,但以后用的时候可以注意了

  7. run 4 game
    run 4 game February 22, 2019

    就是当成伟大的程序员,到大了之后才知道真个是完全不可能实现的,http://www.zwdeng.cn/news.html所以每次见程序员大哥都会有膜拜的眼神

  8. 西顿
    西顿 April 3, 2018

    从小我就有个梦想,就是当成伟大的程序员,到大了之后才知道真个是完全不可能实现的,http://www.zwdeng.cn/news.html所以每次见程序员大哥都会有膜拜的眼神

  9. heropoo
    heropoo January 25, 2018

    鸟哥,学习了

  10. dsadsa
    dsadsa December 21, 2017

    关注了关注了关注了关注了关注了

  11. Crossworld
    Crossworld November 25, 2017

    受教了,感谢鸟哥!

  12. 111
    111 November 1, 2017

    444

  13. spanish to english
    spanish to english June 2, 2017

    那知道了原理修复起来也很简单了, 以Nginx为例

  14. PHP问答
    PHP问答 December 17, 2016

    php扩展迁到php7有啥需要注意的呢?

  15. SH
    SH December 17, 2016

    学习了,谢谢~

  16. hongbo819
    hongbo819 November 30, 2016

    刚看到。。。那些牛逼的站点们还是要做下优化的。。。

  17. zzm
    zzm November 14, 2016

    已更新就是猛料啊 鸟哥

  18. bjmayor
    bjmayor November 10, 2016

    鸟哥最近在忙啥,博客好久没更新了。

  19. Anonymous
    Anonymous October 31, 2016

    英语没过2级的路过

  20. pz
    pz October 28, 2016

    这下就看懂了,之前几篇文字我都没看明白

  21. taylor
    taylor October 26, 2016

    这个漏洞触发比较特殊

  22. fanfan
    fanfan October 20, 2016

    学习了,鸟哥威武!

  23. GenialX
    GenialX October 5, 2016

    学习了,谢过。那么在PHP中,用小写形式来获取http_proxy是不是就可信了?

  24. pulsa online
    pulsa online October 4, 2016

    感谢鸟哥!我们各种接口调用,又是nginx的,可能是高危群体了吧。

  25. Terry
    Terry September 21, 2016

    拜读….

  26. ian
    ian August 27, 2016

    大哥你那yaf框架封装的太好了,我在$app->bootstrap()->run();之前做了$_GET,$_POST,$_REQUEST脏词过滤,最后一点效果没有。感觉一点不人性。

  27. Francis
    Francis August 18, 2016

    给你提个你网站的bug: 在最新版的chrome(52.0.2743.116)下站点久久的打不开, 只能看到空白页在旋转加载, 估计能有好几分钟打不开. 但换做firefox后, 页面能正常显示内容,至少能看到内容.
    观察加载后发现, 可能是由于apis.google.com/js/plusone.js这个js加载不到引起的白屏.
    希望能处理一下.

  28. 志斌
    志斌 August 3, 2016

    在PHP5.4版本下使用opcache的一个问题,pfsockopen打开了一个长连接,当服务器主动断开连接后(第一个请求结束之后),第二次请求使用fgets不能获取服务器的返回
    The first request with strace:
    sendto(11, “POST /users/api.php HTTP/1.1\r\nHo”…, 860, MSG_DONTWAIT, NULL, 0) = 860
    poll([{fd=11, events=POLLIN|POLLPRI|POLLERR|POLLHUP}], 1, 0) = 0 (Timeout)
    poll([{fd=11, events=POLLIN|POLLERR|POLLHUP}], 1, 3000) = 1 ([{fd=11, revents=POLLIN}])
    recvfrom(11, “HTTP/1.1 200 OK\r\nServer: openres”…, 8192, MSG_DONTWAIT, NULL, NULL) = 1102
    And after a few mintue anthor request with strace
    sendto(11, “POST /users/api.php HTTP/1.1\r\nHo”…, 860, MSG_DONTWAIT, NULL, 0) = 860
    poll([{fd=11, events=POLLIN|POLLPRI|POLLERR|POLLHUP}], 1, 0) = 1 ([{fd=11, revents=POLLIN}])
    recvfrom(11, “”, 1, MSG_PEEK, NULL, NULL) = 0
    poll([{fd=11, events=POLLIN|POLLERR|POLLHUP}], 1, 3000) = 1 ([{fd=11, revents=POLLIN}])
    recvfrom(11, “”, 8192, MSG_DONTWAIT, NULL, NULL) = 0
    However when i use fsockopen(or whitout opcache), it won’t occur this problem
    my php version is 5.4.41

  29. yangakw
    yangakw August 3, 2016

    做安全的想象力真的佩服

  30. 木木老蔫
    木木老蔫 July 28, 2016

    啊,鸟哥已经8.6万微博粉丝了啊

  31. fy
    fy July 23, 2016

    php扩展迁到php7要注意什么呢,哪里能看到所有的改动呢

  32. Anonymous
    Anonymous July 19, 2016

    很多框架信任http_x_forwaded_for作为ip地址,危害更大

  33. 石樱灯笼
    石樱灯笼 July 19, 2016

    昨天就把VPS的Apache加了
    “`
    LoadModule headers_module /usr/lib/apache2/modules/mod_headers.so
    RequestHeader unset Proxy early
    “`
    然而并不知道能不能生效……

  34. kisto
    kisto July 19, 2016

    受益匪浅

  35. pz
    pz July 19, 2016

    能说没看懂吗?脚本里的代理为什么会去用 用户设置的代理?

  36. Cheng
    Cheng July 19, 2016

    鸟哥威武

  37. JV
    JV July 19, 2016

    鸟哥终于更新了

  38. windsor
    windsor July 19, 2016

  39. Bun
    Bun July 19, 2016

    终于更新blog了,支持鸟哥,感谢鸟哥

  40. guest
    guest July 19, 2016

    各位Apache下php_mod不会收到影响吗?

  41. Axios
    Axios July 19, 2016

    还是鸟哥的博客看着舒服,比英文的好多啦~

  42. rambone
    rambone July 19, 2016

    这就是咱们鸟哥 第一时间 从前方发回报道

  43. Ethan
    Ethan July 19, 2016

    感谢鸟哥!我们各种接口调用,又是nginx的,可能是高危群体了吧。

Comments are closed.