Problem/Motivation
After following the guidelines on the Securing file permissions and ownership documentation page, and running this module, the report says "PHP files in the Drupal files directory can be executed.".
On the "Executable PHP" page it says:
The Drupal files directory is for user-uploaded files and by default provides some protection against a malicious user executing arbitrary PHP code against your site. Read more about the risk of PHP code execution on Drupal.org.
The .htaccess file is writable which poses a risk should a malicious user find a way to execute PHP code they could alter the .htaccess file to allow further PHP code execution.
From /admin/reports/security-review/help/security_review/executable_php.
.htaccess is 660:
$ ls -al web/sites/default/files | grep .htacces
-rw-rw---- 1 user www-data 486 12 feb 2025 .htaccess
Setting it to read-only seems to satisfy Security Review:
$ chmod 440 web/sites/default/files/.htaccess
$ ls -al web/sites/default/files | grep .htacces
-r--r----- 1 user www-data 486 12 feb 2025 .htaccess
The report goes green and says:
"PHP files in the Drupal files directory cannot be executed."
The permission is probably set by the last line, from the Securing file permissions and ownership doc page:
$ cd /var/www/example.org/public_html/web/sites
$ find . -type d -name files -exec chmod ug=rwx,o= '{}' \;
$ find ./*/files -type d -exec chmod ug=rwx,o= '{}' \;
$ find ./*/files -type f -exec chmod ug=rw,o= '{}' \;
Is that correct, or should we recommend another command?
Steps to reproduce
Proposed resolution
-
Check if the documentation is correct:
✅ Yes, it is correct.For Drupal to protect against PHP file execution in the Drupal files directory then a .htaccess file needs to exist with the following content and not be writeable by the webserver.
-
Check if the recommended steps to secure folders and files is correct:
✅ Command to make.htaccessread-only could be added, and it has been, as seen below.For the "files" directory in the sites/default directory and any other site directories in a multi-site installation, the permissions are slightly different because the
www-datauser must have write permission to the directory:$ cd /var/www/example.org/public_html/web/sites $ find . -type d -name files -exec chmod ug=rwx,o= '{}' \; $ find ./*/files -type d -exec chmod ug=rwx,o= '{}' \; $ find ./*/files -type f -exec chmod ug=rw,o= '{}' \; $ find ./*/files/.htaccess -type f -exec chmod ug=r,o= '{}' \; -
Verify if the check in the code is correct:
✅ It works well, and as intended.if ($writable_htaccess) { $findings[] = 'writable_htaccess'; if ($result !== CheckResult::FAIL) { $result = CheckResult::WARN; } }From https://git.drupalcode.org/project/security_review/-/blob/3.1.x/src/Plug....
-
We could include "... and Securing file permissions and ownership" in the src/Plugin/SecurityCheck/ExecutablePhp.php message, to give the users a solution?
✅ The MR has been committed.
Remaining tasks
User interface changes
API changes
Data model changes
Issue fork security_review-3550828
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #2
ressaComment #3
smustgrave commentedNot sure I follow what would the other command be?
Comment #4
smustgrave commentedActually maybe a bug?
This actually is rendering as a failure
Comment #5
ressaThanks for taking a closer look at this, it seems important.
I found another documentation page Preventing execution of untrusted PHP which states that the .htaccess file in the files folder needs to not be writeable by the webserver, and added it in the Issue Summary.
Comment #6
smustgrave commentedSo if it were a warning that would make sense?
Comment #7
ressaI am not sure ... I think the first step is to check if the documentation is correct (step#1 under "Proposed resolution") and if it is, then proceed to step #2, since the conclusion from step #1 will dictate if the commands are correct, and dictate what should be checked in step #3.
Comment #8
gregglesIt is valid to say that the .htaccess should not be writable by the webserver.
Comment #9
ressaGreat, thanks for verifying @greggles, then the next step #2 is checking the commands on Securing file permissions and ownership, specifically this line, which sets .htaccess to
rw:Assuming that is correct, should we add an extra command, dedicated to .htaccess, like this?
PS. I also wonder if we should include "... and Securing file permissions and ownership" in the src/Plugin/SecurityCheck/ExecutablePhp.php message, to give the users a solution?
Comment #10
gregglesThat all seems like a good idea.
Note that making the file read only is good, but unless the owner is changed away from the webserver user the webserver could always change the file to be writable.
Comment #12
ressaPerfect, I added the
.htaccesson Securing file permissions and ownership as it was suggested here, and added you caveat about webserver and potential scenario of changing the file to be writeable. I created an MR which adds the link to the file, like I suggested.Comment #13
smustgrave commented@greggles thoughts? I'm fine with it
Comment #14
smustgrave commentedComment #15
gregglesYes, seems great!
Comment #16
smustgrave commentedRock on
Comment #18
ressaNice, thank you both for maintaining this great module!