Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Menu
Open sidebar
Sympl
Sympl
Commits
aa8903c5
Commit
aa8903c5
authored
Jun 16, 2019
by
Paul Cammish
Browse files
Significantly improved PHP security
parent
835cb69f
Changes
12
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
CHANGELOG
View file @
aa8903c5
CHANGELOG
---------
* 2019-06-16 - Significantly improved default security for PHP
- PHP is now restricted to public/, and has domain-specific tmp and
sessions directories which are automatically created.
- PHP is now disabled in a path that matches 'wp-content/uploads'
significantly securing all WordPress sites.
- Enables OSCP stapling by default. Disables HSTS by default.
- zz-mass-hosting now configures all sites, not just SSL sites.
- sympl-web-logger now only used for the zz-mass-hosting fallbacks.
- PHP defaults to blocking dangerous functions such as eval() and
exec() which should not be needed typically. This can be re-enabled
but effects all sites on the server.
- new config files: config/disable-php-security and config/hsts.
* 2019-06-13 - Improved SQL backup script
- New script with configurbility.
- Run sympl-sqldump --help for info.
...
...
web/apache.d/non_ssl.template.erb
View file @
aa8903c5
...
...
@@ -34,7 +34,7 @@
Alias /__sympl/ "/usr/share/sympl/static/"
<Directory
"/
usr
/
share
/
sympl
/
static
/"
>
DirectoryIndex index.html
AllowOverride
All
AllowOverride
none
Require all granted
</Directory>
...
...
@@ -46,14 +46,46 @@
ErrorDocument 403 /__sympl/index.html
</LocationMatch>
#
#
# Allow users to override settings via .htaccess
# and enables PHP in htdocs/.
#
<Directory
<%=
domain
_directory
%>
>
<Directory
<%=
htdocs
_directory
%>
/
>
AllowOverride all
Require all granted
php_flag engine on
</Directory>
% if php_security_disabled?
#
# Set unique tmp/ and sessions/ directories
#
php_admin_value upload_tmp_dir
<%=
domain_directory
%>
/tmp/
php_admin_value session.safe_path
<%=
domain_directory
%>
/sessions/
% else
#
# Restrict PHP directories
# Restricts PHP from leaving the public directory.
# Also sets a unique tmp directory and sessions directory.
#
php_admin_value open_basedir
<%=
domain_directory
%>
/public/
php_admin_value upload_tmp_dir
<%=
domain_directory
%>
/tmp/
php_admin_value session.safe_path
<%=
domain_directory
%>
/sessions/
#
# Prevent executing anything from a WordPress uploads directory,
# And block access to any PHP files in that directory.
#
<LocationMatch
"
wp-content
/
uploads
/"
>
php_admin_flag engine off
</LocationMatch>
<LocationMatch
"
wp-content
/
uploads
/.
*
\.
php
"
>
deny from all
</LocationMatch>
% end
#
# The document root
#
...
...
@@ -89,11 +121,9 @@
</Directory>
#
# We need to log the virtual hostname the incoming request was
# made against, so that the cron-job in /etc/cron.daily may generate
# statistics for each domain.
# Write logs
#
ErrorLog "
|| /usr/sbin/sympl-web-logger
<%=
domain
.
log_dir
%>
/error.log"
CustomLog "
|| /usr/sbin/sympl-web-logger
<%=
domain
.
log_dir
%>
/access.log" combined
ErrorLog "
<%=
domain
.
log_dir
%>
/error.log"
CustomLog "
<%=
domain
.
log_dir
%>
/access.log" combined
</VirtualHost>
web/apache.d/ssl.template.erb
View file @
aa8903c5
...
...
@@ -28,13 +28,13 @@
<%=
server_aliases
%>
#
# This is the directory
people are redirected to if their site is
# empty.
# This is the directory
of the error page people are
#
redirected to if their site is
empty.
#
Alias /__sympl/ "/usr/share/sympl/static/"
<Directory
"/
usr
/
share
/
sympl
/
static
/"
>
DirectoryIndex index.html
AllowOverride
All
AllowOverride
none
Require all granted
</Directory>
...
...
@@ -43,7 +43,7 @@
#
<LocationMatch
"^/+$"
>
Options -Indexes
ErrorDocument 403 /__sympl/
ErrorDocument 403 /__sympl/
index.html
</LocationMatch>
<IfModule
ssl_module
>
...
...
@@ -66,14 +66,13 @@
SSLCompression off
#
# OCSP Stapling -- make sure you remove the reject-www-data
# rule from the outgoing firewall if you use this.
# OCSP Stapling
#
SSLUseStapling o
ff
SSLUseStapling o
n
SSLStaplingResponderTimeout 5
SSLStaplingReturnResponderErrors off
% if
mandatory_ssl
?
% if
hsts_enabled
?
<IfModule
headers_module
>
# HSTS (mod_headers is required) (15768000 seconds = 6 months)
Header always set Strict-Transport-Security "max-age=15768000"
...
...
@@ -83,12 +82,44 @@
#
# Allow users to override settings via .htaccess
# and eanble PHP in
#
<Directory
<%=
domain_directory
%>
>
<Directory
<%=
domain_directory
%>
/
public
/
>
AllowOverride all
Require all granted
php_flag engine on
</Directory>
% if php_security_disabled?
#
# Sets a unique tmp/ and sessions/ directory for the site.
#
php_admin_value upload_tmp_dir
<%=
domain_directory
%>
/php_tmp/
php_admin_value session.safe_path
<%=
domain_directory
%>
/php_sessions/
% else
#
# Restrict PHP directories
# Restricts PHP from leaving the public directory.
# Also sets a unique tmp directory and sessions directory.
#
php_admin_value open_basedir
<%=
domain_directory
%>
/public/
php_admin_value upload_tmp_dir
<%=
domain_directory
%>
/php_tmp/
php_admin_value session.safe_path
<%=
domain_directory
%>
/php_sessions/
#
# Prevent executing anything from a WordPress uploads directory,
# And block access to any PHP files in that directory.
#
<LocationMatch
"
wp-content
/
uploads
/"
>
php_admin_flag engine off
</LocationMatch>
<LocationMatch
"
wp-content
/
uploads
/.
*
\.
php
"
>
deny from all
</LocationMatch>
% end
#
# The document root
#
...
...
@@ -124,12 +155,10 @@
</Directory>
#
# We need to log the virtual hostname the incoming request was
# made against, so that the cron-job in /etc/cron.daily may generate
# statistics for each domain.
# Write logs
#
ErrorLog "
|| /usr/sbin/sympl-web-logger
<%=
domain
.
log_dir
%>
/ssl_error.log"
CustomLog "
|| /usr/sbin/sympl-web-logger
<%=
domain
.
log_dir
%>
/ssl_access.log" combined
ErrorLog "
<%=
domain
.
log_dir
%>
/ssl_error.log"
CustomLog "
<%=
domain
.
log_dir
%>
/ssl_access.log" combined
</VirtualHost>
<VirtualHost
<%=
ips
.
collect
{
|
ip
|
ip
+
":80"
}.
join
(
" "
)
%>
>
...
...
@@ -150,13 +179,13 @@
<%=
server_aliases
%>
#
# This is the directory
people are redirected to if their site is
# empty.
# This is the directory
of the error page people are
#
redirected to if their site is
empty.
#
Alias /__sympl/ "/usr/share/sympl/static/"
<Directory
"/
usr
/
share
/
sympl
/
static
/"
>
DirectoryIndex index.html
AllowOverride
All
AllowOverride
none
Require all granted
</Directory>
...
...
@@ -165,9 +194,10 @@
#
<LocationMatch
"^/+$"
>
Options -Indexes
ErrorDocument 403 /__sympl/
ErrorDocument 403 /__sympl/
index.html
</LocationMatch>
% if mandatory_ssl?
<IfModule
rewrite_module
>
#
...
...
@@ -176,10 +206,11 @@
RewriteEngine On
#
# Use our server na
n
e if HTTP_HOST is empty.
# Use our server na
m
e if HTTP_HOST is empty.
#
RewriteCond "%{HTTP_HOST}" =""
RewriteCond "%{HTTP_HOST}" =
""
RewriteRule ^/?(.*) https://
<%=
domain
%>
/$1 [R=301,L]
RewriteRule ^/?(.*) https://%{HTTP_HOST}/$1 [R=301,L]
</IfModule>
% else
...
...
@@ -196,12 +227,44 @@
</IfModule>
#
# Allow users to override settings via .htaccess
# and enables PHP in htdocs/.
#
<Directory
<%=
domain
_directory
%>
>
<Directory
<%=
htdocs
_directory
%>
/
>
AllowOverride all
Require all granted
php_flag engine on
</Directory>
% if php_security_disabled?
#
# Set unique tmp/ and sessions/ directories
#
php_admin_value upload_tmp_dir
<%=
domain_directory
%>
/tmp/
php_admin_value session.safe_path
<%=
domain_directory
%>
/sessions/
% else
#
# Restrict PHP directories
# Restricts PHP from leaving the public directory.
# Also sets a unique tmp directory and sessions directory.
#
php_admin_value open_basedir
<%=
domain_directory
%>
/public/
php_admin_value upload_tmp_dir
<%=
domain_directory
%>
/tmp/
php_admin_value session.safe_path
<%=
domain_directory
%>
/sessions/
#
# Prevent executing anything from a WordPress uploads directory,
# And block access to any PHP files in that directory.
#
<LocationMatch
"
wp-content
/
uploads
/"
>
php_admin_flag engine off
</LocationMatch>
<LocationMatch
"
wp-content
/
uploads
/.
*
\.
php
"
>
deny from all
</LocationMatch>
% end
#
# The document root
#
...
...
@@ -237,12 +300,10 @@
</Directory>
#
# We need to log the virtual hostname the incoming request was
# made against, so that the cron-job in /etc/cron.daily may generate
# statistics for each domain.
# Write logs
#
ErrorLog "
|| /usr/sbin/sympl-web-logger
<%=
domain
.
log_dir
%>
/error.log"
CustomLog "
|| /usr/sbin/sympl-web-logger
<%=
domain
.
log_dir
%>
/access.log" combined
ErrorLog "
<%=
domain
.
log_dir
%>
/error.log"
CustomLog "
<%=
domain
.
log_dir
%>
/access.log" combined
% end
</VirtualHost>
...
...
web/apache.d/zz-mass-hosting.ssl.template.erb
View file @
aa8903c5
...
...
@@ -38,10 +38,9 @@
SSLCompression off
#
# OCSP Stapling -- make sure you remove the reject-www-data
# rule from the outgoing firewall if you use this.
# OCSP Stapling
#
SSLUseStapling o
ff
SSLUseStapling o
n
SSLStaplingResponderTimeout 5
SSLStaplingReturnResponderErrors off
...
...
@@ -58,7 +57,7 @@
Alias /__sympl/ "/usr/share/sympl/static/"
<Directory
"/
usr
/
share
/
sympl
/
static
/"
>
DirectoryIndex index.html
AllowOverride
All
AllowOverride
none
Require all granted
</Directory>
...
...
@@ -67,7 +66,7 @@
#
<LocationMatch
"^/+$"
>
Options -Indexes
ErrorDocument 403 /__sympl/
ErrorDocument 403 /__sympl/
index.html
</LocationMatch>
#
...
...
@@ -76,8 +75,13 @@
<Directory
"/
srv
"
>
AllowOverride all
Require all granted
php_flag engine on
</Directory>
# There is no PHP security ( preventing access outside public/ ) for
# sites not individually configured, as the their directory is floating.
# However, any site created in /srv will have it's own config generated.
<IfModule
cgi_module
>
#
# We will allow global CGIs without any effort though.
...
...
@@ -111,11 +115,25 @@
#
VirtualDocumentRoot /srv/%0/public/htdocs/
php_admin_value open_basedir /srv/%0/public/
<IfModule
cgi_module
>
VirtualScriptAlias /srv/%0/public/cgi-bin/
</IfModule>
</IfModule>
#
# Prevent executing anything from a WordPress uploads directory,
# And block access to any PHP files in that directory.
#
<LocationMatch
"
wp-content
/
uploads
/"
>
php_admin_flag engine off
</LocationMatch>
<LocationMatch
"
wp-content
/
uploads
/.
*
\.
php
"
>
deny from all
</LocationMatch>
#
# Disable any restrictions or rewrites to /.well-known/acme-challenge
# This ensures Let's Encrypt can validate domain ownership.
...
...
web/apache.d/zz-mass-hosting.template.erb
View file @
aa8903c5
...
...
@@ -26,7 +26,7 @@
Alias /__sympl/ "/usr/share/sympl/static/"
<Directory
"/
usr
/
share
/
sympl
/
static
/"
>
DirectoryIndex index.html index.php
AllowOverride
All
AllowOverride
none
Require all granted
</Directory>
...
...
@@ -35,17 +35,23 @@
#
<LocationMatch
"^/+$"
>
Options -Indexes
ErrorDocument 403 /__sympl/
ErrorDocument 403 /__sympl/
index.html
</LocationMatch>
#
# Allow users to override settings via .htaccess
# and enables PHP in htdocs/.
#
<Directory
"/
srv
"
>
<Directory
<%=
htdocs_directory
%>
/
>
AllowOverride all
Require all granted
php_flag engine on
</Directory>
# There is no PHP security ( preventing access outside public/ ) for
# sites not individually configured, as the their directory is floating.
# However, any site created in /srv will have it's own config generated.
<IfModule
cgi_module
>
#
# We will allow global CGIs without any effort though.
...
...
@@ -85,7 +91,11 @@
#
# The document root + CGI-directories.
#
VirtualDocumentRoot /srv/%0/public/htdocs/
php_admin_value open_basedir /srv/%0/public/
<IfModule
cgi_module
>
VirtualScriptAlias /srv/%0/public/cgi-bin/
</IfModule>
...
...
web/debian/changelog
View file @
aa8903c5
sympl-web (9.0.190616.0) stable; urgency=medium
* Massively improved security for PHP
* PHP is now restricted to public/, and has domain-specific tmp and
sessions directories which are automatically created.
* PHP is now disabled in a path that matches 'wp-content/uploads'
significantly securing all WordPress sites.
* Enables OSCP stapling by default. Disables HSTS by default.
* zz-mass-hosting now configures all sites, not just SSL sites.
* sympl-web-logger now only used for the zz-mass-hosting fallbacks.
* PHP defaults to blocking dangerous functions such as eval() and
exec() which should not be needed typically. This can be re-enabled
but effects all sites on the server.
* new config files: config/disable-php-security and config/hsts.
-- Paul Cammish <sympl@kelduum.net> Sun, 16 Jun 2019 22:25:00 +0100
sympl-web (9.0.190612.0) stable; urgency=medium
* Massively improved security for web stats.
...
...
web/debian/sympl-web.links
View file @
aa8903c5
usr/sbin/sympl-web-configure etc/cron.hourly/sympl-web-configure
usr/sbin/sympl-web-rotate-logs etc/cron.daily/sympl-web-rotate-logs
usr/share/sympl/ssl-hooks.d/sympl-web etc/sympl/ssl-hooks.d/sympl-web
etc/php/7.0/conf.d/sympl-web.ini etc/php/7.0/apache2/conf.d/00-sympl-web.ini
usr/sbin/sympl-web-configure usr/sbin/symbiosis-httpd-configure
usr/sbin/sympl-web-rotate-logs usr/sbin/symbiosis-httpd-rotate-logs
usr/sbin/sympl-web-generate-stats usr/sbin/symbiosis-httpd-generate-stats
usr/sbin/sympl-web-configure etc/cron.hourly/sympl-web-configure
usr/sbin/sympl-web-rotate-logs etc/cron.daily/sympl-web-rotate-logs
usr/share/sympl/ssl-hooks.d/sympl-web etc/sympl/ssl-hooks.d/sympl-web
etc/php/7.0/mods-available/sympl-web.ini etc/php/7.0/apache2/conf.d/00-sympl-web.ini
etc/php/7.0/mods-available/sympl-web-security.ini etc/php/7.0/apache2/conf.d/01-sympl-web-security.ini
usr/sbin/sympl-web-configure usr/sbin/symbiosis-httpd-configure
usr/sbin/sympl-web-rotate-logs usr/sbin/symbiosis-httpd-rotate-logs
usr/sbin/sympl-web-generate-stats usr/sbin/symbiosis-httpd-generate-stats
web/lib/symbiosis/domain/http.rb
View file @
aa8903c5
...
...
@@ -3,6 +3,21 @@ require 'symbiosis/domain'
module
Symbiosis
class
Domain
#
# Checks if the PHP security should be disabled for the specific site.
#
def
php_security_disabled?
get_param
(
"disable-php-security"
,
self
.
config_dir
)
==
true
end
#
# Disabled HSTS initially, but allows it to be enabled at a later date.
#
def
hsts_enabled?
get_param
(
"hsts"
,
self
.
config_dir
)
==
true
end
#
# Checks to see if a domain should have statistics generated for it.
# Returns true if statistics should be generated, false if not.
...
...
web/php/7.0/conf.d/sympl-web.ini
deleted
100644 → 0
View file @
835cb69f
[PHP]
;
; Don't add PHP to the service signature
;
expose_php
=
0
;
; upload_max_filesize and post_max_size default to 2M and 8M
;
upload_max_filesize
=
64M
post_max_size
=
64M
web/php/7.0/mods-available/sympl-web-security.ini
0 → 100644
View file @
aa8903c5
[PHP]
disable_functions
=
exec,passthru,shell_exec,system,proc_open,popen,curl_exec,curl_multi_exec,parse_ini_file,show_source
web/php/7.0/mods-available/sympl-web.ini
0 → 100644
View file @
aa8903c5
[PHP]
;
; Don't add PHP to the service signature
;
expose_php
=
0
;
; upload_max_filesize and post_max_size default to 2M and 8M
;
upload_max_filesize
=
128M
post_max_size
=
128M
;
; Disable dangerous functions by default. To override this and enable them
; you must add a seperate php configuration file.
;
; These can only be set on a server-wide basis.
;
disable_functions
=
exec,passthru,shell_exec,system,proc_open,popen,curl_exec,curl_multi_exec,parse_ini_file,show_source
web/sbin/sympl-web-configure
View file @
aa8903c5
...
...
@@ -344,16 +344,37 @@ domains.each do |domain|
FileUtils
.
chown_R
'sympl'
,
nil
,
"
#{
domain
.
directory
}
/public/logs"
,
:verbose
=>
false
end
end
# If public/ exists and php_tmp/ doesnt, then create it
if
File
.
directory?
(
"
#{
domain
.
directory
}
/php_tmp/"
)
unless
File
.
directory?
(
"
#{
domain
.
directory
}
/php_tmp"
)
verbose
"
\t
Creating PHP tmp directory
#{
domain
.
directory
}
/php_tmp"
FileUtils
.
mkdir_p
(
"
#{
domain
.
directory
}
/php_tmp"
)
FileUtils
.
chown_R
'www-data'
,
nil
,
"
#{
domain
.
directory
}
/php_tmp"
,
:verbose
=>
false
end
end
if
apache_mass_hosting_enabled
and
domain
.
ips
.
any?
{
|
ip
|
primary_ips
.
include?
(
ip
)}
if
domain
.
ssl_enabled?
verbose
"
\t
This site has SSL enabled, and is using the host's primary IPs -- continuing with SNI."
else
verbose
"
\t
This site is using the host's primary IPs -- it is covered by the mass-hosting config. Skipping."
next
# If public/ exists and php_sessions/ doesnt, then create it
if
File
.
directory?
(
"
#{
domain
.
directory
}
/php_sessions/"
)
unless
File
.
directory?
(
"
#{
domain
.
directory
}
/php_sessions/"
)
verbose
"
\t
Creating PHP sessions directory
#{
domain
.
directory
}
/php_sessions"
FileUtils
.
mkdir_p
(
"
#{
domain
.
directory
}
/php_sessions"
)
FileUtils
.
chown_R
'www-data'
,
nil
,
"
#{
domain
.
directory
}
/php_sessions"
,
:verbose
=>
false
end
end
#
# We no longer ant this, as all sites should have their own config created automatically.
#
# if apache_mass_hosting_enabled and domain.ips.any?{|ip| primary_ips.include?(ip)}
# if domain.ssl_enabled?
# verbose "\tThis site has SSL enabled, and is using the host's primary IPs -- continuing with SNI."
# else
# verbose "\tThis site is using the host's primary IPs -- it is covered by the mass-hosting config. Skipping."
#dd next
# end
# end
this_config
=
domain
.
apache_configuration
(
ssl_template
,
non_ssl_template
,
apache2_dir
)
unless
this_config
.
is_a?
(
Symbiosis
::
ConfigFiles
::
Apache
)
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment