Steve Kemp's Blog Writings relating to Debian & Free Software

Best practice - Don't serve writeable PHP files

Tuesday, 2 February 2016

I deal with compromises often enough of PHP-based websites that I wish to improve hardening.

One obvious way to improve things is to not serve PHP files which are writeable by the webserver-user. This would ensure that things like wp-content/uploads didn't get served as PHP if a compromise wrote valid PHP there.

In the past using php5-suhosin would have allowd this via the suhosin.executor.include.allow_writable_files flag.

Since suhosin is no longer supported under Debian Jessie I wonder if there is a simple way to achieve this?

I've written a toy-module which allows me to call stat on every request, and return a 403 on access to writeable files/directories. But it seems like I shouldn't need to write my own code for this functionality.

Any pointers welcome; happy to post my code if that is useful but suspect not - it just shouldn't exist.

| 11 comments.

 

Comments On This Entry

[gravitar] Steve Kemp

Submitted at 19:24:12 on 2 February 2016

My toy/hacky solution is here:

I do not wish to have to use this code in production, for obvious reasons.

[gravitar] Ralf

Submitted at 20:41:56 on 2 February 2016

Of course, this breaks the Wordpress Auto-Updater...

[gravitar] Michael Herold

Submitted at 22:14:09 on 2 February 2016

I never heard of a proper solution for this. I am running PHP over CGI with users differing from www-data. My unimplemented plan is to let the CGI-Script refuse calls to PHP if the file is writable for the CGI script.

However, this will not cover the case of script inclusions. Upstream seems to have to decided to not increase security here either https://wiki.php.net/rfc/script_only_include (even this RFC would not cover all problems).

Unfortunately, some software is giving me a hard time with my setup. For example, ownCloud 7 refused to work without having a writable config file, even if there is a config options that says that it should be okay.

[gravitar] Steven C.

Submitted at 22:39:02 on 2 February 2016

Getting Suhosin back into Debian would be my preference. The removal was part of a mass bug filing over really tedious licensing issues: https://bugs.debian.org/752650

[gravitar] Pete Foster

Submitted at 23:22:45 on 2 February 2016

You could use this directive in php.ini: auto_prepend_file = somescript.php

Where some script is something like: <?php if (is_writable($SERVER["SCRIPTFILENAME"])) { die(); } ?>

Yes, it still requires (a little) additional code, but it's portable. :)

[gravitar] Jean Paul Galea

Submitted at 20:38:43 on 2 February 2016

I usually use a combination of reverse proxy (e.g. nginx) and backend (e.g. fastcgi) to mitigate such issues.


# stuff here should never be passed to fastcgi!

location /wp-content/uploads {
    # empty
}

location / {
    # if file or directory do not exist:
    #       internal redirect to /index.php
    #
    # $request_uri is not modified,
    #       and wordpress picks up that value to render dynamic URIs.
    try_files $uri $uri/ /index.php$is_args$args;

location ~ \.php$ { fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; fastcgi_pass 127.0.0.1:$fcgiport; } }
[gravitar] Mensoif

Submitted at 07:51:39 on 3 February 2016

In upload folders, i usually disable php execution (In apache config or htaccess) or put a deny from all (In apache config or htaccess)

[gravitar] Steve Kemp

Submitted at 08:05:25 on 3 February 2016

Removing permissions on specific folders, such as wp-content/uploads is easy. But I'm looking for a more general solution.

So far Pete's approach of using a prepended file looks nicest, but I live in hope!

[gravitar] Steven C.

Submitted at 11:35:45 on 3 February 2016

For me, the ultimate would be if from PHP code you could make sandboxing syscalls that apply to the rest of the script's execution; the design of OpenBSD pledge(2) looks ideal to me but other OSes may be able to emulate that soon.

Either from a prepended script, or later during execution of any other script, depending on the HTTP request being handled you could surrender the ability to fork/exec, use networking or open any new file descriptors.

The important thing is being able to do this at any point within PHP code, because a sandbox applied to the main /index.php before it has done any initialisation (like SElinux) probably cannot be made very restrictive without breaking a lot of things.

[gravitar] John Leach

Submitted at 11:41:35 on 3 February 2016

I've just been using apparmor to deny php the ability to write to any file ending in .php*

A bit extreme perhaps, but it has other benefits.

I have a full apparmor profile defined for my php binary (I use php with fastcgi with apache) but you should be able to just deny php writes and allow everything else

Though now I'm unsure if Debian has apparmor.

[gravitar] Steve Kemp

Submitted at 11:50:36 on 3 February 2016

Debian does have an apparmor packages, in both Wheezy and Jessie releases..

 

Comments are closed on posts which are more than ten days old.

Spiral Logo

Search

Recent Posts

Recent Tags

Links

RSS Feed

  • Subscribe to feed