As discussed on the mailinglists and on my blog. When running multiple sites on one server, maintained or adminstered by various people, then one really wants to disable all use of php input. Not only by permissions, but really.

Because sticking stuff in permissions means that you cannot hand out "administer users" "administer permissions" etc. in practice, the same as disallowing about 30% of all administration functions. That is bad.

Hence I stripped all the php stuff from filter.module and stuck it in a phh input module. If you remove that module, you can finally go to sleep again, without worrying about one client 0wnz0r1ng your server the next morning. Or for that matter, one funny client stealing all stuff from the other client (by including his settings.php).

Allowing PHP trough the web is bad. Always. IMO. I want to be able to run drupal without any php input at all. This patch is the first step towards that.

Note that i do not want to *remove* the option, for it is usefull (unsafe, but usefull) for a lot of people.
Just that I want to be able to sleep again :)

Bèr

PS: setting this to critical is intentional; Setting it to code needs work too. For IMO this is a critical post 4.7 task. One that should be dealt with immediately after the release. (for backportability, most of all)

Comments

killes@www.drop.org’s picture

If you cant sleep due to PHP filters you should get out of the hosting business. ;->

SCNR

chx’s picture

killes@www.drop.org’s picture

I prefer this solution over the one proposed by chx.

adrian’s picture

+1 on this approach.

For hosting providers, this is fairly important.

the php filter is like handing people a loaded gun.

chx’s picture

Status: Needs work » Needs review

I thought this as the second step after my patch. But even if only this one gets in, I am fine.

And this is not post 4.7 but pre 4.7. Releasing another version with PHP filter... dangerous.

morbus iff’s picture

I prefer this approach over chx's too. Some notes:

* I'd rather it be called filter_php.module, to sort properly and to be more indicative of it's function.
* I'd all for it being post 4.7, and not pre 4.7. This is, IMO, not as big a problem as chx makes it out to be.
* "run PHP (be carefull)" is, IMO, too .. .. . .. "condescending". I'd much rather a neutral "allow input to be PHP".

I'll see about working on a revision sometime next week.

Bèr Kessels’s picture

off topic, but still rather important: mty plans for the blocks visibility.

For now we got the permission in. But this means that anyone who can change permissions, can get to PHP level, can get anywhere. In otgher words, taht particular part needs a lot of love too. But that IMO is a very unrelated patch. Here are my plans:
* Get a block_visibility hook in: any modulecan decide on the visibility of a block.
* block.module will be using that o present some basic visibility settings (I was thinking in the line of what we have in 4.6°
* php_block_vis.module (or even the phpinput.module in this patch) would use that hook to present php options for adding/removing blocks acc. to PHP input.

But, I need to stress, that that is a next step, IMO. This patch is important enough to not let it wait for that plan.

Bèr

rbrooks00’s picture

I think this needs to be done as an option and not an absolute (i.e. we are removing this from core and making it a contributed module). This has the potential to cause problems for a lot of sites that might be using this if they all of a sudden upgrade and can't author PHP anymore. PHP is frequently used for small dynamic blocks and pages, see: http://drupal.org/node/39282

If we are talking about a hosted situation wouldn't someone be able to download this module and install it anyway? If they don't have FTP access then it could be something in the settings.php file.

This approach seems to drastic to correct a problem that doesn't exist for many people. It would be good as an optional feature though.

chx’s picture

Ber's patch contains the php_filter.module , we could keep it in core.

drewish’s picture

+1, I think this is an excellent idea.

Richard Archer’s picture

+1 for this concept.

fax8’s picture

+1 for me. php code evaualtion should be on an separate module.
this patch also adds the permissions "run PHP (be carefull)" which is more
straightforward than going to administer » input formats » PHP code » edit .

A little problem:

if ($delta == 0) {
   return drupal_eval($text);
else {
  return $text;
}

should be:

if ($delta == 0) {
  return drupal_eval($text);
}
else {
  return $text;
}
morbus iff’s picture

fax8: please recheck your comment. I am unable to detect the difference between those two snippets.

Stefan Nagtegaal’s picture

Morbus, I think it's in the indentation... :-)

moshe weitzman’s picture

Status: Needs review » Needs work

looks good to me. we need to update existing input formats, right? also need to enable this module for sites currently using the filter. the update path needs work.

kbahey’s picture

+1 for this.

Keep it in core, as a separate module, disabled by default.

Let people enable it if they so want. Staying in core means that it will be constantly scrutinized and not neglected/overlooked.

drewish’s picture

Morbus Iff, the if block doesn't have a closing }.

morbus iff’s picture

Ah! Thankee.

Bèr Kessels’s picture

StatusFileSize
new7.89 KB

this patch has the closing } added.

Steven’s picture

  • Update path definitely needed (the delta for the linebreak filter has changed as well!)
  • The permission 'run php' is not used in the php_input.module, and is not tied to the PHP filter. So it is misleading and unnecessary.
  • The $delta == 0 stuff in php_input is unnecessary, it is only needed when you have multiple filters in a single hook_filter().

Also, by requiring the user to set up the php_input module, there is a risk that they will plunk it into the default Filtered HTML format. How do we avoid this?

chx’s picture

  • I know that the upgrade path is being worked on. Should be pretty easy, one query against system (flip the new module on) and one against the filters table.
  • Yes, the permission is not needed.
  • I advice to avoid the filter clash by assigning a negative delta to those filters which can not be combined with any other. Checked database tables, there is no "unsigned" on filters.delta. filter_admin_filters_save is the place to check this. BTW. there is nothing to stop the idiot currently from adding PHP filter to filtered HTML. But I can see your problems so I am willing to cooperate with Ber on this.
Bèr Kessels’s picture

about the persmission
We can remove the permission. Or use it in the filter.
The latter has the problem that it feels odd because the filter system has its own private and rather confusing permission system. (not going into that now :p).
The first has the problem that it will be re-introduced in a few days wen we move over the PHP for block visibiliy. My idea of that permission was, indeed, to use it sidewide. For all the PHP input, also in contribs.(I already rewrote sections module to use the blocks permission)

So both scenarios have their pro's and con's. I would say we
* either choose NO 'can use php input' permission at all.
* or use it in *all* places. Meaning in the filter settings too.

moshe weitzman’s picture

ok folks. anyone willing to refresh this patch and write the update?

gerhard killesreiter’s picture

I've wrtiten paranoia.module which disables the creation of new php filters. You still need to delete the existing one manually (although I could move that into the install script).

Is this a useful solution to this thread?

Bèr Kessels’s picture

I am testing the project by Gerhard. And so far, it seems a good alternative for this patch.

I would love a "visionary" comment by Dries, about what route he likes: Solve such "security" issues in contribs, or build them into core.
If the latter, we cannot close this thread. If the first, I would love to close it.

drumm’s picture

Status: Needs work » Postponed

Lets consider this for the next version.

Zen’s picture

Version: x.y.z » 6.x-dev
Assigned: Bèr Kessels » Zen
Status: Postponed » Needs review
StatusFileSize
new10.08 KB

Reviving:

Rerolled Bèr's patch + changed php_input to php_filter + incorporated Unconed's points.

Update patch + language fixes to be addressed once primary changes are given the green light.

Please feel free to update patch rather than wait for me to do so :)

Thanks,
-K

Zen’s picture

StatusFileSize
new10.12 KB

Missed a chunk.

chx’s picture

Re. Steven's question, how we avoid putting PHP filter into Filtered HTML -- what about a mechanism that would make it possible for a filter to define that it is a standalone filter and it can not be mated with anything? Or if it is decided that it is only PHP filter that needs this mechanism, then simply make filter module recogn it and refuse to put it into any format which is not empty and refuse to add anything to a format which contains the PHP filter.

Bèr Kessels’s picture

re: filters. I'd say that *on top of the filters* the global permission 'insert php' should be in place. So, regardless who you assign php input filters to, they won't work if that person has no got 'insert php' access'.

Off course we would need to communicate this in the interface too. e.g. by graying out the 'php input filter' for roles without the access to 'insert php'.

Zen’s picture

I personally think that a dire warning will suffice. Let's not over-engineer here.

Thanks,
-K

Stefan Nagtegaal’s picture

First of all, i did not test the patch (yet)..
But wouldn't it be better, to not display the option at all if the sufficient permissions aren't there for the user?

Once again, I did not tested the patch yet...

Bèr Kessels’s picture

@zen, this is not about over-engineering, this is security. We should 'engineer' this is such a way, that an admin can go to sleep once (s)he has the PHP input permissions set, or unset. Knowing that these permissions will make sure that those *without* the permissions can never insert or inject PHP.

Example: here, at Drupal.org I suddenly had rights to insert PHP at one moment, due to a misconfiguration after an upgrade. Now, that is not a huge issue, since I had quite high admin rights anyway. But it shows that an admin still needs to take great care. Such a critical issue as allowing PHP input, should work VERY transparent. If I do not give someone PHP rights, that person should not be able to insert PHP. Nothing more nothing less. We cannot expect everyone to be aware that in some far corner of the Drupal site, another setting can/will grant that same person PHP rights again.

dries’s picture

Looks good, but please rename the module to php.module. Thanks.

Zen’s picture

Status: Needs review » Reviewed & tested by the community
StatusFileSize
new9.96 KB

Blanket rename of php_filter to just php as per Dries' request. No other changes. Setting to RTBC.

I'm working on the updater patch as we speak.

-K

Zen’s picture

StatusFileSize
new3.72 KB

Updater patch attached. While #35 is RTBC, this patch is _not_. Please review and test.

Thanks,
-K

nedjo’s picture

This change is indeed needed.

At the same time, we should be developing a broader solution to the problem of conditionally limiting PHP input. I've posted a complimentary patch to add a variable we can set in settings.php, 'php_input', which would be the means of preventing all user-input PHP code on a site, http://drupal.org/node/134779.

Steven’s picture

Status: Reviewed & tested by the community » Needs work

I'm not convinced this is the best approach... if you are afraid of PHP input, you may want to lock down other things on a Drupal site too. A paranoia.module seems a much better solution than removing useful features from Drupal core. Unless someone can bring up some solid arguments why that approach is not viable, I'd prefer not committing this patch.

Pasteable PHP snippets are a very useful way of customizing your site for example. With this change, we now require novice users to 1) Enable an additional module 2) Add a new input format, with the right permissions 3) Add the filter to the newly created format. If we do go down this road, at the very least, there should be a module_enable hook to create the format with the filter in it, otherwise we will have clueless people dropping the php filter into the Filtered HTML format.

As for a global php_input variable... this is very un-Drupal-like. It doesn't appear like the variable would cleanly disable PHP from the UI everywhere, but merely lock it down for use. That could lead to a frustrating experience for users for that installation.

chx’s picture

I love having PHP around to do quick stuff on my site (running queries from node/add/page -- lovely!) . As for security well, it can be dangerous, but to the hell with it, we have now much better defaults and the choice checker than we had a year and a half ago. I would like to hear what Heine thinks over this one.

Bèr Kessels’s picture

Many people, systems and distributions consider "able to run aribtrary code" as a critical security hole. When you install Drupal, you have such a possibility. It is arguable wether this is a valid and handy feature (Drupal community leans towards that) or a critical security hole. Fact remains, that for many people it /is/ a security issue at the very least.

Drupal (community) can do two things: ignore these people and defend the argument of this being a feature, not a security hole. And tell them to "use some hack around the hole", by attempting
Or we can offer a way to remove the feature.

IMO the latter is by far the a) cleanest, b) securest, c) simplest.
Note that this does not mean removeing it from core, as Steven makes you think. We must simply *offer people the ability* to remove it from core. This is not the same!

By sticking all the PHP input in one module, the only thing one needs to do, is remove that module.

That way, it is CERTAIN that no-one can run PHP. Since the feature is not there at all. This is very different from havin the feature around, yet denying access to it. The latter can be seen as a security hole that is still in your application, without having a *known* way to abuse it.

So: again: We are not argueïng to remove this from core. We are simply trying to isolate all the PHP input in one module, and with that, offer users a way to choose for themselves if they take the risk of having this feature around. Freedom to Choose ++.

Zen’s picture

Status: Needs work » Needs review
StatusFileSize
new1.58 KB

.install file patch attached to add a PHP code input format.

There are 3 patches now:
#35 - reviewed.
#36 - To be reviewed & tested.
#41 - To be reviewed & tested.

dries’s picture

1. I think it makes sense to move this to an additional module that can be removed from disk.

2. At the same time, I agree with Steven that it is safer/better if _we_ can pre-configure this, then when the user has to configure it him selves. It's less prone to errors.

I think we can do (1) and pre-configure the PHP input format so (2) isn't a concern. Heck, we could even enable the PHP input filter by default but still make it easy to disable.

----

Another solution, but not necessarily better, would be to rely on PHP's "disable_functions" setting. You can globally disable function calls by listing them in the disable_functions variable in your php.ini file. I haven't tried it yet, but if a hosting company globally disables eval(), maybe we can wrap the PHP filter code in a function_exist() call? So, when eval() is disabled, we degrade gracefully (assuming that function_exist() would work for disabled functions). Not sure if it would work, but I figured, I'd float the idea.

The disable_functions approach might be better because it is a technique that hosting companies are probably already familiar with -- it fits their workflow. However, it might be problematic because other parts of Drupal might rely on eval(). The locale module, for example, uses something like '@eval("return intval($locale_formula);");' ...

Steven’s picture

I'm just wondering if paranoia.module isn't better because there are other things to consider. A somewhat insecure contrib module could allow a privileged admin to upload .php files for example. And generally, you may want to lock down some other settings in the administration, like allowed file extensions. Remember that .pdf XSS vulnerability which is still out there?

It just seems to me that turning the php filter off is just one of many things that need to be done, and that there is very little reason to make core less useful out of the box. The PHP code filter is way more than just a development tool. It helps people build sites and gives those who would otherwise shy away from PHP an easy way of customizing simple snippets.

As long as it as simple as turning on the relevant module, I'd be okay with it though.

nedjo’s picture

This would be easier to evaluate as a single patch rather than three. The first one at any rate needs more work (see below).

As long as it as simple as turning on the relevant module, I'd be okay with it though.

I think that's the idea. In fact, most people won't have to turn it on--that will be done in the relevant install profile.

Besides the PHP filter, the other part of core we need a solution for is the PHP block configuration. That's what's in my patch at http://drupal.org/node/134779 (and, yes, it deals with the UI as well as the data handling). Should I rewrite that to be part of this patch?

I'm thinking we should move drupal_eval() into php.module, perhaps renaming it to php_eval(). That way we know it can't be called unless the module is present.

When this patch is applied, contrib modules wanting to conditionally add user PHP input could test for the php module:


if (module_exists('php')) {
  // PHP input here.
}

(replacing the need for the configuration setting I'd previously suggested).

dries’s picture

Steven -- what else would a paranoia module do, and how? Could you try and provide an itemized list of some ideas?

I see two problems with a paranoia module:

1. The user can disable/enable it. We want to ISP owner to have control here, not the user. So when the ISP owner, removes php.module, he/she knows that the site owner can't re-enable it.

2. ISP have their own workflow and audit processes. When you look at this through the eyes of a very conservative ISP, there is only one solution ... and that's to disable certain functions at the PHP-level. It's a simple switch that is guaranteed to work, and that doesn't put additional burden on their shoulders. They don't want to audit our code, or inspect whether the paranoia module really works. All they want to know is whether Drupal degrades gracefully when eval() is disabled. If I were an ISP, I would not want to rely on or trust paranoia.module, I just want to use disable_function. Is that a viewpoint you can relate to?

However, if you look at this from a user's point of view, a paranoia module might be the better choice.

Zen’s picture

StatusFileSize
new3.72 KB

Update number changed from 2007 to 2008.

#35 - reviewed.
#46 - To be reviewed & tested.
#41 - To be reviewed & tested.

I think everybody is in general agreement that the filter should live in a separate module #35: User Node Favorites/Bookmarks. There is no other way to disable it from everybody including UID #1. It is still going to remain in core.

New installations will (based on the installation profile) have it disabled by default; it is safe to assume that by the time an admin decides that he needs a PHP filter, he will have understood how to enable modules. Enabling the module #41: User option to make email address visible. installs the format and sets everything up.

Upgraded installations will see no difference [#46] other than having the ability to turn it off via the modules page. A warning has been provided for this case.

ISPs aside, without the PHP filter disabled, one cannot have a safe multi-site installation without custom frippery. Multi-site A's admin will be able to access the settings.php etc. of multi-site B using the PHP filter. The point of a multi-site is lost unless all the sites have the same admin or something similarly restrictive.

-K

killes@www.drop.org’s picture

Dries: http://drupal.org/project/paranoia

You can't disable the module if you can't access the database.

dries’s picture

Zen -- looks good to me. When I enable the PHP filter module, will it properly configure itself or is that left for the user?

Zen’s picture

Updated the update patch to sync with HEAD.

@Dries: The .install and the system update both create a PHP code input format and add the PHP evaluator filter to it.

#35 - reviewed.
#49 - To be reviewed & tested.
#41 - To be reviewed & tested.

Thanks,
-K

Zen’s picture

StatusFileSize
new3.7 KB

And the patch :/

#35 - reviewed.
#41 - To be reviewed & tested.
#50 - To be reviewed & tested.

-K

dries’s picture

Zen, could you roll everything into one big patch. I'd like to test and commit this. :)

Zen’s picture

StatusFileSize
new15.25 KB

All in one patch.

Thanks,
-K

dries’s picture

Status: Needs review » Fixed

I've tested this, and committed it to CVS HEAD. We can refine this as necessary but it marks an important first step. Thanks Zen and Ber.

Anonymous’s picture

Status: Fixed » Closed (fixed)
nedjo’s picture

http://drupal.org/node/124158 follows up on this patch by moving PHP page matching and drupal_eval() to php.module.

gábor hojtsy’s picture

Unfortunately the upgrade path of this patch is less than satisfactory. See http://drupal.org/node/194304