PHP 服务器管理的 20 个关注点

PHP 是广泛使用的开源服务端脚本语言。通过 HTTP 或 HTTPS 协议,Apache Web/Nginx 服务允许用户访问文件或内容。服务端脚本语言的错误配置会导致各种问题。因此,PHP 应该小心使用。

以下是为系统管理员准备的,安全配置 PHP 的 25 个实践事例。

本文系统转载整理。由于收藏时忘记备注来源。如果,你知道本文出处请联系我修改。

用于下文的 PHP 设置样例

  • DocumentRoot:/var/www/html
  • 默认 Web 服务:Apache(可以使用LighttpdNginx 代替)
  • 默认 PHP 配置文件:/etc/php.ini
  • 默认PHP Extensions 配置目录:/etc/php.d/
  • PHP 安全配置样例文件:/etc/php.d/security.ini(需要使用文本编辑器创建这个文件)
  • 操作系统:RHEL / CentOS / Fedora Linux(指令应该可以在所有其他Linux发行版,如Debian / Ubuntu,或是 Unix-like 的操作系统,如OpenBSD / FreeBSD / HP-UX下正常运行)
  • PHP 服务的默认TCP/UDP 端口:none

下面列出的大部分操作,都是基于 root 用户能在 bash 或其他现代 shell 上执行操作的假设。

$ php -v

样例输出

PHP 7.2.11 (cli) (built: Oct 12 2018 15:32:50) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.2.0, Copyright (c) 1998-2018 Zend Technologies
    with Xdebug v2.6.1, Copyright (c) 2002-2018, by Derick Rethans

本文使用的操作系统

$ cat /etc/redhat-release

样例输出

Red Hat Enterprise Linux Server release 6.1 (Santiago)

1:知彼

基于 PHP 的应用面临着各种各样的攻击:

  • XSS:对 PHP 的 Web 应用而言,跨站脚本是一个易受攻击的点。攻击者可以利用它盗取用户信息。你可以配置 Apache,或是写更安全的 PHP 代码(验证所有用户输入)来防范 XSS 攻击。
  • SQL 注入:这是 PHP 应用中,数据库层的易受攻击点。防范方式同上。常用的方法是使用 PDO 预处理 SQL,把值当作参数处理。
  • 文件上传:它可以让访问者在服务器上放置(即上传)文件。这会造成例如:删除服务器文件、数据库,获取用户信息等一系列问题。你可以使用 PHP 来禁止文件上传,或编写更安全的代码(如检验用户输入,只允许上传 png、gif 这些图片格式)
  • 包含本地与远程文件:攻击者可以使远程服务器打开文件,运行任何PHP代码,然后上传或删除文件,安装后门。可以通过取消远程文件执行的设置来防范。
  • eval():这个函数可以使一段字符串如同PHP代码一样执行。它通常被攻击者用于在服务器上隐藏代码和工具。通过配置 PHP,取消 eval() 函数调用来实现。
  • Sea-surt Attack(Cross-site request forgery,CSRF。跨站请求伪造):这种攻击会使终端用户在当前账号下执行非指定行为。这会危害终端用户的数据与操作安全。如果目标终端用户的账号用于管理员权限,整个Web应用都会收到威胁。

2:减少内建的 PHP 模块

执行下面指令可以查看当前PHP所编译的模块:

$ php -m

样例输出:

[root@localhost ~]# php -m
[PHP Modules]
bcmath
Core
ctype
curl
date
dom
event
exif
filter
ftp
....

从性能与安全性的角度考虑,我建议使用 PHP 时减少不必要的模块。例如上面的 sqlite3 是不必要的。那么可以通过删除或重命名 /etc/php.d/sqlite3.ini 文件来取消它:

$ rm /etc/php.d/sqlite3.ini

mv /etc/php.d/sqlite3.ini /etc/php.d/sqlite3.disable

有些模块则只能通过使用重新编译安装 PHP 来移除。例如,从 php.net 下载 PHP 源码后,使用下面指令编译GD,fastcgi 和 MySQL 支持:

./configure --with-libdir=lib64 --with-gd --with-mysql --prefix=/usr --exec-prefix=/usr --bindir=/usr/bin --sbindir=/usr/sbin --sysconfdir=/etc --datadir=/usr/share --includedir=/usr/include --libexecdir=/usr/libexec --localstatedir=/var --sharedstatedir=/usr/com --mandir=/usr/share/man --infodir=/usr/share/info --cache-file=../config.cache --with-config-file-path=/etc --with-config-file-scan-dir=/etc/php.d  --enable-fastcgi --enable-force-cgi-redirect

更多信息请查看:http://php.net/manual/zh/install.unix.php

3:防止 PHP 信息泄漏

可以通过取消 expose_php,对 PHP 信息泄漏进行限制。编辑 /etc/php.d/security.ini 如下:

expose_php=Off

expose_php 会在 HTTP Header 中添加服务器上。包括版本在内的 PHP 信息(例如 X-Powered-By:

PHP/7.2.11)。同时,PHP 的全局统一标识符也会暴露。

4:最小化可载入的 PHP 模块(动态Extension)

PHP 支持 “Dynamic Extensions”。默认情况下,RHEL 会载入 /etc/php.d/ 目录下的所有 Extension 模块。如需启用或取消某一模块,只需把 /etc/php.d/ 目录下配置文件把该模块注释掉。也可以把文件删除或重命名该模块的配置文件。为了最优化 PHP 的性能和安全性,应只启用 Web 应用所需的 Extension。

5:记录所有 PHP 错误

不要把 PHP 错误信息输出给所用用户。编辑 /etc/php.d/security.ini,如下修改:

display_errors=Off

确保把所有错误信息记录到日志文件:

log_errors=On
error_log=/var/log/httpd/php_scripts_error.log

6:禁止文件上传

为安全考虑,如下编辑 /etc/php.d/security.ini 取消文件上传

file_uploads=Off

如用户的确需要上传文件,那么把它启用,而后限制 PHP 接受的最大文件大小:

file_uploads=On
upload_max_filesize=1M

7:关闭远程代码执行

如果这个特性被启动,PHP 可以通过 allow_url_fopen,在 file_get_contents()includerequire 中获取诸如 FTP 或网页内容这些远程数据。程序员经常忘记了对用户输入进行过滤,而如果这些函数调用了这些数据,则形成了注入漏洞。

在基于 PHP 的 Web 应用中,大量代码中的注入漏洞都由此产生。可以通过编辑 /etc/php.d/security.ini 来关闭该特性:

allow_url_fopen=Off

除此之外,建议把 allow_url_include 也取消掉:

allow_url_include=Off

8:控制 POST 的数据大小

HTTP POST 通常作为请求的一部分,被客户端用于向 Apache Web 服务器发送数据。如上传文件或提交表单。攻击者会尝试发送超大的 POST 请求去消耗服务器的资源。

如下编辑 /etc/php.d/security.ini 限制 POST 的最大大小:

在这里设置一个靠谱的数值:

post_max_size=1K

这里设置了 1K 的最大大小。这个设置会影响到文件上传。要上传大文件,这个值需要比 update_max_filesize 大。

9:资源控制(DoS 控制)

设置每个 PHP 脚本的最大运行时间。另外建议限制用于处理请求数据的最大时间,以及最大可用内存数。

单位:秒

max_execution_time = 30 # 脚本最大执行时间。
max_input_time = 30  # GET/POST/PUT 方式接收数据时间。
memory_limit = 40M # 脚本最大可用内存。

10:取消危险的 PHP 函数

PHP 有大量可用于入侵服务器的函数,如使用不当则会成为漏洞。如下取消这些函数:

disable_functions =exec,passthru,shell_exec,system,proc_open,popen,curl_exec,curl_multi_exec,parse_ini_file,show_source

11:PHP Fastcgi / CGI – cgi.force_redirect 管理

PHP 可与 FastCGI 协同工作。FastCGI 可以减少Web服务器的内存足迹(memory footprint),并改善 PHP 性能。可以参考这个来配置 Apache2+PHP+FastCGI。在这个配置中,cgi.force_redirect 会阻止用户通过访问 URL 来调用 PHP。

为安全考虑,启用该特性:

; Enable cgi.force_redirect for security reasons in a typical Apache+PHP-CGI/FastCGI setup  cgi.force_redirect=On

12:限制PHP访问文件系统

open_basedir 会限制 PHP 的运行目录,例如通过 fopen() 之类的函数可访问的目录。如果访问的目录不在open_basedir 之内,PHP 会拒绝该访问。不要使用软链接作为工作区。例如,只允许访问 /var/www/html 而非/var/www/tmp/etc 目录:

; open_basedir, if set, limits all file operations to the defined directory
; and below.  This directive makes most sense if used in a per-directory
; or per-virtualhost web server configuration file.
; http://php.net/open-basedir
open_basedir = "/var/www/html://var/www/data" 

13:Session 路径

PHP Session 用户提供数据保存功能,以便后续访问。这可以使应用可定制性更强,提升吸引力。所有 Session 相关的数据会被保存在 session.save_path 中。

只需要将 session 保存的目录不被 web 访问即可。如果可以的话,请将 session 保存到 Redis 这样的缓存系统中。

14:保证 PHP,软件及操作系统更新到最新

这个没啥好说的。但是,要注意代码与新版本的兼容性。

15:限制文件及目录访问

确认以 Apache 或 www 这种非 root 用户运行 Apache。/var/www/html 目录下的 owner 也应是非 root 用户:

# chown -R apache:apache /var/www/html/

DocumentRoot 下的文件应禁止运行或创建。设置该目录下的文件权限为0444(只读):

# chmod -R 0444 /var/www/html/

设置该目录下的所有文件夹权限为0445

# find /var/www/html/ -type d -print0 | xargs -0 -I {} chmod 0445 {}

16:Apache、PHP、MySQL配置文件的写入保护

使用 chattr 命令给这些配置文件加上写入保护:

同样可以为 /var/www/html 目录加上写入保护

# chattr +i /var/www/html/file1.php
# chattr +i /var/www/html/

17:使用Linux安全拓展(如SELinux)

Linux 有各种安全方案来防止服务程序的错误配置或漏洞。尽可能使用 SELinux 或其他 Linux 安全方案限制网络和程序。

例如,SELinux 为 Linux 内核或 Apache Web 服务提供不同的安全策略。使用下面命令列出所有Apache保护信息:

# getsebool -a | grep httpd

样例输出:

allow_httpd_anon_write --> off  allow_httpd_mod_auth_ntlm_winbind --> off  allow_httpd_mod_auth_pam --> off  allow_httpd_sys_script_anon_write --> off  httpd_builtin_scripting --> on  httpd_can_check_spam --> off  httpd_can_network_connect --> off  httpd_can_network_connect_cobbler --> off  httpd_can_network_connect_db --> off  httpd_can_network_memcache --> off  httpd_can_network_relay --> off  httpd_can_sendmail --> off  httpd_dbus_avahi --> on  httpd_enable_cgi --> on  httpd_enable_ftp_server --> off  httpd_enable_homedirs --> off  httpd_execmem --> off  httpd_read_user_content --> off  httpd_setrlimit --> off  httpd_ssi_exec --> off  httpd_tmp_exec --> off  httpd_tty_comm --> on  httpd_unified --> on  httpd_use_cifs --> off  httpd_use_gpg --> off  httpd_use_nfs --> off

取消 Apache cgi 支持可以输入:

# setsebool -P httpd_enable_cgi off

18:安装Mod_security

ModSecurity 是一个开源的入侵检测和防范的 Web 应用引擎。安装 mod_security 可以保护 Apache 和 PHP 应用免受 XSS 和其他攻击。

19:使用防火墙限制传出连接

攻击者会使用 wget 之类的工具从你的 Web 服务器下载文件。使用 iptables 来阻挡 Apache 用户的传出连接。ipt_owner 模块会为本地数据包的生成者分配不同角色。它只对 OUTPUT chain 有效。下面指令允许vivek用户通过80端口进行外部访问:

/sbin/iptables -A OUTPUT -o eth0 -m owner --uid-owner vivek -p tcp --dport 80 -m state --state NEW,ESTABLISHED  -j ACCEPT

下面的样例则是阻挡所有Apache用户的传出连接,只允许 smtp 服务及 spam 识别 API 服务通过:

20:查看并审查日志

查看 Apache 日志文件:

# tail -f /var/log/httpd/error_log  
# grep 'login.php' /var/log/httpd/error_log  
# egrep -i "denied|error|warn" /var/log/httpd/error_log

查看 PHP 日志文件:

# tail -f /var/log/httpd/php_scripts_error.log  
# grep "...etc/passwd" /var/log/httpd/php_scripts_error.log

查看日志文件可以让你知道服务器正在承受何种攻击,并分析当前安全级别是否足够。启用审查服务用于系统审查,可审查 SELinux 时间,验证事件,文件修改,账号修改等。建议使用 Linux System Monitoring Tools 来监控Web服务器。

关于 PHP 服务器管理的实践还有很多。虽然我们保持对 PHP 安全的持续关注。

博主 2011 年创建了一个《PHP 初学者官方群》,目前群成员 500 人左右。群号:168159147。为了防止广告,设置为付费入群。欢迎大家加入讨论技术!

标签: 无

发表评论: