Forum: NGINX Possible widespread PHP configuration issue - security risk

Posted by Ed Wg (ewildgoose)
on 2010-08-27 17:23
(Received via mailing list)
Look, not had a lot of success raising this quietly.  The Nginx wiki
has a number of very insecure PHP configuration suggestions.  Anyone
using these example configurations should immediately review their
configuration and ensure that they aren't vulnerable to an upload attack
where uploaded files might be accidentally treated as executable files
by nginx

The core of the problem is that most of the example configurations
enable php scripts in *all* directories on the server.  Coupled with
relatively poor upload handling (in most PHP apps) and you have an
upload attack waiting to blow up on you.

Try the following:

1) PHP Uploads allows (erk...)

Create a file test.php containing:
<?php echo 'hello' ?>

Try and upload this.  If you can then probably turn off the server until
you fix the issue...

The attack is to construct a URL which points to the uploads directory, 
eg:
     http://myserver/uploads/test.php


2) JPG uploads allowed, and wildcard ~ .php execution allowed

Create a test file test.jpg as follows:
     # echo -e "\xff\xd8\xff\xe0\n<?php echo 'hello'; ?>" > test.jpg
     # file test.jpg
     test.jpg: JPEG image data

Now try and upload this test.jpg file to your server.  If it succeeds
then probably turn off the server until you fix the issue...

The attack is to construct a URL which points to the uploads directory
and then append /.php on the URL, eg
     http://myserver/uploads/test.jpg/.php

Under *certain* configurations (wildcard php without a specific
SCRIPT_URL set) this will cause the execution of test.jpg by the php
interpreter


The correct solution is where possible:
- Enable PHP only on files in certain directories (if possible). Exclude
upload dirs!
- Specifically disable (lots of) stuff on any upload locations!!
Remember configuration ordering in nginx puts regexp before named
locations (order is important)
- Use try_files and other techniques to additionally lock down uri to
file mapping
- Check for any Apache .htaccess files shipped with your app and
translate to nginx config where appropriate (eg blocking certain
locations completely)

There are plenty of examples of dangerous configuration on the nginx
wiki.  eg the Wordpress initially presented configuration seems
vulnerable, but further down that page a more secure config is 
presented:
     http://wiki.nginx.org/Wordpress
The Media wiki example seems to show the same vulnerability:
     http://wiki.nginx.org/NginxMediaWiki

Please just treat your uploads directory carefully.  It's a huge attack
vector.

Any volunteers to help improve the Wiki?  Anyone got some better example
configurations (which are secure)? I don't use most of the PHP apps
listed, so hard to test their configurations?

Note this is not a problem with Nginx, this is a *configuration issue*.
However, the docs recommend such an insecure default configuration that
there must surely be loads of people vulnerable here...

Cheers

Ed W
Posted by Jim Ohlstein (Guest)
on 2010-08-27 17:46
(Received via mailing list)
On 8/27/10 11:22 AM, Ed W wrote:
> upload attack waiting to blow up on you.
>
>
> Now try and upload this test.jpg file to your server. If it succeeds
> then probably turn off the server until you fix the issue...

It doesn't work on the apps I mentioned. It simply won't upload.

But again, it is still up to individual webmasters to test and secure
their own apps.

> The correct solution is where possible:
>
> There are plenty of examples of dangerous configuration on the nginx
> wiki. eg the Wordpress initially presented configuration seems
> vulnerable, but further down that page a more secure config is presented:
> http://wiki.nginx.org/Wordpress
> The Media wiki example seems to show the same vulnerability:
> http://wiki.nginx.org/NginxMediaWiki

So stop complaining about the Wiki and fix it. The Wiki is after all a
community project. If you have better ideas post them.


> there must surely be loads of people vulnerable here...
>
> Cheers
>


--
Jim Ohlstein
Posted by zuborg (Guest)
on 2010-08-27 17:48
(Received via mailing list)
http://myserver/uploads/test.jpg/.php - this attack relyes on some
php-fcgi feature ?

I don't think it will work on 'proxy_pass' to Apache

Actually, there is difference between
location ~ .php$ { }
and
location ~ .php {}

Last one will match 'test.php.jpg', but Apache will still handle such
file as image/jpeg, so 'fastcgi_pass' is  still required to exploit such
configuration.

It also applyes to first exploit too - most installations forbid access
to *.php files in upload/ dir by .htaccess, so 'proxy_pass' will return
403 in most cases.


But, again, people using 'fastcgi_pass' should take a look at their
configs, they really may be vulnerable.

Posted at Nginx Forum: 
http://forum.nginx.org/read.php?2,124297,124308#msg-124308
Posted by Ed Wg (ewildgoose)
on 2010-08-27 18:08
(Received via mailing list)
On 27/08/2010 16:45, Jim Ohlstein wrote:
>
> So stop complaining about the Wiki and fix it. The Wiki is after all a 
> community project. If you have better ideas post them.

I'm posting and yet you are apparently telling me not to post any more?
Posted by Jim Ohlstein (Guest)
on 2010-08-27 18:16
(Received via mailing list)
On 8/27/10 12:07 PM, Ed W wrote:
> On 27/08/2010 16:45, Jim Ohlstein wrote:
>>
>> So stop complaining about the Wiki and fix it. The Wiki is after all a
>> community project. If you have better ideas post them.
>
> I'm posting and yet you are apparently telling me not to post any more?

Don't be so dramatic.

I said to stop complaining about the content of the Wiki and feel free
to fix it. You seem to have all the answers.

Out...

--
Jim Ohlstein
Posted by brianmercer (Guest)
on 2010-08-27 18:23
(Received via mailing list)
Ed W Wrote:
-------------------------------------------------------
> by nginx
> 

More discussion and proposed fixes here:
http://forum.nginx.org/read.php?2,88845,88996

In addition to:

1. disabling .php execution in upload directories;
2. adding a try_files to your .php location to check that the requested
.php file exists;
you can also change this setting in php.ini

cgi.fix_pathinfo=1

to

cgi.fix_pathinfo=0

to disable that feature and then use

  location ~ ^(.+\.php)(.*)$ {
    try_files $uri =404;
    include /etc/nginx/fastcgi_params;
    fastcgi_index index.php;
    fastcgi_split_path_info ^(.+\.php)(.*)$;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    fastcgi_param PATH_INFO $fastcgi_path_info;
    fastcgi_pass http://localhost:9000;
}

if you have software that needs the path_info feature.  The only thing I
use that does is chive.

Thanks in advance for updating the wiki

Posted at Nginx Forum: 
http://forum.nginx.org/read.php?2,124297,124321#msg-124321
Posted by Ed Wg (ewildgoose)
on 2010-08-27 18:24
(Received via mailing list)
On 27/08/2010 16:47, zuborg wrote:
> http://myserver/uploads/test.jpg/.php - this attack relyes on some
> php-fcgi feature ?

I *think* it's purely down to use of this configuration stanza:

     location ~ \.php$ {
         fastcgi_pass myphp;
     }

What I try and do as far as possible is use a tighter stanza  so that it
only applies to certain files or directories or whatever.  I have done
it on a slightly ad-hoc basis so far and used IF statements if I need to
exclude stuff and a tigher regexp in other situations

My implicit question was really because I suspect there is perhaps a
better and more general way to right this generic config assuming:
- large number of arbitrary locations containing PHP files
- some dangerous locations which need to be excluded
- complicated mapping between URIs and file locations

Perhaps someone has a better base config for the above and fastcgi?


Remember the other hint here was that many web apps ship with a bunch of
.htaccess files for apache.  It feels very likely that many nginx users
forget to scan for these and translate them into appropriate nginx
configuration.  How could we better document that this usually shouldn't
be ignored?

Ed W
Posted by Ed Wg (ewildgoose)
on 2010-08-27 18:26
(Received via mailing list)
On 27/08/2010 17:15, Jim Ohlstein wrote:
>
> I said to stop complaining about the content of the Wiki and feel free 
> to fix it. You seem to have all the answers.
>

Oh fuck off you twit.

If the content is dangerously wrong (my assertion only for sure) then
sticking your head in the sand and telling the person highlighting the
problem to shut up is hardly a solution?

I *don't* have all the answers.  Why don't you get off your high horse
and we will see if we can't *together* design a better general fastcgi
config?

Regards

Ed W
Posted by Nuno Magalhães (Guest)
on 2010-08-27 18:33
(Received via mailing list)
On Fri, Aug 27, 2010 at 17:25, Ed W <lists@wildgooses.com> wrote:
>
> Oh fuck off you twit.

Gee, you're so mature.
Posted by Ed Wg (ewildgoose)
on 2010-08-27 18:43
(Received via mailing list)
Hi

> More discussion and proposed fixes here:
> http://forum.nginx.org/read.php?2,88845,88996

Thanks for the link.

However, I have to say with my "typical user" hat on: I started reading
the thread, got about halfway through, skipped to the end to find some
kind of executive summary and then came away deciding that it looked too
complicated...

Look, there are some smart cookies here and I'm sure most of the people
on this list have their server's setup securely.  However, there are a
massive 99% of other people who just want to cut and paste a config and
it's my opinion that the default configs they are likely using have big
holes in them


This isn't new stuff.  EVERY web app needs to secure the uploads
directory.  The point is more that the main config examples are for
Apache and less skilled nginx users will easily miss these subtleties.

I last posted about this 23/2/2009.  Didn't raise the slightest interest
then either.

> In addition to:
>
> 1. disabling .php execution in upload directories;

Yes, but this isn't that obvious how to do?

> 2. adding a try_files to your .php location to check that the requested
> .php file exists;

I agree.  However, we still don't have a cut'n'paste solution for the
average user?


> if you have software that needs the path_info feature.  The only thing I
> use that does is chive.

Actually I think we might be overthinking the problem here.  I don't
think it's the path_info which is the problem - the post you mentioned
was really just a special case of getting the interpreter to run
something in the uploads dir.  I think the big final config change is to
give a more generic way to avoid running files in the upload dir *at
all*.  All the other stuff such as try_files, etc is really icing after
that?


Look, heres my best attempt.  I think it's poor hence I hope someone has
a better suggestion:


Single script, enable only that single script:

                 location ~ /blah/script\.php$ {
                         include /etc/nginx/fastcgi_params;
                         fastcgi_pass    localhost:9000;
                 }

Exclude single dir, everything else executable:

                 location ~ .*.php$ {
                         include /etc/nginx/fastcgi_params;
                         if ( $uri !~ "^/images/") {
                             fastcgi_pass    localhost:9000;
                         }
                 }


> Thanks in advance for updating the wiki

I don't know what the definitive solution should be yet?  All I see are
a very confused bunch of posts showing how if you are an nginx guru it
won't happen to you..?  Lets get a core solution shall we and then we
can work from there?


Ed W
Posted by Ed Wg (ewildgoose)
on 2010-08-27 18:46
(Received via mailing list)
On 27/08/2010 17:32, Nuno Magalhães wrote:
>> I said to stop complaining about the content of the Wiki and feel 
>> free to fix it. You seem to have all the answers. 
>
>> Oh fuck off you twit.
> Gee, you're so mature.

How is your post advancing the solution?

How about you avoid quoting out of context parts of my message and focus
on the rest of that message?

Regards

Ed W
Posted by Ed Wg (ewildgoose)
on 2010-08-27 18:49
(Received via mailing list)
I'm not sure why a bunch of people are attacking me over this?

The problem is clearly worded.  I have taken some time to try and
explain the issue. I have appealed for help designing a solution and yet
half the responses are flames?

Look, I'm reasonably sure *my* servers are fine.  I don't really care if
thousands of people I don't know get their servers taken over.  However,
I have taken the time to try and help here and try to encourage
discussion on a new and better baseline config - I don't see why I'm
getting attacked over this?

Regards

Ed W
Posted by Raina Gustafson (Guest)
on 2010-08-27 18:59
(Received via mailing list)
Hey Ed W,

Just want to say that while I'm not participating in this dialog since
it is over my head, I am listening and I do appreciate your asking
these questions, as well as your general commitment to Nginx and its
community.

Hopefully I am part of a silent majority in this regard.

Best,
Raina Gustafson
Posted by Cliff Wells (Guest)
on 2010-08-27 19:06
(Received via mailing list)
On Fri, 2010-08-27 at 17:45 +0100, Ed W wrote:
> on the rest of that message?
And destroy the theme of this thread?  <Gasp>

Aside from the first post I haven't seen a single response that didn't
overreact to the previous one.

My personal opinion is that if you have PHP installed you already have
serious security concerns (every server I take live almost immediately
undergoes a hostile scan for every popular PHP package in existence).

Nevertheless, I've updated the MediaWiki entry.   I'm sure there's still
8000 other security holes in MediaWiki that allow remote execution of
code, but hopefully this isn't one of them.

That being said: Ed, if you have specific information about
misconfigurations on the wiki, PLEASE update them or at least make a
note on the wiki itself that there are concerns.   As has been pointed
out, it's a community-driven project.   If something is wrong we need
people to fix it.   Your long email would have been better served as a
wiki page that was linked to from all PHP configs that appear
vulnerable.

Now, everyone fuck off.

Regards,
Cliff
Posted by brianmercer (Guest)
on 2010-08-27 19:18
(Received via mailing list)
Ed W Wrote:
-------------------------------------------------------
> This isn't new stuff.  EVERY web app needs to
> secure the uploads 
> directory.  The point is more that the main config
> examples are for 
> Apache and less skilled nginx users will easily
> miss these subtleties.
> 

As you say, your web app should have a plan for mitigating the dangers
of user uploads.  Drupal puts an .htaccess file in the upload directory
which changes the apache file handler.  Of course, that does nothing
with nginx and so you want something like

location ~ .*/files/.* {
  try_files $uri =404 # or index.php?q=$uri or @drupal depending on your
config
}

located before your location ~ .php so you get a match on the files
directory and you don't execute malicious .php.  Or something more
restrictive when it comes to .php files like specifying the permitted
executable files explicitly. see
http://test.brianmercer.com/content/nginx-configuration-drupal

> I don't think it's the path_info which is the problem -

Your situation number 2 is about path info which is enabled in PHP by
default so that requests like

http://mysite.com/chive/index.php/site/login

will work.  Most web apps don't need the cgi.fix_pathinfo feature turned
on.  Drupal, Wordpress use queries.  i.e.
http://mysite.com/wordpress/index.php?q=/site/login

Some things like chive need the path info feature, and so the PHP devs
ship PHP with cgi.fix_pathinfo turned on by default, which leads to the
vulnerability with common nginx configurations.  Luckily, nginx has
support for pathinfo without enabling cgi.fix_pathinfo in php.  I noted
the config above.

The only solution is to alert people to these complexities, and to
update the sample configs on the wiki.  Unfortunately, there's about a
thousand sample configs on the web which don't account for this issue.
A page on the wiki specifically addressing upload directories and
cgi.fix_pathinfo would also be a good idea.

Posted at Nginx Forum: 
http://forum.nginx.org/read.php?2,124297,124340#msg-124340
Posted by Boris Dolgov (Guest)
on 2010-08-27 19:21
(Received via mailing list)
On Fri, Aug 27, 2010 at 9:17 PM, brianmercer <nginx-forum@nginx.us> 
wrote:
> located before your location ~ .php so you get a match on the files
> directory and you don't execute malicious .php.  Or something more
> restrictive when it comes to .php files like specifying the permitted
> executable files explicitly. see
> http://test.brianmercer.com/content/nginx-configuration-drupal
By the way, you can just write:
location ^~ /files/
{
    try_files ...;
}
And if the request matches this location, no regular expressions
locations will be tried.

--
Boris Dolgov.
Posted by Ed Wg (ewildgoose)
on 2010-08-27 19:22
(Received via mailing list)
> Nevertheless, I've updated the MediaWiki entry.   I'm sure there's still
> 8000 other security holes in MediaWiki that allow remote execution of
> code, but hopefully this isn't one of them.

The nginx wiki has of a few moments ago stopped responding for me?  I
could get to it a before, now the browser just hangs saying "connecting
to wiki.nginx.org"?

Update - I can reach some of it, but the javascript "wikibits.js" isn't
downloading, this is blocking page loading for me?


That aside, I *hope* we can do better than whatever you wrote (don't
know what you wrote though...).

Can you please see my more recent email where I have listed some general
categories of application and perhaps we can hammer out some generic
configurations that solve those situations?

After that I think is the best time to update the wiki?

Cheers

Ed W
Posted by Maxim Dounin (Guest)
on 2010-08-27 19:23
(Received via mailing list)
Hello!

On Fri, Aug 27, 2010 at 05:42:38PM +0100, Ed W wrote:

[...]

> Look, heres my best attempt.  I think it's poor hence I hope someone
> has a better suggestion:
> 
> 
> Single script, enable only that single script:
> 
>                 location ~ /blah/script\.php$ {
>                         include /etc/nginx/fastcgi_params;
>                         fastcgi_pass    localhost:9000;
>                 }

Use exact match location instead:

    location = /blah/script.php {
        ...
    }

> Exclude single dir, everything else executable:
> 
>                 location ~ .*.php$ {
>                         include /etc/nginx/fastcgi_params;
>                         if ( $uri !~ "^/images/") {
>                             fastcgi_pass    localhost:9000;
>                         }
>                 }

Use normal location instead, with "^~" (don't execute regexp
locations) modifier:

    location ^~ /images/ {
        # just handle as static, don't consult regexps
    }

    location ~ \.php$ {
        fastcgi_pass ...
    }

Or, alternatively (and much more clear, but may have problems
in older nginx versions), use inclusive/nested locations:

    location / {
        ...

        location ~ \.php$ {
            fastcgi_pass ...
        }
    }

    location /images/ {
        # just handle as static
    }

Maxim Dounin
Posted by Ed Wg (ewildgoose)
on 2010-08-27 19:34
(Received via mailing list)
Hi

> ship PHP with cgi.fix_pathinfo turned on by default, which leads to the
> vulnerability with common nginx configurations.  Luckily, nginx has
> support for pathinfo without enabling cgi.fix_pathinfo in php.  I noted
> the config above.

Thanks for clarifying this - I guess I didn't understand my own example
correctly

This stuff is quite subtle - I hope we are getting somewhere towards a
generic config starting point now...

> The only solution is to alert people to these complexities, and to
> update the sample configs on the wiki.  Unfortunately, there's about a
> thousand sample configs on the web which don't account for this issue.
> A page on the wiki specifically addressing upload directories and
> cgi.fix_pathinfo would also be a good idea.

Sounds excellent - I'm hoping some smarter folks can also suggest a
baseline cgi config and then we have all the bits together?

Note some other smart people might point out that there are other nginx
specific config that might usefully be applied to untrusted upload
directories?  Anyone think of anything that might be missed along the
SSI/directory listing line that could be abused?

Cheers

Ed W
Posted by Cliff Wells (Guest)
on 2010-08-27 19:46
(Received via mailing list)
On Fri, 2010-08-27 at 18:21 +0100, Ed W wrote:
> 
> 
> That aside, I *hope* we can do better than whatever you wrote (don't 
> know what you wrote though...).
> 
> Can you please see my more recent email where I have listed some general 
> categories of application and perhaps we can hammer out some generic 
> configurations that solve those situations?

I simply do not have time for the next several days.   I'm literally
working day and night on an app that I need ready by Monday.

Plus, I am probably the worst person to work on PHP issues as I firmly
believe PHP to be utter crap starting from its conception right down to
the last byte of its actual implementation.  It tries my patience in
ways a toddler wired on espresso couldn't.

Regards,
Cliff
Posted by Ed Wg (ewildgoose)
on 2010-08-27 19:49
(Received via mailing list)
On 27/08/2010 18:05, Cliff Wells wrote:
> Nevertheless, I've updated the MediaWiki entry.

I'm still having problems getting to the wiki - no .js files are loading
which is causing some wierd stuff to happen.

However, my opinion is that just adding try_files is only a partial
fix.  If some way is found to upload .php files (bad wikipedia config)
or some other exploit is found that can bypass the try_files then we
still have an issue.

My mediawiki config does this:

                 location ~ .*.php$ {
                         include /etc/nginx/fastcgi_params;
                         if ( $uri !~ "^/images/") {
                                 fastcgi_pass    localhost:9000;
                         }
                 }

Others have already pointed out that we can do better than my IF.
However, your try_files, plus the explicit exclusion of the /images/ dir
go a long way to secure mediawiki.  Also I think the specific exclusion
of the /images/ dir becomes quite self-documenting, whereas the
try_files is quite a subtle fix?

Cheers

Ed W
Posted by Ed Wg (ewildgoose)
on 2010-08-27 19:51
(Received via mailing list)
> I simply do not have time for the next several days.   I'm literally
> working day and night on an app that I need ready by Monday.

Sure - I can update stuff.  I only meant if you can spare some mins to
contribute to a best efforts config.

Our emails crossed - I will edit the media wiki entry to include an
exclusion for the /images/ dir also.  For me at least this is then 
"secure".


> Plus, I am probably the worst person to work on PHP issues as I firmly
> believe PHP to be utter crap starting from its conception right down to
> the last byte of its actual implementation.  It tries my patience in
> ways a toddler wired on espresso couldn't.

I hear you there... Allowing PHP apps on the server keeps me awake at
night...

As an aside, my solution has been to use linux-vservers for each php
app.  This was what led me to nginx to keep the memory usage of such a
system low.  It's super easy to segment apps though and gives an extra
amount of resilience to the installation

Not relevant to our thread though...

Cheers

Ed W
Posted by ubitux (Guest)
on 2010-08-27 19:53
(Received via mailing list)
On Fri, Aug 27, 2010 at 06:48:12PM +0100, Ed W wrote:
> 
> However, your try_files, plus the explicit exclusion of the /images/
> dir go a long way to secure mediawiki.  Also I think the specific
> exclusion of the /images/ dir becomes quite self-documenting,
> whereas the try_files is quite a subtle fix?
> 

Why don't you just check if the file exists?

I use something like that:

location ~ \.php$ {
        if (!-f $request_filename) {
                return 404;
        }
        fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock;
        fastcgi_param SCRIPT_FILENAME $vpath/$fastcgi_script_name;
        include fastcgi_params;
}

And it seems to fix the nginx issue.

> Cheers
> 
> Ed W
> 
> _______________________________________________
> nginx mailing list
> nginx@nginx.org
> http://nginx.org/mailman/listinfo/nginx

--
ubitux
Posted by Cliff Wells (Guest)
on 2010-08-27 20:05
(Received via mailing list)
On Fri, 2010-08-27 at 19:52 +0200, ubitux wrote:
> > then we still have an issue.
> > Others have already pointed out that we can do better than my IF.
> location ~ \.php$ {
>         if (!-f $request_filename) {
>                 return 404;
>         }
>         fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock;
>         fastcgi_param SCRIPT_FILENAME $vpath/$fastcgi_script_name;
>         include fastcgi_params;
> }

That's exactly equivalent to the try_files, except longer and using a
deprecated feature.

Cliff
Posted by Cliff Wells (Guest)
on 2010-08-27 20:14
(Received via mailing list)
On Fri, 2010-08-27 at 18:48 +0100, Ed W wrote:
> On 27/08/2010 18:05, Cliff Wells wrote:
> > Nevertheless, I've updated the MediaWiki entry.
> 
> I'm still having problems getting to the wiki - no .js files are loading 
> which is causing some wierd stuff to happen.

I do not see any issues... does anyone else have a problem?

> However, my opinion is that just adding try_files is only a partial 
> fix.  If some way is found to upload .php files (bad wikipedia config) 

I don't think we should try to overcome people's intentional
configuration.   Not only is it completely their fault if they go
through the difficulty of enabling a feature that is off by default, but
now we are attempting to impose our will on a user who has made a
specific decision.  This is always a bad road in software.

> or some other exploit is found that can bypass the try_files then we 
> still have an issue.

Not going to worry about such speculative future issues.  If such an
issue arises it will need to be addressed as an Nginx patch, not a
configuration option.

> Others have already pointed out that we can do better than my IF.  
> However, your try_files, plus the explicit exclusion of the /images/ dir 
> go a long way to secure mediawiki.  Also I think the specific exclusion 
> of the /images/ dir becomes quite self-documenting, whereas the 
> try_files is quite a subtle fix?

It is subtle, but all fixes are, because the underlying vulnerability is
quite subtle.  What user isn't going to look at that and say to
themselves "why do I need this if statement?".   Just use the try_files
and add a comment to its purpose.

Cliff
Posted by Michael Shadle (Guest)
on 2010-08-27 20:17
(Received via mailing list)
On Fri, Aug 27, 2010 at 11:13 AM, Cliff Wells <cliff@develix.com> wrote:

> It is subtle, but all fixes are, because the underlying vulnerability is
> quite subtle.  What user isn't going to look at that and say to
> themselves "why do I need this if statement?".   Just use the try_files
> and add a comment to its purpose.

The caveat with try_files is it means nginx has filesystem access to
check the existence of the file and an additional stat call (or more)
- it can be in the open file cache, modern systems it's not a huge
deal, etc, etc.

But it won't help if you're fastcgi_pass to a remote server that nginx
does not have the same path to the file (or have access to the php
file) at all.
Posted by Cliff Wells (Guest)
on 2010-08-27 20:42
(Received via mailing list)
On Fri, 2010-08-27 at 11:15 -0700, Michael Shadle wrote:
> deal, etc, etc.
> 
> But it won't help if you're fastcgi_pass to a remote server that nginx
> does not have the same path to the file (or have access to the php
> file) at all.

Good point.   I do prefer your more general fix, although I'd like
confirmation that it does fully address the issue (the whole split_path
thing is too weird for me to want to try to understand).

Regards,
Cliff
Posted by Ed Wg (ewildgoose)
on 2010-08-28 12:35
(Received via mailing list)
On 27/08/2010 16:45, Jim Ohlstein wrote:
> It doesn't work on the apps I mentioned. It simply won't upload.
The apps you mentioned were vBulletin and IPB.  I have done a little
more research on this and I believe I can smuggle in the PHP using  jpeg
comments.  The resulting file should pass all tests as a valid JPG, but
still be executable to the PHP interpreter...

The point is: my expectation is that with a bit of wriggling it should
be possible to find something which should get past your image upload
checks, but your PHP interpreter will still happily process it.  If your
server is misconfigured to allow accidental execution of such files then
I think you have a gaping hole in your security...  Bottom line is to
*completely disable* execution of all untrusted files (variety of ways
to do that of course)

Personally I don't believe in trusting *only* to the upload filtering to
secure a web application.  There is simply too much subtlety here that a
well crafted file should eventually be able to bypass...

Ed W
Posted by Michael Shadle (Guest)
on 2010-08-28 13:08
(Received via mailing list)
Let's stop debating and start with a clean fix. It sounds like this is
all that is needed. Anyone want to verify?

php config:
cgi.fix_pathinfo=0

then just make sure nginx splits the path info for you in case your
app needs it with fastcgi_split_path_info:
location ~ \.php$ {
   fastcgi_pass 127.0.0.1:11000;
   include fastcgi_params;
   fastcgi_split_path_info ^(.+\.php)(.*)$; # just throw this in
fastcgi_params too, then!
}

Is this the right solution? Yes or no?
Posted by Igor Sysoev (Guest)
on 2010-08-28 13:41
(Received via mailing list)
On Fri, Aug 27, 2010 at 11:06:00AM -0700, Michael Shadle wrote:

>    include fastcgi_params;
>    fastcgi_split_path_info ^(.+\.php)(.*)$; # just throw this in
> fastcgi_params too, then!
> }
> 
> Is this the right solution? Yes or no?

- location ~ \.php$ {
+ location ~ \.php {

BTW, in 0.8.x you may use

 location ~ ^(?<script>.+\.php)(?<path_info>.*)$ {
    fastcgi_pass 127.0.0.1:11000;
    fastcgi_param   SCRIPT_FILENAME  $script;
    fastcgi_param   PATH_INFO        $path_info;
    include fastcgi_params;
 }


--
Igor Sysoev
http://sysoev.ru/en/
Posted by Michael Shadle (Guest)
on 2010-08-28 13:44
(Received via mailing list)
On Fri, Aug 27, 2010 at 11:39 AM, Igor Sysoev <igor@sysoev.ru> wrote:

>  location ~ ^(?<script>.+\.php)(?<path_info>.*)$ {
>    fastcgi_pass 127.0.0.1:11000;
>    fastcgi_param   SCRIPT_FILENAME  $script;

Doesn't this typically have the $document_root$fastcgi_script_name -
so the full system path?

Thanks for the pointers, though.

I will begin adopting this style once I check it quick and pushing it
on everyone I know...
Posted by Igor Sysoev (Guest)
on 2010-08-28 13:57
(Received via mailing list)
On Fri, Aug 27, 2010 at 11:41:38AM -0700, Michael Shadle wrote:

> On Fri, Aug 27, 2010 at 11:39 AM, Igor Sysoev <igor@sysoev.ru> wrote:
> 
> > šlocation ~ ^(?<script>.+\.php)(?<path_info>.*)$ {
> > š šfastcgi_pass 127.0.0.1:11000;
> > š šfastcgi_param š SCRIPT_FILENAME š$script;
> 
> Doesn't this typically have the $document_root$fastcgi_script_name -
> so the full system path?

You are right:

š šfastcgi_param š SCRIPT_FILENAME š/path/to/files$script;

or

š šfastcgi_param š SCRIPT_FILENAME š$document_root$script;

> Thanks for the pointers, though.
> 
> I will begin adopting this style once I check it quick and pushing it
> on everyone I know...

This way saves one regex execution.
BTW, it's better for perfomance and configuration maintenance reasons
to isolate regex locaitons inside static ones as Maxim has shown:

   location / {
  š    location ~ ^(?<script>.+\.php)(?<path_info>.*)$ {
           ...
       }
       ...
   }

   location /dir1/ {
       ...
   }

   location /dir2/ {
  š    location ~ ^(?<script>.+\.php)(?<path_info>.*)$ {
           ...
       }
       ...
   }


--
Igor Sysoev
http://sysoev.ru/en/
Posted by Michael Shadle (Guest)
on 2010-08-28 14:09
(Received via mailing list)
Initial testing shows:

cgi.fix_pathinfo = 0

and Igor's suggestion:

location ~ ^(?<script>.+\.php)(?<path_info>.*)$ {
    fastcgi_pass 127.0.0.1:11000;
    fastcgi_param   SCRIPT_FILENAME  $document_root$script;
    fastcgi_param   PATH_INFO        $path_info;
    include fastcgi_params;
}

To be working properly. I need to check out PATH_INFO using old style
and new style, make sure it still reports the expected behavior for
PHP scripts (PATH_INFO, PHP_SELF, all that jazz)

The one thing I don't like is now I have to hardcode that into each
place, unless I defined the fastcgi_pass location, and then just had a
php.conf - then all of this could be done with a single line of config
code.

set $fastcgi_pass = '127.0.0.1:11000';
include php.conf;

php.conf would have this:

location ~ ^(?<script>.+\.php)(?<path_info>.*)$ {
    fastcgi_pass $fastcgi_pass;
    fastcgi_param   SCRIPT_FILENAME  $document_root$script;
    fastcgi_param   PATH_INFO        $path_info;
    include fastcgi_params;
}

Would that be a workable solution Igor? Prior to this new style of PHP
handling I used to only need two lines:

fastcgi_pass 127.0.0.1:11000;
include fastcgi_params;
Posted by Ed Wg (ewildgoose)
on 2010-08-28 14:20
(Received via mailing list)
On 27/08/2010 20:06, Michael Shadle wrote:
>      include fastcgi_params;
> }
>
> To be working properly. I need to check out PATH_INFO using old style
> and new style, make sure it still reports the expected behavior for
> PHP scripts (PATH_INFO, PHP_SELF, all that jazz)


I will believe you that this works, but it seems incredibly subtle and I
for one don't quite understand why it's working?

My point is only that we need to document how/why this is the solution
or users will deviate (innocently) and re-introduce the problem


Please, please also lets have the final solution also include an example
of how to efficiently *exclude* a certain directory. A good proportion
of apps that I have seen, ship with example Apache configurations that
do exactly this.

The suggestion was adding an excluded location:

     location ^~/images/  {
         # just handle as static, don't consult regexps
     }

However, the issue I see here is that the user then needs to
specifically configure how that location should be handled, rather than
it being an *exclusion* to the original location

Can we work excluded locations into the regexp (negative lookahead
supported?):

  location ~ ^(?!/images/)(?<script>.+\.php)(?<path_info>.*)$ {


The justification for excluding specific locations from the PHP
interpretor is that *most* applications don't encourage uploaded
executable cgi scripts and better apps are going to ship with a
recommendation to disable script execution in the upload directory.
Actually the situation is worse on Apache because there are so many ways
to trick the interpreter to run files.  However, it's seems to be such
standard practice on Apache that it seems prudent to include it in our
standardised solution?

Lots of justifications for this via google:

http://www.google.co.uk/search?hl=en&q=disable+php+script+execution+upload

Someone argued that this might be *wanted* by the application... (Some
apps *wants* users to upload .php files which should then be
executable...??!!).  I claim that it will be a serious minority of
applications desire this, and the vast majority will want uploaded files
to be non executable (regardless of extension)

Can we please, please, please try and make sure the recommended
configuration includes examples of specifically *excluding* locations
not expected to contain executable scripts...  My proposal above...

Ed W
Posted by Michael Shadle (Guest)
on 2010-08-28 14:25
(Received via mailing list)
On Sat, Aug 28, 2010 at 3:14 AM, Ed W <lists@wildgooses.com> wrote:

> I will believe you that this works, but it seems incredibly subtle and I for
> one don't quite understand why it's working?
>
> My point is only that we need to document how/why this is the solution or
> users will deviate (innocently) and re-introduce the problem

It is a bit more complex to drop in and not as "straightforward" as
one might hope. At the moment I have this working:

main nginx.conf in a server {} block:

set $fastcgi 127.0.0.1:11000;
include confs/php.conf;

root@local:/etc/nginx# cat confs/php.conf
location ~ ^(?<script>.+\.php)(?<path_info>.*)$ {
        fastcgi_buffers 16 8k;
        fastcgi_buffer_size 8k;
        fastcgi_busy_buffers_size 16k;
        fastcgi_ignore_client_abort on;
        fastcgi_index index.php;
        fastcgi_intercept_errors on;
        fastcgi_param CONTENT_LENGTH $content_length;
        fastcgi_param CONTENT_TYPE $content_type;
        fastcgi_param DOCUMENT_ROOT $document_root;
        fastcgi_param DOCUMENT_URI $document_uri;
        fastcgi_param GATEWAY_INTERFACE CGI/1.1;
        fastcgi_param QUERY_STRING $query_string;
        fastcgi_param PATH_INFO $path_info;
        fastcgi_param REDIRECT_STATUS 200;
        fastcgi_param REMOTE_ADDR $remote_addr;
        fastcgi_param REMOTE_PORT $remote_port;
        fastcgi_param REQUEST_METHOD $request_method;
        fastcgi_param REQUEST_URI $request_uri;
        fastcgi_param SCRIPT_FILENAME  $document_root$script;
        fastcgi_param SCRIPT_NAME $fastcgi_script_name;
        fastcgi_param SERVER_ADDR $server_addr;
        fastcgi_param SERVER_NAME $http_host;
        fastcgi_param SERVER_PORT $server_port;
        fastcgi_param SERVER_PROTOCOL $server_protocol;
        fastcgi_param SERVER_SOFTWARE nginx/$nginx_version;
        fastcgi_pass $fastcgi;
}

Now, it looks like $_SERVER['PATH_INFO'] is never filled in unless you
have /foo.php/somethingafterit

With cgi.fix_pathinfo=1, PATH_INFO = "/foo.php/somethingafterit"
With cgi.fix_pathinfo=0, PATH_INFO = "/somethingafterit"

Otherwise, PATH_INFO is empty if there is nothing after the .php.

PHP_SELF is empty using the new style approach to the nginx config 
block.

Using the old style, $_SERVER['PHP_SELF'] works; I tried setting a
fastcgi_param for it, but it did not take. It seems like this is
derived internally in PHP and not able to be overridden.

A lot of things reference PHP_SELF, so this could introduce an issue.
It's late, but my quick tests show a glaring caveat with that.
Posted by Ensiferous (Guest)
on 2010-08-30 18:47
(Received via mailing list)
All I'm reading here is reiterations of the previous discussion and
language elites-ism .

This is an extremely old issue, the opinion last time was that this is
not something that should be fixed in Nginx. Nginx is a reverse proxy
and there may be very valid cases where allowing such URIs make sense.

The *real* solution is to fix the php pathinfo setting, it's archaic and
shouldn't be used unless absolutely necessary. That said, I did look
around a bit on the wiki and it wasn't covered overly much, about the
only place was in my Nginx primer post so I'll go ahead and add a
section on the pitfalls page that details the issue.

Posted at Nginx Forum: 
http://forum.nginx.org/read.php?2,124297,125274#msg-125274
Please log in before posting. Registration is free and takes only a minute.
Existing account (Switch to SSL-encrypted connection)
NEW: Do you have a Google/GoogleMail or Yahoo account? No registration required!
Log in with Google account | Log in with Yahoo account
No account? Register here.