Equivalent of Apache's SetEnv Variable

On śro, sie 04, 2010 at 02:48:07 -0700, Michael S. wrote:

might be an interesting approach, haven’t tried it yet. would this add
an additional stat call or two though for every PHP request, Igor?

While we’re at it, I had an experimental patch some time ago that
provided location mapping based on file extensions instead of URIs which
would prevent the above exploit.

The config looked like:

types {

application/x-httpd-php php;
}

location / {
root /the/document/root;
}

location @application/x-httpd-php {
fastcgi_pass …; # etc.
}

It never went to production but I guess I could refresh and post it if
there’s some interest in it and it has a chance of being accepted
upstream (guarded with some config option, of course).

Best regards,
Grzegorz N.

On Thu, Aug 05, 2010 at 09:17:17AM +0200, Grzegorz N. wrote:

It never went to production but I guess I could refresh and post it if
there’s some interest in it and it has a chance of being accepted
upstream (guarded with some config option, of course).

How may this prevent from the exploit if a requested file is
“/dir/1.gif/2.php” ? As I understand the file will have
“application/x-httpd-php” type ?


Igor S.
http://sysoev.ru/en/

On Thu, Aug 05, 2010 at 12:01:38AM -0700, Michael S. wrote:

Yeah I expect nginx to only be aware of the filesystem it has access to. So open_file_cache saves stat calls? How do you invalidate the cache if a file is removed? Or if I put a new file that wasn’t there I want it to instantly show up not 404 for a while? Apologies if you’ve covered this already.

open file cache entries are valid for open_file_cache_valid time, 60s
by default. If you want to cache file errors such as “not found”, you
may
set open_file_cache_errors on.

a gaping potential issue to upload arbitrary files named xx.php and you are
exploit http://site.ru/images/as5df3.jpeg/.php
Igor S.
nginx Info Page

Igor S.
Igor Sysoev

On Thu, Aug 05, 2010 at 11:29:55AM +0400, Igor S. wrote:

How may this prevent from the exploit if a requested file is
“/dir/1.gif/2.php” ? As I understand the file will have
“application/x-httpd-php” type ?

The patch hooks into the static module ngx_http_static_handler, takes
r->headers_out.content_type and searches for an appropriately named
location. If found, it reroutes the request there.

Like I said, the patch has never seen production use. Also, security
wasn’t really the motivation so I may be badly mistaken about it.

Hmm, getting more and more uncertain about it :wink: In the example above,
is 1.gif a file (and /2.php the path_info), or is it a directory (and
2.php is a normal file)? -ENOCOFFEE, I guess.

Best regards,
Grzegorz N.

On Thu, Aug 5, 2010 at 12:17 AM, Grzegorz N.
[email protected] wrote:

location @application/x-httpd-php {
 fastcgi_pass …; # etc.
}

I think this would be more appropriate, personally:

type application/x-httpd-php {
fastcgi_pass …; # etc.
}

it’s not really a location, and needing to use the “@” for prefixing a
named location… all that seems like a hack bolted on to the existing
framework.

it’d be nice to see

type text/plain {
expires max;
}

type text/css {
expires max;
}

… etc …

currently the same thing is a location block with
js|css|ico|gif|jpg|jpeg etc… one single line to max the headers
would be interesting to fill in. and not have it be conflicting with
existing locations.

On Thu, Aug 05, 2010 at 10:06:08AM +0200, Grzegorz N. wrote:

wasn’t really the motivation so I may be badly mistaken about it.

Hmm, getting more and more uncertain about it :wink: In the example above,
is 1.gif a file (and /2.php the path_info), or is it a directory (and
2.php is a normal file)? -ENOCOFFEE, I guess.

What’s about when “/dir/1.gif/2.php” is proxied to remote server ?
nginx has no access to a filesystem of the file.


Igor S.
http://sysoev.ru/en/

On Thu, Aug 05, 2010 at 12:09:33PM +0400, Igor S. wrote:

What’s about when “/dir/1.gif/2.php” is proxied to remote server ?
nginx has no access to a filesystem of the file.

It doesn’t go via the static module then and the patch won’t do
anything.

Best regards,
Grzegorz N.

On Thu, Aug 05, 2010 at 12:35:13AM -0700, Michael S. wrote:

I think this would be more appropriate, personally:

type application/x-httpd-php {
fastcgi_pass …; # etc.
}

it’s not really a location, and needing to use the “@” for prefixing a
named location… all that seems like a hack bolted on to the existing
framework.

Sure it is, it was the simplest thing that could possibly work. An
upstream submission would have to be much cleaner, of course.

… etc …

currently the same thing is a location block with
js|css|ico|gif|jpg|jpeg etc… one single line to max the headers
would be interesting to fill in. and not have it be conflicting with
existing locations.

I like your proposed syntax much better, actually.

Best regards,
Grzegorz N.

On Thu, Aug 5, 2010 at 1:10 AM, Grzegorz N.
[email protected] wrote:

I like your proposed syntax much better, actually.

Of course :slight_smile: I’m a smart guy!

It’s sort of a meta/fake location, so a location block doesn’t make
sense. It maps to types, so a “type” keyword makes sense :slight_smile:

On Thu, Aug 05, 2010 at 10:11:29AM +0200, Grzegorz N. wrote:

On Thu, Aug 05, 2010 at 12:09:33PM +0400, Igor S. wrote:

What’s about when “/dir/1.gif/2.php” is proxied to remote server ?
nginx has no access to a filesystem of the file.

It doesn’t go via the static module then and the patch won’t do
anything.

The issue is that someone is able to upload a image file to a directory
with scripts (I do not know why he is not able to override some valid
images or even the scripts themself in this case). Then someone requests
the image file as “/dir/1.gif/2.php” making exploit. I do not see
how using types will help in a case when nginx ahs not access to remote
filesystem.


Igor S.
http://sysoev.ru/en/

On Thu, Aug 05, 2010 at 12:19:22PM +0400, Igor S. wrote:

The issue is that someone is able to upload a image file to a directory
with scripts (I do not know why he is not able to override some valid
images or even the scripts themself in this case). Then someone requests

I guess it comes from apache-land, where the simplest config is “run all
.php files via the interpreter” (compared to nginx’s “run all files
under
this directory via the interpreter”). The directory where the user is
able to upload files is often a subdirectory of the application, as in:

/index.php
/foo.php
/uploads
/1.gif
/2.png
/images
/foo.gif

The more naive apps simply allow uploading of everything and store that
under /uploads, while the smarter ones try to filter files for validity.
So you cannot overwrite /foo.php or /images/foo.gif (barring directory
traversal bugs…) but can upload /uploads/anythingyoulike.gif

the image file as “/dir/1.gif/2.php” making exploit. I do not see
how using types will help in a case when nginx ahs not access to remote
filesystem.

It won’t help at all in that case. The proposed types would be a feature
of the static module. It wouldn’t be useful in single-huge-site
deployments, only for sites running on a single server (Nginx+PHP).

Best regards,
Grzegorz N.

Thu, Aug 5, 2010 at 1:49 AM, Grzegorz N. [email protected]
wrote:

It won’t help at all in that case. The proposed types would be a feature
of the static module. It wouldn’t be useful in single-huge-site
deployments, only for sites running on a single server (Nginx+PHP).

or massive sites that use nginx+php/php-fpm on the same node. it’s a
nice (and common) practice. also throw on a memcached instance to add
any extra memory to the cluster :wink:

On Thu, Aug 05, 2010 at 01:58:04PM +0400, Igor S. wrote:

Then it can be easy fixed by

location ^~ /uploads/ {
or
location ~ ^/uploads/ {

Sure. However this requires cooperation between the application user and
the server admin, which isn’t always possible (e.g. in a shared hosting
setup it’s infeasible to configure every application according to its
needs; everything must be set up well enough to work with automated
configuration).

I never liked this Apache idea of internal MIME-types such as
application/x-httpd-php, text/x-server-parsed-html, etc.
I believe it confuses and complicates things.

The Apache approach to e.g. FastCGI is positively insane, but (for me at
least) the major problem is tying everything to filesystem paths, not
assigning everything a MIME type.

Thankfully, those days are gone by, but I remember setting up a fake
path to some nonexistent ScriptAlias’ed directory(?) just to run a
FastCGI server. I sincerely hope Nginx never goes that way :wink: but if
a URL has been resolved to a real file on disk, we do have a proper MIME
type we could use. Apart from the internal types like you (and I)
mentioned, Mike proposed a less controversial (IMHO) use case:

type text/css {
expires max;
}

I think it’s quite clean and conveys the idea better than:

location ~ .css$ {
expires max;
}

Best regards,
Grzegorz N.

On Thu, Aug 05, 2010 at 10:49:52AM +0200, Grzegorz N. wrote:

/index.php
traversal bugs…) but can upload /uploads/anythingyoulike.gif
Then it can be easy fixed by

location ^~ /uploads/ {
or
location ~ ^/uploads/ {

the image file as “/dir/1.gif/2.php” making exploit. I do not see
how using types will help in a case when nginx ahs not access to remote
filesystem.

It won’t help at all in that case. The proposed types would be a feature
of the static module. It wouldn’t be useful in single-huge-site
deployments, only for sites running on a single server (Nginx+PHP).

I never liked this Apache idea of internal MIME-types such as
application/x-httpd-php, text/x-server-parsed-html, etc.
I believe it confuses and complicates things.


Igor S.
http://sysoev.ru/en/

On Thu, Aug 5, 2010 at 3:16 AM, Grzegorz N.
[email protected] wrote:

type text/css {
 expires max;
}

I think it’s quite clean and conveys the idea better than:

location ~ .css$ {
 expires max;
}

I won’t say that I am absolutely in support of this, just wanted to
add in my few cents on what the syntax should be, if it was to be
something.

My biggest pet peeve is the conflicting location blocks. I’ve often
mentioned a “super location” idea, something that gets executed at the
very end of all the other rules, so that something like adding expires
headers can be done at the very end.

The idea of using this “type” methodology is nice though, as nginx
could in theory factor it in at the very end before it spits out the
content, examining the content-type header to determine “hey, this is
text/css! I should apply these rules on it” and not having to setup
regexp’ed locations that could conflict with other location blocks.

However, the biggest thing here is to see if there is a magic way to
stop “any url ending in .php to be parsed as PHP” using existing nginx
configuration or a small patch. That would make anyone who says there
is any sort of security hazard go back into their caves (as nginx
rarely has anything to be concerned about!)

On czw, sie 05, 2010 at 03:22:19 -0700, Michael S. wrote:

My biggest pet peeve is the conflicting location blocks. I’ve often
mentioned a “super location” idea, something that gets executed at the
very end of all the other rules, so that something like adding expires
headers can be done at the very end.

I’d settle for a clean way to cover all of /foo (spanning several
locations, some of them being regex ones) with authentication or other
access controls. I’m currently using an ugly hack in Nginx code for
that. So I guess we’re aiming for roughly the same thing.

The idea of using this “type” methodology is nice though, as nginx
could in theory factor it in at the very end before it spits out the
content, examining the content-type header to determine “hey, this is
text/css! I should apply these rules on it” and not having to setup
regexp’ed locations that could conflict with other location blocks.

Would you expect it to be processed after static requests only or also
after *_pass?

However, the biggest thing here is to see if there is a magic way to
stop “any url ending in .php to be parsed as PHP” using existing nginx
configuration or a small patch. That would make anyone who says there
is any sort of security hazard go back into their caves (as nginx
rarely has anything to be concerned about!)

It’s effectively impossible if Nginx doesn’t run on the same node as the
backend as it requires matching …/foo.php the URL with …/foo.php the
file and acting upon the results. That’s why I think it belongs as an
extension in the static module.

Best regards,
Grzegorz N.

On Thu, Aug 05, 2010 at 12:16:32PM +0200, Grzegorz N. wrote:

needs; everything must be set up well enough to work with automated
Thankfully, those days are gone by, but I remember setting up a fake
I think it’s quite clean and conveys the idea better than:

location ~ .css$ {
expires max;
}

Well, how can you express this

location ~ ^/dev/.*\.css$ {
    root   /path/to/dev;
    expires off;
}

location ~ \.css$ {
    root   /path/to/production;
    expires max;
}

using mime-types ?


Igor S.
http://sysoev.ru/en/

On Thu, Aug 5, 2010 at 3:40 AM, Grzegorz N.
[email protected] wrote:

Would you expect it to be processed after static requests only or also
after *_pass?

I don’t know :slight_smile: All I know is I want to apply rules like expires
headers and such at the very end - those could be CSS/JS files being
generated on the fly by PHP for instance (which is horrible, but oh
well) and I’d like those to be treated just like static .css or .js
files. A “type” fixes that, a filename regexp does not. It’s just an
example. That example -may- have just unraveled my whole point of the
discussion, too. It’s late :slight_smile:

It’s effectively impossible if Nginx doesn’t run on the same node as the
backend as it requires matching …/foo.php the URL with …/foo.php the
file and acting upon the results. That’s why I think it belongs as an
extension in the static module.

understood. I’d say most of us are using things like try_files and if
(-e $request_filename) type checks already, so nginx is aware of the
files themselves, hence that interesting idea of a try_files $uri
inside of the location for .php files… unless I’m missing something
which is blatantly obvious in the internals of course :slight_smile:

On czw, sie 05, 2010 at 02:44:19 +0400, Igor S. wrote:

}

using mime-types ?

Dunno, how about:

location /dev {
root /path/to/dev;

type text/css {
expires off;
}
}

location / {
root /path/to/production;

type text/css {
expires max;
}
}

  1. Yes, this requires nesting type{} in location{}

  2. I don’t expect everybody to drop regex locations in favour of type{},
    I just expect it’ll make some types of configuration easier, just like
    try_files did.

Best regards,
Grzegorz N.

On Thu, Aug 05, 2010 at 12:53:26PM +0200, Grzegorz N. wrote:

Yes, Nginx is aware of files, of course :slight_smile: but unlike Apache, where
everything must be a file, it prefers operating on URLs and uses files
as late as possible. That’s my understanding of its philosophy, at
least.

I believe NSCA/Apache was being developed primarily as static web
server.
So all these , , .htaccess, etc exist.
Then mod_proxy module has been added. In nginx static files processing
is just a part of functionality, so it uses "location"s only (analog of
Apache’s ) to concentrate processing in a single place.


Igor S.
http://sysoev.ru/en/