Enable modproxy and supporting modules in the Apache httpd.conf configuration file by uncommenting (i.e. Remove the leading '#') the following lines if necessary: LoadModule proxymodule modules/modproxy.so LoadModule proxyconnectmodule modules/modproxyconnect.so LoadModule proxyhttpmodule modules/modproxyhttp.so.
A CGI application vulnerability (in 2016)for PHP, Go, Python and others
httpoxy is a set of vulnerabilities that affect application code running in CGI, or CGI-like environments. It comesdown to a simple namespace conflict:
- Mar 30, 2021 Apache httpd 1.3 and later versions support an optional module (modproxy) that configures the web server to act as a proxy server.This can be used to forward requests for a particular web application to a Tomcat instance, without having to configure a web connector such as modjk.
- Configuring Apache Tomcat to use HTTP/TCP proxy You must modify the Java™ virtual machine (JVM) so that Apache Tomcat can use an HTTP/TCP proxy. You can do this change by setting some JVM options in the Tomcat startup script.
- RFC 3875 (CGI) puts the HTTP
Proxy
header from a request into the environment variables asHTTP_PROXY
HTTP_PROXY
is a popular environment variable used to configure an outgoing proxy
This leads to a remotely exploitable vulnerability. If you’re running PHP or CGI, you should block the Proxy
header.Here’s how.
httpoxy is a vulnerability for server-side web applications. Entrust others driver download for windows. If you’re not deploying code, you don’t need to worry.
What can happen if my web application is vulnerable?
If a vulnerable HTTP client makes an outgoing HTTP connection, while running in a server-side CGI application, anattacker may be able to:
- Proxy the outgoing HTTP requests made by the web application
- Direct the server to open outgoing connections to an address and port of their choosing
- Tie up server resources by forcing the vulnerable software to use a malicious proxy
httpoxy is extremely easy to exploit in basic form. And we expect securityresearchers to be able to scan for it quickly. Luckily, if you read on andfind you are affected, easy mitigations are available.
Isn’t this old news? Is this still a problem?
httpoxy was disclosed in mid-2016. If you’re reading about it now for the first time, you can probably relax andtake your time reading about this quaint historical bug that hopefully no longer affects any of the applications youmaintain. But you should verify that to your own satisfaction.
The content below this point reflects the original disclosure, and I’ll be leaving the site up and mostly unchanged, otherthan noting fix versions where I can. I guess I’m just saying: the time for urgency was last year.
What Is Affected
A few things are necessary to be vulnerable:
- Code running under a CGI-like context, where
HTTP_PROXY
becomes a real or emulated environment variable - An HTTP client that trusts
HTTP_PROXY
, and configures it as the proxy - That client, used within a request handler, making an HTTP (as opposed to HTTPS) request
For example, the confirmed cases we’ve found so far:
Language | Environment | HTTP client |
---|---|---|
PHP | php-fpm mod_php | Guzzle 4+ Artax |
Python | wsgiref.handlers.CGIHandler twisted.web.twcgi.CGIScript | requests |
Go | net/http/cgi | net/http |
But obviously there may be languages we haven’t considered yet. CGI is a common standard, andHTTP_PROXY
seems to be becoming more popular over time. Take the below as a sample of the mostcommonly affected scenarios:
PHP
- Whether you are vulnerable depends on your specific application code and PHP libraries, but the problemseems fairly widespread
- Just using one of the vulnerable libraries, while processing a user’s request, is exploitable.
- If you’re using a vulnerable library, this vulnerability will affect any version of PHP
- It even affects alternative PHP runtimes such as HHVM deployed under FastCGI
- It is present in Guzzle, Artax, and probably many, many libraries
- Guzzle versions in the range
>=4.0.0rc2,<6.2.1
are vulnerable, Guzzle 3 and below is not. - Another example is (update: was) in Composer’s StreamContextBuilder utility class
- Guzzle versions in the range
So, for example, if you are using a Drupal module that uses Guzzle 6.2.0
and makes an outgoing HTTP request (for example,to check a weather API), you are vulnerable to the request that plugin makes being “httpoxied”.
Python
- Python code must be deployed under CGI to be vulnerable. Usually, that’ll mean the vulnerable codewill use a CGI handler like
wsgiref.handlers.CGIHandler
- This is not considered a normal way of deploying Python webapps (most people are using WSGI or FastCGI, both of which arenot affected), so vulnerable Python applications will probably be much rarer than vulnerable PHP applications.
- wsgi, for example, is not vulnerable, because os.environ is not polluted by CGI data
- Vulnerable versions of the requests library will trust and use
os.environ['HTTP_PROXY']
, without checking if CGI is in use - Update: Fixed in
2.7.13
,3.4.6
,3.5.3
,3.6.0
(see the Python advisory)
Go
- Go code must be deployed under CGI to be vulnerable. Usually, that’ll mean the vulnerable code usesthe
net/http/cgi
package.- As with Python, this is not considered a usual way of deploying Go as a web application, so this vulnerability should berelatively rare
- Go’s
net/http/fcgi
package, by comparison, does not set actual environment variables, so it is not vulnerable
- Vulnerable versions of
net/http
will trust and useHTTP_PROXY
for outgoing requests, without checking if CGI is in use - Update: Fixed in Go
1.7rc3
, all stable versions of>=1.7
Immediate Mitigation
The best immediate mitigation is to block Proxy
request headers as early as possible, and before they hit yourapplication. This is easy and safe.
- It’s safe because the
Proxy
header is undefined by the IETF, and isn’t listed on theIANA’s registry of message headers. This meansthere is no standard use for the header at all; not even a provisional use-case. - Standards-compliant HTTP clients and servers will never read or send this header.
- You can either strip the header or completely block requests attempting to use it.
- You should try to do your mitigation as early and as far upstream as you can.
- Do it “at the edge”, where HTTP requests first enter your system.
- That way, you can fix lots of vulnerable software at once.
- Everything behind a reverse proxy or application firewall that strips the
Proxy
header is safe!
How you block a Proxy
header depends on the specifics of your setup. The earliest convenient place to block the headermight be at a web application firewall device, or directly on the webserver running Apache or NGINX. Here are a few ofthe more common mitigations:
NGINX/FastCGI
Use this to block the header from being passed on to PHP-FPM, PHP-PM etc.
In FastCGI configurations, PHP is vulnerable (but many other languages that use NGINX FastCGI are not).
For specific NGINX coverage, we recommend that you read the official NGINX blog poston this vulnerability. The blog post provides a graphic depiction of howhttpoxy works and more extensive mitigation information for NGINX.
Apache
For specific Apache coverage (and details for other Apache software projects like Tomcat), we strongly recommendyou read the Apache Software Foundation’s official advisory onthe matter. The very basic mitigation information you’ll find below is covered in much greater depth there.
If you’re using Apache HTTP Server with mod_cgi
, languages like Go and Python may be vulnerable (the HTTP_PROXY
env varis “real”). And mod_php
is affected due to the nature of PHP. If you are using mod_headers, you can unset theProxy
header before further processing with this directive:
Example for using this in .htaccess
files:
If you are using mod_security, you can use a SecRule
to deny traffic with a Proxy
header. Here’s an example,vary the action to taste, and make sure SecRuleEngine
is on. The 1000005 ID has been assigned to this issue.
Finally, if you’re using Apache Traffic Server, it’s not itself affected, but you can use it to strip the Proxy
header; very helpfulfor any services sitting behind it. Again, see the ASF’s guidance,but one possible configuration is:
Within
plugin.config
, inside the configuration directory (e.g./usr/local/etc/trafficserver
or/etc/trafficserver
),add the following directive:Add the following to a new file named
strip_proxy.conf
in the same directory:
HAProxy
This will strip the header off requests:
If your version of HAProxy is old (i.e. 1.4
or earlier), you may not have the http-request del-header
directive.If so, you must also take care that headers are stripped from requests served after the first one over an HTTP 1.1keep-alive connection. (i.e. take special note of the limitation described in the first paragraph of the 1.4 “headermanipulation” documentation)
Varnish
For Varnish, the following should unset the header. Add it to the pre-existing vcl_recv section:
OpenBSD relayd
For relayd, the following should remove the header. Add it to a pre-existing filter:
lighttpd
<= 1.4.40
To reject requests containing a Proxy
header
Create
/path/to/deny-proxy.lua
, read-only to lighttpd, with the content:Modify
lighttpd.conf
to loadmod_magnet
and run the above lua code:
Tomcat Proxyname Https
lighttpd2 (development)
To strip the Proxy
header from the request, add the following to lighttpd.conf
:
Microsoft IIS with PHP or a CGI framework
For detailed information about mitigating httpoxy on IIS, you shouldhead to the official Microsoft article KB3179800, which coversthe below mitigations in greater detail.
Also important to know: httpoxy does not affect any Microsoft Web Frameworks, e.g. not ASP.NET nor Active Server Pages.But if you have installed PHP or any other third party framework on top of IIS, we recommend applying mitigation stepsto protect from httpoxy attacks. You can either block requests containing a Proxy
header, or clear the header. (The headeris safe to block, because browsers will not generally send it at all).
To block requests that contain a Proxy
header (the preferred solution), run the following command line.
Note:appcmd.exe
is not typically in the path and can be found in the %systemroot%system32inetsrv
directory
To clear the value of the header, use the following URL Rewrite rule:
Note: URL Rewrite is a downloadable add-in for IIS and is not included in a default IIS installation.
Hiawatha
You can block any request containing a Proxy
header (or ban the sending client) via the UrlToolkit:
See more information at the hiawatha blog
LiteSpeed Web Server
Upgrade to >= 5.0.19
or >= 5.1.7
to mitigate. You can do this manually with one of these commands, or you’ll getan upgrade notification soon.
See more information at the litespeed blog
h2o Web Server
Upgrade to >= 2.0.2
and add this to your configuration:
More information can be found in this GitHub pull request.
Other CGI software and applications
Please let us know of other places where httpoxy is found. We’d be happy to help you communicate fixes for your platform,server or library if you are affected. Contact contact@httpoxy.org to let usknow. Or create a PR or issue against the httpoxy-org repo in GitHub.
Ineffective fixes in PHP
Userland PHP fixes don’t work. Don’t bother:
- Using
unset($_SERVER['HTTP_PROXY'])
does not affect the value returned fromgetenv()
, so is not an effectivemitigation - Using
putenv('HTTP_PROXY=')
does not work either (to be precise: it only works if that value is coming from anactual environment variable rather than a header – so, it cannot be used for mitigation)
Prevention
Summary
- If you can avoid it, do not deploy into environments where the CGI data is merged into the actual environment variables
- Use and expect
CGI_HTTP_PROXY
to set the proxy for a CGI application’s internal requests, if necessary- You can still support
HTTP_PROXY
, but you must assert that CGI is not in use - In PHP, check
PHP_SAPI 'cli'
Otherwise, a simple check is to not trust
HTTP_PROXY
ifREQUEST_METHOD
is also set. RFC 3875 seems to requirethis meta-variable:The
REQUEST_METHOD
meta-variable MUST be set to the method which should be used by the script to process the request
- You can still support
Don’t Trust HTTP_PROXY
Under CGI
To put it plainly: there is no way to trust the value of an HTTP_
env var in a CGI environment. They cannot bedistinguished from request headers according to the specification. So, any usage of HTTP_PROXY
in a CGI context issuspicious.
If you need to configure the proxy of a CGI application via an environment variable, use a variable name that willnever conflict with request headers. That is: one that does not begin with HTTP_
. We strongly recommend you go forCGI_HTTP_PROXY
. (As seen in Ruby and libwww-perl’s mitigations for this issue.)
PHP
CLI-only code may safely trust $_SERVER['HTTP_PROXY']
or getenv('HTTP_PROXY')
. But bear in mind that code writtenfor the CLI context often ends up running in a SAPI eventually, particularly utility or library code. And, with opensource code, that might not even be your doing. So, if you are going to rely on HTTP_PROXY
at all, you should guardthat code with a check of the PHP_SAPI
constant.
Network Configuration as Prevention
A defense-in-depth strategy that can combat httpoxy (and entire classes of other security problems) is to severely restrictthe outgoing requests your web application can make to an absolute minimum. For example, if a web application isfirewalled in such a way that it cannot make outgoing HTTP requests, an attacker will not be able to receivethe “misproxied” requests (because the web application is prevented from connecting to the attacker).
HTTPS
And, of course, another defense-in-depth strategy that works is to use HTTPS for internal requests, not just forsecuring your site’s connections to the outside world. HTTPS requests aren’t affected by HTTP_PROXY
.
How It Works
Using PHP as an example, because it is illustrative. PHP has a method called getenv()
1.
There is a common vulnerability in many PHP libraries and applications, introduced by confusinggetenv
for a method that only returns environment variables. In fact, getenv() is closer to the$_SERVER
superglobal: it contains both environment variables and user-controlled data.
Specifically, when PHP is running under a CGI-like server, the HTTP request headers (data supplied by the client) are merged into the $_SERVER
superglobal under keys beginning with HTTP_
. This is the same information that getenv
reads from.
When a user sends a request with a Proxy
header, the header appears to the PHP application as getenv('HTTP_PROXY')
.Some common PHP libraries have been trusting this value, even when run in a CGI/SAPI environment.
Reading and trusting $_SERVER['HTTP_PROXY']
is exactly the same vulnerability, but tends to happen much less often(perhaps because of getenv’s name, perhaps because the semantics of the $_SERVER
superglobal are better understood amongthe community).
Minimal example code
Note that these examples require deployment into a vulnerable environment before there is actually a vulnerability(e.g. php-fpm, or Apache’s ScriptAlias
)
PHP
Tomcat Proxyport
Python
Go
More complete PoC repos (using Docker, and testing with an actual listener for the proxied request) have been preparedunder the httpoxy Github organization.
Why It Happened
Under the CGI spec, headers are provided mixed into the environment variables. (These are formally known as“Protocol-Specific Meta-Variables”2). That’s just the way the spec works, not a failure or bug.
The goal of the code, in most of the vulnerabilities, is to find the correct proxy to use, when auto-configuring aclient for the internal HTTP request made shortly after. This task in Ruby could be completed bythe find_proxy
method of URI::Generic
, which notes:
http_proxy
and HTTP_PROXY
are treated specially under the CGI environment, because HTTP_PROXY
may be set by Proxy:header. So HTTP_PROXY
is not used. http_proxy
is not used too if the variable is case insensitive. CGI_HTTP_PROXY
can be used instead.
Other instances of the same vulnerability are present in other languages. For example, whenusing Go’s net/http/cgi
module, and deploying as a CGI application. This indicates the vulnerabilityis a standard danger in CGI environments.
History of httpoxy
This bug was first discovered over 15 years ago. The timeline goes something like:
The issue is discovered in libwww-perl and fixed. Reported by Randal L. Schwartz. 3
The issue is discovered in curl, and fixed there too (albeit probably not for Windows). Reported by Cris Bailiff. 4
In implementing HTTP_PROXY
for Net::HTTP
, the Ruby team notice and avoid the potential issue. Nice work Akira Tanaka! 5
The issue is mentioned on the NGINX mailing list. The user humbly points out the issue: “unless I’m missing something, which is very possible”. No, Jonathan Matthews, you were exactly right! 6
The issue is mentioned on the Apache httpd-dev mailing list. Spotted by Stefan Fritsch. 7
Scott Geary, an engineer at Vend, found an instance of the bug in the wild. The Vend security team found the vulnerability was still exploitable in PHP, and present in many modern languages and libraries. We started to disclose to security response teams.
So, the bug was lying dormant for years, like a latent infection: pox. We imagine that many people may have found the issue overthe years, but never investigated its scope in other languages and libraries. If you’ve found a historical discussionof interest that we’ve missed, let us know. You can contact contact@httpoxy.orgor create an issue against the httpoxy-org repo.
CVEs
httpoxy has a number of CVEs assigned. These cover the cases where
- a language or CGI implementation makes the
Proxy
header available in such a way that the application cannot tell whetherit is a real environment variable, or - an application trusts the value of the
HTTP_PROXY
environment variable by default in a CGI environment (but only where that application should have beenable to tell it came from a request)
The assigned CVEs so far:
- CVE-2016-5385: PHP
- CVE-2016-5386: Go
- CVE-2016-5387: Apache HTTP Server
- CVE-2016-5388: Apache Tomcat
- CVE-2016-6286: spiffy-cgi-handlers for CHICKEN
- CVE-2016-6287: CHICKEN’s http-client
- CVE-2016-1000104: mod_fcgi
- CVE-2016-1000105: Nginx cgi script
- CVE-2016-1000107: Erlang inets
- CVE-2016-1000108: YAWS
- CVE-2016-1000109: HHVM FastCGI
- CVE-2016-1000110: Python CGIHandler
- CVE-2016-1000111: Python Twisted
- CVE-2016-1000212: lighttpd
We suspect there may be more CVEs coming for httpoxy, as less common software is checked over. If youwant to get a CVE assigned for an httpoxy issue, there are a couple of options:
- For open source code projects, you can use the Distributed Weakness Filing Project (DWF).They have a simple way to report (public) issues using the form at iwantacve.org
- For closed source code projects, you can talk to MITRE, or one of their participating CNAs/vendors/coordinators.
Thanks and Further Coverage
We’ll be linking to official announcements from affected teams here, as they become available.
Over the past two weeks, the Vend security team worked to disclose the issue responsibly to as many affected parties as wecould. We’d like to thank the members of:
- The Red Hat Product Security team, who provided extremely useful advice and access to their experience disclosingwidespread vulnerabilities - if you’re sitting on a big or complicated disclosure, they’re a great resource to reachout to for help.
- The language and implementation teams, who kept to disclosure norms and provided lively discussion.
Download ett driver. There’s an extra page with some meta-discussion on the whole named disclosure thing and contact details.The content on this page is licensed as CC0 (TL;DR: use what youlike, no permission/attribution necessary).
I’ve put together some more opinionated notes on httpoxy on my Medium account.
Regards,
Dominic Scheirlinck and the httpoxy disclosure team
July 2016
Contact
You can email contact@httpoxy.org, or, for corrections or suggestions, feel free to open an issue on the httpoxy-org repo.
Page updated at 2017-06-23 14:17 UTC
References
The fix applied correctly handles cases with case-insensitive environment variables.libwww-perl-5.51 announcement↩
The fix applied to Curl does notcorrectly handle cases with case-insensitive environment variables - it specifically mentions the fix would notbe enough for “NT” (Windows). The commit itself carries the prescient message “since it might becomea security problem.” ↩
The mitigation in Ruby, like that for libwww-perl, correctly handlescase-insensitive environment variables. ↩
The NGINX mailing list even had a PHP-specificexplanation. ↩
Discussed in reference to CGI specifically. ↩
Proxy Support How-To
Table of Contents
Introduction
Using standard configurations of Tomcat, web applications can ask forthe server name and port number to which the request was directed forprocessing. When Tomcat is running standalone with theHTTP/1.1 Connector, it will generallyreport the server name specified in the request, and the port number onwhich the Connector is listening. The servlet APIcalls of interest, for this purpose, are:
ServletRequest.getServerName()
: Returns the host name of the server to which the request was sent.ServletRequest.getServerPort()
: Returns the port number of the server to which the request was sent.ServletRequest.getLocalName()
: Returns the host name of the Internet Protocol (IP) interface on which the request was received.ServletRequest.getLocalPort()
: Returns the Internet Protocol (IP) port number of the interface on which the request was received.
When you are running behind a proxy server (or a web server that isconfigured to behave like a proxy server), you will sometimes prefer tomanage the values returned by these calls. In particular, you willgenerally want the port number to reflect that specified in the originalrequest, not the one on which the Connector itself islistening. You can use the proxyName
and proxyPort
attributes on the <Connector>
element to configurethese values.
Proxy support can take many forms. The following sections describeproxy configurations for several common cases.
Apache httpd Proxy Support
Apache httpd 1.3 and later versions support an optional module(mod_proxy
) that configures the web server to act as a proxyserver. This can be used to forward requests for a particular web applicationto a Tomcat instance, without having to configure a web connector such asmod_jk
. To accomplish this, you need to perform the followingtasks:
Configure your copy of Apache so that it includes the
mod_proxy
module. If you are building from source, the easiest way to do this is to include the--enable-module=proxy
directive on the./configure
command line.If not already added for you, make sure that you are loading the
mod_proxy
module at Apache startup time, by using the following directives in yourhttpd.conf
file:Include two directives in your
httpd.conf
file for each web application that you wish to forward to Tomcat. For example, to forward an application at context path/myapp
:which tells Apache to forward URLs of the form
http://localhost/myapp/*
to the Tomcat connector listening on port 8081.Configure your copy of Tomcat to include a special
<Connector>
element, with appropriate proxy settings, for example:which will cause servlets inside this web application to think that all proxied requests were directed to
www.mycompany.com
on port 80.It is legal to omit the
proxyName
attribute from the<Connector>
element. If you do so, the value returned byrequest.getServerName()
will by the host name on which Tomcat is running. In the example above, it would belocalhost
.If you also have a
<Connector>
listening on port 8080 (nested within the same Service element), the requests to either port will share the same set of virtual hosts and web applications.You might wish to use the IP filtering features of your operating system to restrict connections to port 8081 (in this example) to be allowed only from the server that is running Apache.
Alternatively, you can set up a series of web applications that are only available via proxying, as follows:
- Configure another
<Service>
that contains only a<Connector>
for the proxy port. - Configure appropriate Engine, Host, and Context elements for the virtual hosts and web applications accessible via proxying.
- Optionally, protect port 8081 with IP filters as described earlier.
- Configure another
When requests are proxied by Apache, the web server will be recording these requests in its access log. Therefore, you will generally want to disable any access logging performed by Tomcat itself.
When requests are proxied in this manner, all requestsfor the configured web applications will be processed by Tomcat (includingrequests for static content). You can improve performance by using themod_jk
web connector instead of mod_proxy
.mod_jk
can be configured so that the web server serves staticcontent that is not processed by filters or security constraints definedwithin the web application's deployment descriptor(/WEB-INF/web.xml
).