天天看點

PHP 、Python 等網站應用驚爆遠端代理漏洞:httpoxy

httpoxy 是一系列影響到以 cgi 或類 cgi 方式運作的應用的漏洞名稱。簡單的來說,它就是一個名字空間的沖突問題。

rfc 3875 (cgi)中定義了從 http 請求的 <code>proxy</code> 頭部直接填充到環境變量 <code>http_proxy</code> 的方式

<code>http_proxy</code> 是一個常用于配置外發代理的環境變量

這個缺陷會導緻遠端攻擊。如果你正在運作着 php 或 cgi 程式,你應該馬上封擋 proxy 頭部!馬上! 具體做法參見下面。httpoxy 是一個伺服器端 web 應用漏洞,如果你沒有在伺服器端部署這些代碼,則不用擔心。

<a target="_blank"></a>

當一個利用了此漏洞的 http 用戶端發起請求時,它可以做到:

通過你的 web 應用去代理請求别的 url

直接讓你的伺服器打開指定的遠端位址及端口

浪費伺服器的資源,替攻擊者通路指定的資源

httpoxy 漏洞非常容易利用。希望安全人員盡快掃描該漏洞并快速修複。

以下情況會存在安全漏洞:

代碼運作在 cgi 上下文中,這樣 <code>http_proxy</code> 就會變成一個真實的或模拟的環境變量

一個信任 <code>http_proxy</code>的 http 用戶端,并且支援代理功能

該用戶端會在請求内部發起一個 http(或 https)請求

下列情形是已經發現存在該缺陷的環境:

語言

環境

http 用戶端

php

php-fpm 

mod_php

guzzle 4+ 

artax

python

wsgiref.handlers.cgihandler 

twisted.web.twcgi.cgiscript

requests

go

net/http/cgi

net/http

肯定還有很多我們沒有确定是否存在缺陷的語言和環境。

是否存在缺陷依賴于你的應用代碼和 php 庫,但是影響面看起來似乎非常廣泛

隻要在處理使用者請求的過程中使用了一個帶有該缺陷的庫,就可能被利用

如果你使用了有該缺陷的庫,該缺陷會影響任意 php 版本

甚至會影響到替代的 php 運作環境,比如部署在 fastcgi 模式下的  hhvm

确認影響 guzzle、artax 等庫,可能還有很多很多的庫也受影響

guzzle 4.0.0rc2 及其以後版本受影響,guzzle 3 及更低版本不受影響

其它的例子還有 composer 的 streamcontextbuilder 工具類

舉個例子說,如果你在 drupal 中使用 guzzle 6 子產品發起外發請求(比如請求一個天氣 api),該子產品發起的請求就存在這個 httpoxy 缺陷。

python 代碼隻有部署在 cgi 模式下才存在缺陷,一般來說,存在缺陷的代碼會使用類似<code>wsgiref.handlers.cgihandler</code> 的 cgi 控制器

正常方式部署的 python web 應用不受影響(大多數人使用 wsgi 或 fastcgi,這兩個不受影響),是以受到影響的 python 應用要比 php 少得多

wsgi 不受影響,因為 os.environ 不會受到 cgi 資料污染

存在缺陷的 requests 庫必須信任和使用  <code>os.environ['http_proxy']</code>,并且不做内容檢查

go 代碼必須部署在 cgi 下才受影響。一般來說受到影響的代碼會使用  <code>net/http/cgi</code> 包

像 python 一樣,這并不是部署 go 為一個 web 應用的通常方式。是以受到影響的情形很少

相較而言,go 的 <code>net/http/fcgi</code> 包并不設定實際的環境變量,是以不受影響

存在缺陷的 <code>net/http</code> 版本需要在外發請求中信任并使用  <code>http_proxy</code> ,并不做内容檢查

最好的修複方式是在他們攻擊你的應用之前盡早封擋 <code>proxy</code> 請求頭部。這很簡單,也很安全。

符合标準的 http 用戶端和伺服器絕不應該讀取和發送這個頭部

你可以從請求中去掉這個頭部或者幹脆整個封擋使用它的請求

你可以在上遊沒有釋出更新檔時自己來解決這個問題

當 http 請求進來時就檢查它,這樣可以一次性修複好許多存在缺陷的應用

在反向代理和應用防火牆之後的應用剔除  <code>proxy</code> 請求頭部是安全的

如何封擋  <code>proxy</code> 請求頭部依賴于你的配置。最容易的辦法是在你的 web 應用防火牆上封擋該頭部,或者直接在 apache 和 nginx 上做也行。以下是一些如何做的指導:

使用如下語句封擋傳遞給 php-fpm、php-pm 的請求頭,這個語句可以放在 fastcgi.conf 或 fastcgi_param 中(視你使用了哪個配置檔案):

<code>fastcgi_param http_proxy "";</code>

在 fastcgi 模式下,php 存在缺陷(但是大多數使用 nginx fastcgi  的其它語言則不受影響)。

如果你在 apache http 伺服器中使用 <code>mod_cgi</code>來運作 go 或 python 寫的腳本,那麼它們會受到影響(這裡 <code>http_proxy</code> 環境變量是“真實的”)。而 <code>mod_php</code> 由于用于 php 腳本,也存在該缺陷。

如果你使用 mod_headers 子產品,你可以通過下述配置在進一步處理請求前就 unset 掉 <code>proxy</code> 請求頭部:

<code>requestheader unset proxy early</code>

如果你使用 mod_security 子產品,你可以使用一個 <code>secrule</code> 規則來拒絕帶有 <code>proxy</code> 請求頭部的請求。下面是一個例子,要確定 <code>secruleengine</code> 打開了。你可以根據自己的情況調整。

<code>secrule &amp;request_headers:proxy "@gt 0" "id:1000005,log,deny,msg:'httpoxy denied'"</code>

通過下述配置剔除該請求頭部:

<code>http-request del-header proxy</code>

通過下述語句取消該頭部,請将它放到已有的 vcl_recv 小節裡面:

<code>sub vcl_recv {</code>

<code>[...]</code>

<code>unset req.http.proxy;</code>

<code>}</code>

使用如下語句移除該頭部。把它放到已有的過濾器裡面:

<code>http protocol httpfilter {</code>

<code>match request header remove "proxy"</code>

彈回包含 <code>proxy</code> 頭部的請求。

建立一個 <code>/path/to/deny-proxy.lua</code>檔案,讓它對于 lighttpd 隻讀,内容如下:

<code>if (lighty.request["proxy"] == nil) then return 0 else return 403 end</code>

修改 <code>lighttpd.conf</code> 以加載 <code>mod_magnet</code> 子產品,并運作如上 lua 代碼:

<code>server.modules += ( "mod_magnet" )</code>

<code>magnet.attract-raw-url-to = ( "/path/to/deny-proxy.lua" )</code>

從請求中剔除 <code>proxy</code> 頭部。加入如下語句到 <code>lighttpd.conf</code>中:

<code>req_header.remove "proxy";</code>

使用者端的修複不能解決該缺陷,是以不必費勁:

使用 <code>unset($_server['http_proxy'])</code> 并不會影響到 <code>getenv() </code>傳回的值,是以無用

使用 <code>putenv('http_proxy=')</code> 也沒效果(putenv  隻能影響到來自實際環境變量的值,而不是來自請求頭部的)

原文釋出時間為:2016-07-19

本文來自雲栖社群合作夥伴“linux中國”