- Hardening and Security Guidance
- List of placeholder names
- Firewall
- File Access Rights
- Place data directory outside of the web root
- Isolate Docroot
- OS user handling security
- Major security improvement: use HTTPS
- Suppress server signature and PHP version information
- deny access or restrict to several files or locations
- Integrity check of ILIAS code in docroot
- Use WebAccessChecker
- Use secure passwords
- Report security issues
This guideline is going to show you some best practice examples how to improve the security of your ILIAS installation, of the webserver and it's associated components. The ILIAS e.V. requested a documentation for a "Secure ILIAS" in march 2019. The section "Hardening and Security Guidance" should be removed and the security related instructions have to be maintained in a own document.
In the following text includes some placeholder. For a better identification, they will describe here:
placeholder | description |
---|---|
%USERNAME% | an individual user name or the webserver user based on distribution |
%GROUP% | a individual group name or the webserver group based on distribution |
%HOSTNAME% | your specific fully qualified domain name of ILIAS |
%IPADDRESS% | ip address in CIDR notation |
%DOCROOT% | directory that forms the main document tree visible from the web |
%EXTERNALDATA% | ILIAS data directory outside of the web document root |
%LOGDIR% | path to the directory containing log files |
%CLIENTID% | the client name of the ILIAS installation |
Block all traffic by default and explicitly allow only specific traffic to port 443/TCP for HTTPS secured traffic. For "quality of life", it is recommend to also permit 80/TCP for a redirect to HTTPS.
If you're an experienced admin you MAY want to use more restrictive file access rights that we RECOMMEND in this document. To make it impossible for an attacker to modify PHP files if he gains control over the web server processes, those files SHOULD be owned by root
wherever possible.
The only files and directories that MUST be owned/writeable by the web user are:
- ilias.ini.php
- data/
- ILIAS data dir outside of the webservers docroot
All the other files and directories should be owned by a specific user (%USERNAME% and %GROUP%, has to be created), but readable by the web user (e.g. 644/755).
example of the suggested configuration (may you can choose other directories, based on your discretion / distribution standard):
git clone --single-branch -b release_5-4 https://github.com/ILIAS-eLearning/ILIAS.git %DOCROOT%/.
mkdir -p %DOCROOT%
mkdir %EXTERNALDATA%
mkdir %LOGDIR%
mkdir %LOGDIR%/errors
chown %USERNAME%:%GROUP% %DOCROOT% %DOCROOT%/data
chown %USERNAME%:%GROUP% %EXTERNALDATA%
chown %USERNAME%:%GROUP% %LOGDIR% %LOGDIR%/errors
chmod 2775 %DOCROOT%
chmod 2775 %EXTERNALDATA%
chmod 2775 %LOGDIR%
chmod 2775 %LOGDIR%/errors
After the installation of ILIAS is finished, you SHOULD also revoke write permission for the file ilias.ini.php
(e.g. %DOCROOT%/ilias.ini.php
).
note: for changing base setting via ILIAS setup, you need to grant write permission for the file ilias.ini.php
again.
It is highly RECOMMENDED to place your data directory outside of the web server docroot, as pointed out by the ILIAS Installation Wizard.
You MAY use openbasedir-restriction to avoid malicious software to directory-traverse out of your docroot-directory. This is very important if there are other websites on the same host.
Apache2:
php_admin_value open_basedir ./:%DOCROOT%:%EXTERNALDATA%:%LOGDIR%:/usr/share/php/:/var/www/lib/:/tmp
Nginx:
fastcgi_param PHP_VALUE open_basedir="./:%DOCROOT%:%EXTERNALDATA%:%LOGDIR%:/usr/share/php/:/var/www/lib/:/tmp";
Hint: This option will be applied to the PHP-FPM process. If there are multiple websites on your webserver you have to define a single PHP-FPM-pool for each website. Otherwise these other homepages won' t be accessible anymore.
If you use PHP-FPM (FastCGI Process Manager), you can increase security by running the PHP-FPM processes as a specific unique user instead of www-data
/ wwwrun
(depends on linux distribution).
Snippet from a PHP-FPM pool definition:
; Unix user/group of processes
; Note: The user is mandatory. If the group is not set, the default user's group
; will be used.
user = %USERNAME%
group = %GROUP%
note: NGINX and also apache2 can only run with one user (no multi user multi process model). So it is necessary to put all the "PHP-FPM"-users in the primary group of the webserver user.
You can get a trusted, free SSL certificate at https://letsencrypt.org. Or use a SSL certificate from a commercial certificate authority.
To redirect all HTTP traffic to HTTPS you SHOULD issue a permanent redirect using the 301 status code:
<VirtualHost *:80>
ServerName %HOSTNAME%
Redirect permanent / https://%HOSTNAME%/
</VirtualHost>
server {
listen *:80;
listen [::]:80;
server_name %HOSTNAME%;
location / {
return 301 https://%HOSTNAME%$request_uri;
}
The default SSL settings (e.g. ciphers & ssl protocol version ) used by web servers are often not state-of-the-art, so you SHOULD consider to choose your own settings.
Suggestion of modern settings for SSL configuration:
The following suggestion can only be a recommendation and depends completely on your specific environment (webserver software and version, used OpenSSL version, etc.).
If you use, the following suggestion, please note that the oldest compatible clients will be:
- Firefox 27
- Chrome 30
- IE 11 on Windows 7
- Edge
- Opera 17
- Safari 9
- Android 5.0
- Java 8
Older browser clients will not be able to reach the ILIAS installation!
(Version: 2.4.34, OpenSSL 1.1.1c)
Add the following line INSIDE the <VirtualHost></VirtualHost>
block:
<VirtualHost *:443>
...
ServerName %HOSTNAME%
...
SSLEngine on
SSLCertificateFile /path/to/signed_cert_plus_intermediates
SSLCertificateKeyFile /path/to/private/key
Add the following line OUTSIDE the <VirtualHost></VirtualHost>
block:
SSLProtocol all -SSLv3 -TLSv1 -TLSv1.1
SSLCipherSuite ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256
SSLHonorCipherOrder on
SSLCompression off
SSLSessionTickets off
(Version: 1.14.0, OpenSSL 1.1.1c)
Add the following line INSIDE the server block:
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
...
server_name %HOSTNAME%;
...
# certs sent to the client in SERVER HELLO are concatenated in ssl_certificate
ssl_certificate /path/to/signed_cert_plus_intermediates;
ssl_certificate_key /path/to/private_key;
ssl_session_timeout 5m;
ssl_session_cache shared:SSL:16m;
ssl_session_tickets off;
ssl_protocols TLSv1.2;
ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256';
ssl_prefer_server_ciphers on;
ssl_dhparam /etc/ssl/private/dhparam.pem;
ssl_dhparam /etc/ssl/private/dhparam.pem;
:
This specifies a file with DH parameters for EDH (Ephemeral Diffie-Hellman) ciphers.
By default, NGINX will use the default DHE parameters provided by openssl. This uses a weak key that gets lower scores.
Run openssl dhparam -out /etc/ssl/private/dhparam.pem 4096
in terminal to generate it.
We RECOMMEND to use the Mozilla SSL Configuration Generator to generate a suitable configuration and the Qualys SSL Labs Tests or the High-Tech Bridge SSL Server Test to check your settings. It is recommended to reach a "A" rating as minimum.
It is necessary to often revise these configuration. In best case, you always use the latest "Modern" configuration.
To improve the security of your ILIAS users you SHOULD set the following Headers: (this is an experience based configuration set of headers, this may differ from your configuration/usage scenario)
X-Content-Type-Options: nosniff;
X-XSS-Protection: 1; mode=block;
X-Frame-Options: SAMEORIGIN;
Referrer-Policy: strict-origin;
Feature-Policy sync-xhr 'self';
add_header Content-Security-Policy "default-src 'self'; connect-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' blob:; style-src 'self' 'unsafe-inline' data:; img-src 'self' 'unsafe-inline' data:; font-src 'self' 'unsafe-inline' data:; media-src 'self' 'unsafe-inline' data:";
Backward compatibility to Microsoft Internet Explorer 10:
add_header X-Content-Security-Policy "default-src 'self'; connect-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' blob:; style-src 'self' 'unsafe-inline' data:; img-src 'self' 'unsafe-inline' data:; font-src 'self' 'unsafe-inline' data:; media-src 'self' 'unsafe-inline' data:";
see also: Browser compatibility of HTTP headers
The proposed CSP is to be understood as a starting point. ILIAS is a generic software to support many different LMS scenarios and thus can't provide a suggestion which fits all circumstances and guarantees the best security. Depending on the content your users can provide (embedded media, SCORM packages, etc.) you should try to initially define a CSP which is as strict as possible.
You could use the Reporting Feature to log and analyse CSP violations to loosen the CSP gradually and carefully, if necessary.
A minimum endpoint to log the CSP violations could be:
<?php
declare(strict_types=1);
file_put_contents('csp.log', file_get_contents('php://input') . "\n", FILE_APPEND);
This is not a production ready solution, but a starting point to get an idea how to log the CSP violations.
Add the following line INSIDE the <VirtualHost></VirtualHost>
block:
<IfModule mod_headers.c>
Header set X-Content-Type-Options "nosniff"
Header set X-XSS-Protection "1; mode=block"
Header set X-Frame-Options "SAMEORIGIN;"
Header set Referrer-Policy "strict-origin"
Header set Feature-Policy "sync-xhr 'self'"
# Working with ILIAS in most use cases:
Header set Content-Security-Policy "default-src 'self'; connect-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' blob:; style-src 'self' 'unsafe-inline' data:; img-src 'self' 'unsafe-inline' data:; font-src 'self' 'unsafe-inline' data:; media-src 'self' 'unsafe-inline' data:"
# Working with ILIAS in most use cases:
Header set X-Content-Security-Policy "default-src 'self'; connect-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' blob:; style-src 'self' 'unsafe-inline' data:; img-src 'self' 'unsafe-inline' data:; font-src 'self' 'unsafe-inline' data:; media-src 'self' 'unsafe-inline' data:"
</IfModule>
You can simply add this in your server
configuration:
# Content-Security
add_header X-Frame-Options "SAMEORIGIN";
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
add_header Referrer-Policy "strict-origin";
add_header Feature-Policy "sync-xhr 'self';
# Working with ILIAS in most use cases:
add_header Content-Security-Policy "default-src 'self'; connect-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' blob:; style-src 'self' 'unsafe-inline' data:; img-src 'self' 'unsafe-inline' data:; font-src 'self' 'unsafe-inline' data:; media-src 'self' 'unsafe-inline' data:";
#compatibility to Microsoft Internet Explorer 10:
add_header X-Content-Security-Policy "default-src 'self'; connect-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' blob:; style-src 'self' 'unsafe-inline' data:; img-src 'self' 'unsafe-inline' data:; font-src 'self' 'unsafe-inline' data:; media-src 'self' 'unsafe-inline' data:";
note: If you use a proxied Chat Server, you MUST add the url to the CSP definition:
connect-src 'self' wss://onscreenchat.%HOSTNAME% https://onscreenchat.%HOSTNAME%;
If you use other external content (e.g. for a SCORM module or external video content) you have to add a default-src
(The default-src is the default policy for loading content such as JavaScript, Images, CSS, Fonts, AJAX requests, Frames, HTML5 Media from other sites):
e.g. for https://www.youtube.com as source:
default-src 'self' www.youtube.com; ...
It is recommended to validate your configuration with the services from https://securityheaders.com. Try to reach A grade.
The TLS/SSL extension OCSP stapling provides a way to improve the performance (as the webserver will fetch the OCS instead of the browser client) of SSL negotiation while maintaining visitor privacy. The Online Certificate Status Protocol (OCSP) is used for checking the revocation status of a SSL certificate (X.509 certificate). -> https://tools.ietf.org/html/rfc6066
By adding the following to your SSL VirtualHost configuration your webserver will do the check for you and send signatured information regarding to browser client
Add the following line INSIDE the <VirtualHost></VirtualHost>
block:
SSLUseStapling on
SSLStaplingResponderTimeout 5
SSLStaplingReturnResponderErrors off
Add the following line OUTSIDE the <VirtualHost></VirtualHost>
block:
SSLStaplingCache shmcb:/tmp/stapling_cache(128000)
ssl_stapling on;
ssl_stapling_verify on;
ssl_stapling_file ocsp_response;
ssl_trusted_certificate /path/to/cert_chain.pem;
resolver <IP DNS resolver>;
openssl s_client -connect %HOSTNAME%:443 -servername %HOSTNAME% -status < /dev/null 2>&1 | grep -i "OCSP response"
The expected output of a working OCSP configuration:
OCSP response:
OCSP Response Data:
OCSP Response Status: successful (0x0)
Response Type: Basic OCSP Response
The Qualys SSL Labs Tests will also show if your OCSP configuration is working:
OCSP stapling Yes
A word of warning here : This is a very effective, but also complex thing to do. It is recommended you do that - but you should totally know what you're doing. If not, please be aware that you may mess up your installation. If you have the slightest doubt you can pull this off, do yourself (and your users) a huge favor by trying this on an unimportant subdomain first. Really.
The HTTP Strict Transport Security (HSTS) header allows a host to enforce the use of HTTPS on the client side. The browser will be informed to use HTTPS. This protects e.g. from protocol downgrade attacks and cookie hijacking.
By adding the following to your SSL VirtualHost configuration you instruct browsers not to allow any connection to your ILIAS instance using HTTP and prevent visitors from bypassing invalid certificate warnings.
Ensure you have mod_headers.so
enabled in Apache2:
<IfModule mod_headers.c>
Header always set Strict-Transport-Security "max-age=15552000; includeSubDomains; preload"
</IfModule>
add_header Strict-Transport-Security "max-age=15552000; includeSubDomains" preload;
Warning: Before activating the configuration above you MUST make sure that you have a good workflow for maintaining your SSL settings (including certificate renewals) as you will not be able to disable HTTPS access to your site for up to 6 months.
Tip: When you test HSTS, use a very short max-age timeout
includeSubDomains: Restrictions also apply to all subdomains of the current domain.
max-age: Duration of cached information (180 days)
(The JF https://docu.ilias.de/goto.php?target=wiki_1357_JourFixe-2018-04-23 suggested to do this in webserver configuration.)
The browser will include the cookie in an HTTP request only if the request is transmitted over a secure channel (HTTPS). https://en.wikipedia.org/wiki/Secure_cookie
You have to add this to the apache2 configuration.
Header edit Set-Cookie ^(.*)$ $1;HttpOnly;Secure
note: Apache2 will use this for all cookie, who are beeing created.
You can simply add for example add_header Set-Cookie
in your server
configuration.
add_header Set-Cookie "ilClientId=%CLIENTID%; Path=/; Secure; HttpOnly";
note: For nginx, you have to generate a specific cookie for your ILIAS client. This will override the cookie delivered by ILIAS, so it is necessary to generate the whole cookie.
By default, web servers include sensitive server information in http headers and detailed PHP version information. It is recommended to suppress these header informations to prevent detection and exploit of version specific security issues of web server and PHP version.
- Module mod_headers is needed
<IfModule mod_headers.c>
Header unset Server
Header always unset Server
</IfModule>
- Module ngx_http_headers_module is needed
more_set_headers 'Server: ';
or better
more_clear_headers 'Server:*';
This can also be done by unsetting the header in webserver.
Header unset X-Powered-By
for Apache2 or rathermore_clear_headers 'X-Powered-By'
for NGINX.
The suggested solution is to set 'expose_php' to 'off' in your php.ini:
expose_php = Off
The access to the ILIAS Installation Wizard (/cli/setup.php)
MAY be restricted:
Apache2:
<Location /setup>
<IfVersion < 2.3>
Order Deny,Allow
Deny From All
Allow from %IPADDRESS%
</IfVersion>
<IfVersion > 2.3>
Require all denied
Require ip %IPADDRESS%
</IfVersion>
</Location>
Nginx:
location /setup {
allow %IPADDRESS%;
deny all;
# add location for PHP processing here
}
location /cli/setup.php {
allow %IPADDRESS%;
deny all;
}
Please add the whitelisted ip address (%IPADDRESS%) to grant access to ILIAS setup here.
If somebody tries to upload a file with a filetype blacklisted by the upload settings, the upload will take place, but the file will be renamed to filename.sec
. The webserver should not serve this file anymore to it's visitors as the file may consists of malicious software.
Apache2:
<FilesMatch "\.(sec)$">
Order Deny,Allow
Deny from All
</FilesMatch>
Nginx:
location ~ [^/]\.sec {
deny all;
}
There may be situations where there is no opportunity to disallow uploading php-files e.g. in Computer Science courses. In this case you SHOULD disallow these uploaded code to be executed by the webserver.
Apache2:
<LocationMatch "/data/.*(?i)\.(php)$">
Order Deny,Allow
Deny from All
</LocationMatch>
Nginx:
location ~* /data/.*\.php {
deny all;
}
If you installed ILIAS via git, access the local Git-Directory (.git) SHOULD be denied for visitors via web.
Apache2:
<Directorymatch "^/.*/\.git/">
Order deny,allow
Deny from all
</Directorymatch>
Nginx:
location /.git {
deny all;
}
Local changes of the code of ILIAS can indicate a potential intrusion.
To determine local changes of the code of ILIAS use git status
/ git diff
.
This will show you the uncommitted local changes.
(Beware: Committed local changes remain undetected using this method.)
(If you have conscious code local changes, this can lead to a false positive.)
In previous versions of ILIAS, it might have been possible to access SCORM, Media Files and User Profile Images without beeing logged in by guessing the proper URL and no measures were taken by the admin to deny such access. Since ILIAS 5.1, a new WebAccessChecker (WAC) is activated by default. To make use of WAC you MUST enable mod_rewrite
in your Apache configuration.
Please note that this will not work with Nginx as .htaccess-files
are not supported. Instead you MUST add the following to your Nginx configuration file (please note that running ILIAS with Nginx isn't officially supported and certain features like Shibboleth won't work):
This is a NGINX recommended configuration. (note: inside the %DOCROOT%/data
no PHP will be proceed)
server {
[...]
set $root $document_root;
location ~ /data/ {
rewrite ^/data/(.*)/(.*)/(.*)$ /wac.php last;
location ~ [^/]\.php(/|$) { access_log off; log_not_found off; deny all; }
}
location ^~ /secured-data {
# Protected, only working for subrequests (X-Accel-Redirect)
alias $root/data;
internal;
location ~ [^/]\.php(/|$) { access_log off; log_not_found off; deny all; }
}
[...]
}
ilFileDelivery (concerns NGINX/PHP-FPM):
This is needed if you want to use the ilFileDelivery::DELIVERY_METHOD_XACCEL or the ilFileDelivery::DELIVERY_METHOD_XSENDFILE Method since PHP can't figure out whether X-Accel ist installed or not.""
rename the file:
%DOCROOT%/Services/FileDelivery/classes/override.php.template
to
%DOCROOT%/Services/FileDelivery/classes/override.php
Please keep in mind, that your platform might me be accessible to the world wide web. To avoid unauthorized access to your Ilias-Installation, it his highly recommended to use secure passwords. Especially the root password and the Ilias-Master-Password are potentially endangered.
Your passwords should fulfil the following criterias:
- at least 8 characters in length
- lowercase and uppercase alphabetic characters [possible:
a-z
,A-Z
] - numbers [possible:
0-9
] - and symbols [possible:
_ . + ? # - * @ ! $ % ~ / : ;
] - do not consist of information that can easily be associated with the user
You MAY generate a password by using the pwgen-command on your webserver's cli
-B
: don't include ambiguous characters in the password;-y
: include at least one special symbol in the password
pwgen -By
If you think you found an security related issue in ILIAS please refer to http://www.ilias.de/docu/goto_docu_wiki_5307.html#ilPageTocA213 for reporting it.