http_proxy 了解


 

 

漏洞原文在這里, https://httpoxy.org/, 沒看懂的一定都是英語沒過6級的 :)

這里有一個核心的背景是, 長久一來我們習慣了使用一個名為”http_proxy”的環境變量來設置我們的請求代理, 比如在命令行我們經常這么用:

  1. 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

再后來很多的類庫, 各種語言的, 都開始支持這種配置, 有的支持大寫的, 有的支持小寫的, 還有的都支持.

包括我們自己, 也很有可能在日常的工作中寫出如下的代碼(我就曾經在寫爬蟲的時候寫過):

  1. <?php
  2. $http_proxy = getenv("HTTP_PROXY");
  3. if ($http_proxy) {
  4.     $context = array(
  5.         'http' => array(
  6.             'proxy' => $http_proxy,
  7.             'request_fulluri' => true,
  8.         ),
  9.  
  10.     );
  11.     $s_context = stream_context_create($context);
  12. } else {
  13.     $s_context = NULL;
  14. }
  15. $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”)就變成可被控制的了. 那么如果你的所有類似的請求, 都會被代理到攻擊者想要的地址,之后攻擊者就可以偽造,監聽,篡改你的請求了…

比如:

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

所以, 這個漏洞要影響你, 有幾個核心前提是:

  • 你的服務會對外請求資源
  • 你的服務使用了HTTP_PROXY(大寫的)環境變量來代理你的請求(可能是你自己寫,或是使用一些有缺陷的類庫)
  • 你的服務跑在PHP的CGI模式下(cgi, php-fpm)

如果你沒有滿足上面的條件, 那么恭喜你,你不受此次漏洞影響 :) .

后記: 在微博上有同學提醒, 我可能把這個問題的影響潛意識的讓大家覺得危害不大, 但實際上, 延伸一下: 所有HTTP_開頭的環境變量在CGI下都是不可信的, 千萬不要用於敏感操作, 另外一點就是, 我深刻的體會過, 做安全的同學想象力非常豐富, 雖然看似很小的一個點, 但到了安全的同學手里, 配合他們豐富的想象力, 強大的社工能力, 也是能做出巨大攻擊效果的….

那知道了原理修復起來也很簡單了, 以Nginx為例, 在配置中加入:

  1.    fastcgi_param HTTP_PROXY "";

所以建議, 即使你不受此次漏洞影響, 也應該加入這個配置.

而如果你是一個類庫的作者,或者你因為什么原因沒有辦法修改服務配置, 那么你就需要在代碼中加入對sapi的判斷, 除非是cli模式, 否則永遠不要相信http_proxy環境變量,

  1. <?php
  2. if (php_sapi_name() == 'cli' && getenv('HTTP_PROXY')) {
  3.    //只有CLI模式下, HTTP_PROXY環境變量才是可控的
  4. }

就好比Guzzle的這個修復:Addressing HTTP_PROXY security vulnerability

補充: 從PHP5.5.38開始, getenv增加了第二個參數, local_only = false, 如果這個參數為true, 則只會從系統本地的環境變量表中獲取, 從而修復這個問題, 並且默認的PHP將攔截HTTP_PROXY: fix


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM