Hello PHP devs. In this post, I'll try and provide you with some concrete steps you can make to improve the security of your PHP app. I'm focusing on the PHP configuration itself, so we won't talk about SQL injections, HTTPS or other non PHP related issues.
I'll illustrate examples with bash lines from my
docker-entrypoint.sh script, but of course you can apply it to a non docker environment.
Increasing the session id length will make it harder for an attacker to guess it (via bruteforce or more likely side-channel attacks). Session ID length can be between 22 to 256 characters. The default is 32.
sed -i -e "s/session.sid_length = 26/session.sid_length = 42/" /etc/php7/php.ini
(don't ask me why it's 26 on Alpine Linux...)
You might also want to look at session.sid_bits_per_character.
Only nginx/php needs to access the sessions, so let's put them in a special folder with restrictive permissions.
sed -i -e "s:;session.save_path = \"/tmp\":session.save_path = \"/sessions\":" /etc/php7/php.ini mkdir -p /sessions chown nginx:nginx /sessions chmod 700 /sessions
Of course, if you use Redis to handle sessions, you don't care about this part ;)
sed -i -e "s/session.cookie_httponly.*/session.cookie_httponly = true/" /etc/php7/php.ini sed -i -e "s/;session.cookie_secure.*/session.cookie_secure = true/" /etc/php7/php.ini
session.cookie_secure to prevent your cookie traveling on cleartext HTTP.
session.cookie_samesite to prevent Cross-Site attacks. Only for recent PHP/browsers.
Sessions should close with the browser. So set session.cookie_lifetime to 0.
open_basedir is a
php.ini config option that allows you to restrict the files/directories that can be accessed by PHP.
sed -i -e "s#;open_basedir =#open_basedir = /elabftw/:/tmp/:/usr/bin/unzip#" /etc/php7/php.ini
Here I have added unzip as it is used by composer.
/elabftw is where all the source php files are located. And I don't remember why
/tmp is here but there is surely a reason.
Be careful with this, as you can very easily mess up an app. But this is definitely something to look into. Let's say an attacker somehow managed to upload a webshell, with this correctly in place, the webshell won't really work as
shell_exec and friends will be disabled. I'm providing a list that works for elabftw but it's not 100% complete.
sed -i -e "s/disable_functions =/disable_functions = php_uname, getmyuid, getmypid, passthru, leak, listen, diskfreespace, tmpfile, link, ignore_user_abort, shell_exec, dl, system, highlight_file, source, show_source, fpaththru, virtual, posix_ctermid, posix_getcwd, posix_getegid, posix_geteuid, posix_getgid, posix_getgrgid, posix_getgrnam, posix_getgroups, posix_getlogin, posix_getpgid, posix_getpgrp, posix_getpid, posix_getppid, posix_getpwnam, posix_getpwuid, posix_getrlimit, posix_getsid, posix_getuid, posix_isatty, posix_kill, posix_mkfifo, posix_setegid, posix_seteuid, posix_setgid, posix_setpgid, posix_setsid, posix_setuid, posix_times, posix_ttyname, posix_uname, phpinfo/" /etc/php7/php.ini
sed -i -e "s/allow_url_fopen = On/allow_url_fopen = Off/" /etc/php7/php.ini
You don't want to allow non PHP files to be executed as PHP files, right? Then disable this. More info.
sed -i -e "s/;cgi.fix_pathinfo=1/cgi.fix_pathinfo=0/g" /etc/php7/php.ini
To finish, a nobrainer:
sed -i -e "s/expose_php = On/expose_php = Off/g" /etc/php7/php.ini
That's it for now. I hope you'll find this post useful and improve your configurations ;)
Let me know in the comments if I've missed something important!