Home | 简体中文 | 繁体中文 | 杂文 | 知乎专栏 | Github | OSChina 博客 | 云社区 | 云栖社区 | Facebook | Linkedin | 视频教程 | 打赏(Donations) | About
知乎专栏多维度架构 微信号 netkiller-ebook | QQ群:128659835 请注明“读者”

第 7 章 PHP 安全与性能优化

目录

7.1. Apache mod_php / php-fpm
7.1.1. 用户权限
7.1.1.1. Apache
7.1.1.2. Nginx / lighttpd + fastcgi
7.1.2. web server 版本信息
7.1.3. php_flag / php_admin_flag
7.1.4. 防止URL注入
7.2. php.ini
7.2.1. Magic quotes
7.2.2. 危险PHP函数
7.2.2.1. chdir()函数安全演示
7.2.3. 隐藏PHP版本信息
7.2.4. session名字可以泄露你的服务器采用php技术
7.2.5. 隐藏PHP出错信息
7.2.6. open_basedir 防止操作web环境意外文件目录
7.3. 开发于安全
7.3.1. 彻底解决目录于文件的安全
7.3.2. Session / Cookie安全
7.3.3. 注入安全
7.3.3.1. 禁止输出调试信息
7.3.3.2. 预防SQL注入攻击
7.3.3.3. SHELL 命令注入
7.4. 执行效率
7.4.1. timeout
7.4.1.1. mysql
7.4.2. 浏览器上传文件尺寸控制

7.1. Apache mod_php / php-fpm

目录权限安全

7.1.1. 用户权限

web server 启动用户不能于运行用户为同一个用户

web server 运行用户与php程序不能为同一个用户

root      1082  0.0  0.1  11484  2236 ?        Ss   Mar01   0:00 nginx: master process /usr/sbin/nginx
www-data 13650  0.0  0.0  11624  1648 ?        S    09:44   0:00 nginx: worker process
www-data 13651  0.0  0.0  11624  1132 ?        S    09:44   0:00 nginx: worker process
www-data 13652  0.0  0.0  11624  1132 ?        S    09:44   0:00 nginx: worker process
www-data 13653  0.0  0.0  11624  1132 ?        S    09:44   0:00 nginx: worker process
			
  1. 父进程

    root 启动 web server, 此时web server 父进程应该是 root,同时父进程监听80端口

  2. 子进程

    父进程派生许多子进程,同时使用setuid,setgid将子进程权限切换为非root

    子进程用户可以通过httpd.conf设置

    User nobody
    Group nobody
    					

    nginx.conf

    $ cat /etc/nginx/nginx.conf
    user www-data;
    					
  3. fastcgi 进程

    root     13082  0.0  0.1  19880  2584 ?        Ss   09:28   0:00 php-fpm: master process (/etc/php5/fpm/php-fpm.conf)
    www-data 13083  0.0  0.1  20168  3612 ?        S    09:28   0:00 php-fpm: pool www
    www-data 13084  0.0  0.1  20168  2808 ?        S    09:28   0:00 php-fpm: pool www
    www-data 13085  0.0  0.1  20168  2812 ?        S    09:28   0:00 php-fpm: pool www
    www-data 13086  0.0  0.1  20168  2812 ?        S    09:28   0:00 php-fpm: pool www
    					

    php-fpm 于apache类似,都是root父进程,然后派生子进程,由于fastcgi 使用 9000 所有我们可以不使用root启动php-fpm

现在我们开始讲解安全配置问题

我们目的是避免用户通过漏洞提升权限,或者由于权限配置不当产生漏洞

7.1.1.1. Apache

Apache 案例

  1. Apache : root

  2. Apache 子进程 : nobody

  3. HTDOCS 目录 : /var/www

    /var/www
    |--include
    |--image
    |--temp
    |--...
    						

很多人会将/var/www用户与组设置为 nobody:nogroup / nobody:nobody, 同时因为images会上传文件需要设置777, 很多书本于教程上面也是这样讲的, 这样配置会有什么问题呢?我们来分析一下:

我们假设,一个用户上传一个文件到images目录,会有几种情况:

  1. 上传一个.php文件,我们可以通过程序禁止上传.php文件

  2. 我们上传一个.jpg文件,OK 通过了,通过某种手段将他重命名位.php扩展名的文件,然后通过http://www.example.com/images/your.php 运行它,your.php 可以做什么呢? 它可以查看所有文件,修改所有文件,创建其他php文件,去你可include目录下看config.php然后下载数据库。

  3. 内部开发人员偷偷将一个程序植入到系统中,这个做code review 可以避免

如何避免这样问题出现,有一个办法,我们新建一个用户www, webserver 进程是nobody,程序目录/var/www中的代码是www用户,nobody可能读取但不能修改。/var/www/images 目录所有者是nobody可以上传图片

				
chown www /var/www/
chown nobody /var/www/images
find /var/www/ -type d -exec chmod 555 {} \;
find /var/www/ -type f -exec chmod 444 {} \;
chmod 755 /var/www/images
				
				

使所有可能目录允许运行.php文件,http://www.example.com/images/your.php 将被拒绝. include 也是同样处理方式,只允许使用include_once,require_one 包含,不允许http://www.example.com/include/your.php运行

				
<Location ~ "/((js/)|(css/)|(images/)).*\.php">
	Order Deny,Allow
	Deny from all
</Location>

<Location /includes/>
        Order allow,deny
        Deny from all
</Location>
<Location /library/>
        Order allow,deny
        Deny from all
</Location>

<Directory /var/www/themes/>
    <Files *.php>
		Order allow,deny
		Deny from all
    </Files>
</Directory>
				
				

7.1.1.2. Nginx / lighttpd + fastcgi

Nginx / lighttpd 案例分析

  1. nginx / lighttpd : root

  2. web server 子进程 : nobody

  3. php-fpm : root

  4. php-fpm 子进程 : nobody

  5. HTDOCS 目录 : /var/www

    /var/www
    |--include
    |--image
    |--temp
    |--...
    						

fastcgi 遇到的问题与上面apache案例中遇到的问题类似,不同是的fastcgi把动态于静态完全分开了,这样更容易管理,我们可以这样入手

  1. nginx / lighttpd : root

  2. web server 子进程 : nobody

  3. php-fpm : root

  4. php-fpm 子进程 : www

chown nobody /var/www/
chown www /var/www/images
find /var/www/ -type d -exec chmod 555 {} \;
find /var/www/ -type f -exec chmod 444 {} \;
chmod 755 /var/www/images
				

/var/www所有权限给nobody, images权限给www, 同时保证www用户可以读取/var/www下的程序文件

location ~ ^/upload/.*\.php$
{
        deny all;
}

location ~ ^/static/images/.*\.php$
{
        deny all;
}

location ~ /include/.*\.php$ {
    deny all;
}

location ~ .*\.(sqlite|sq3)$ {
    deny all;
}

				
vim /etc/php5/fpm/pool.d/www.conf

user = www
group = www
				

/etc/php5/fpm/pool.d/www.conf

chdir = /
改为
chdir = /var/www
				

chroot可以彻底解决cd跳转问题,单配置比较繁琐

chroot = /var/www
				

这样当用户试图通过chdir跳转到/var/www以外的目录是,将被拒绝

7.1.2. web server 版本信息

Apache:
ServerTokens ProductOnly
ServerSignature Off

Nginx:
server_tokens off;
			

7.1.3. php_flag / php_admin_flag

你在php.ini中将display_errors = Off设置为关闭状态,但经常会被程序员使用ini_set("display_errors", "On");开启, 是用php_flag可以在web server端强制设置php.ini参数

php_flag register_globals off
php_flag magic_quotes_gpc off
			

php_admin_value(php_admin_flag) 与 php_value(php_flag) 有何不同?

不同的地方是:php_admin_value(php_admin_flag) 命令只能用在apache的httpd.conf文件中, 而php_value(php_flag)则是用在.htacces

在.htaccess中停用全局变量

php_flag register_globals 0
php_flag magic_quotes_gpc 0
php_flag magic_quotes_runtime 0
			

7.1.4. 防止URL注入

			
if ($request_uri ~* (.*)(insert|select|delete|update|count|concat|cost|union|drop|table|*|%|master|truncate|declare|'|;|and|or|(|)|exec)(.*)$ ) 
{ 
	return 403; 
}
if ( $query_string ~* ".*[;'<>].*" ){
	return 403;
}