-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathFileSecurity.php
132 lines (119 loc) · 3.86 KB
/
FileSecurity.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
<?php
namespace Drupal\Composer\Plugin\VendorHardening;
/**
* Provides file security functions.
*
* IMPORTANT: This file is duplicated at /lib/Drupal/Component/FileSecurity.
* If any change is made here, the same change should be made in the duplicate.
* See https://www.drupal.org/project/drupal/issues/3079481.
*
* @internal
*/
class FileSecurity {
/**
* Writes an .htaccess file in the given directory, if it doesn't exist.
*
* @param string $directory
* The directory.
* @param bool $deny_public_access
* (optional) Set to FALSE to ensure an .htaccess file for an open and
* public directory. Default is TRUE.
* @param bool $force
* (optional) Set to TRUE to force overwrite an existing file.
*
* @return bool
* TRUE if the file already exists or was created. FALSE otherwise.
*/
public static function writeHtaccess($directory, $deny_public_access = TRUE, $force = FALSE) {
return self::writeFile($directory, '.htaccess', self::htaccessLines($deny_public_access), $force);
}
/**
* Returns the standard .htaccess lines that Drupal writes.
*
* @param bool $deny_public_access
* (optional) Set to FALSE to return the .htaccess lines for an open and
* public directory that allows Apache to serve files, but not execute code.
* The default is TRUE, which returns the .htaccess lines for a private and
* protected directory that Apache will deny all access to.
*
* @return string
* The desired contents of the .htaccess file.
*
* @see file_save_htaccess()
*/
public static function htaccessLines($deny_public_access = TRUE) {
$lines = static::htaccessPreventExecution();
if ($deny_public_access) {
$lines = static::denyPublicAccess() . "\n\n$lines";
}
return $lines;
}
/**
* Returns htaccess directives to deny execution in a given directory.
*
* @return string
* Apache htaccess directives to prevent execution of files in a location.
*/
protected static function htaccessPreventExecution() {
return <<<EOF
# Turn off all options we don't need.
Options -Indexes -ExecCGI -Includes -MultiViews
# Set the catch-all handler to prevent scripts from being executed.
SetHandler Drupal_Security_Do_Not_Remove_See_SA_2006_006
<Files *>
# Override the handler again if we're run later in the evaluation list.
SetHandler Drupal_Security_Do_Not_Remove_See_SA_2013_003
</Files>
# If we know how to do it safely, disable the PHP engine entirely.
<IfModule mod_php.c>
php_flag engine off
</IfModule>
EOF;
}
/**
* Returns htaccess directives to block all access to a given directory.
*
* @return string
* Apache htaccess directives to block access to a location.
*/
protected static function denyPublicAccess() {
return <<<EOF
# Deny all requests from Apache 2.4+.
<IfModule mod_authz_core.c>
Require all denied
</IfModule>
# Deny all requests from Apache 2.0-2.2.
<IfModule !mod_authz_core.c>
Deny from all
</IfModule>
EOF;
}
/**
* Writes the contents to the file in the given directory.
*
* @param string $directory
* The directory to write to.
* @param string $filename
* The file name.
* @param string $contents
* The file contents.
* @param bool $force
* TRUE if we should force the write over an existing file.
*
* @return bool
* TRUE if writing the file was successful.
*/
protected static function writeFile($directory, $filename, $contents, $force) {
$file_path = $directory . DIRECTORY_SEPARATOR . $filename;
// Don't overwrite if the file exists unless forced.
if (file_exists($file_path) && !$force) {
return TRUE;
}
// Try to write the file. This can fail if concurrent requests are both
// trying to write a the same time.
if (@file_put_contents($file_path, $contents)) {
return @chmod($file_path, 0444);
}
return FALSE;
}
}