总有一些人,热衷于窃取他人的劳动果实。比如好事者用一个空头域名指向你的主机,从而利用你的网站内容提升他自己的域名排名。比如我就发现有两个空头域名sunrisenet.cn、mbagroup.cn指向了我的网站,我们该如何防止这种情况发生呢?

方法1:将来自其他域名的访问导向自己的域名

 server {
     listen 80 default;
     server_name _;
     rewrite ^(.*) http://www.xuanhao360.com;
 }
 server {
     listen 80;
     server_name  www.xuanhao360.com;
     root /var/www;
     index  index.html;
     ......
 }

方法2:对来自其他域名的访问返回500错误

server {
        listen 80 default;
        server_name _;
        return 500;
}
 server {
     listen 80;
     server_name  www.xuanhao360.com;
     root /var/www;
     index  index.html;
     ......
 }

方法3:黑名单

 server {
     listen 80 default;
     server_name sunrisenet.cn;
     return 500;
 }
 server {
     listen 80;
     server_name  www.xuanhao360.com;
     root /var/www;
     index  index.html;
     ......
 }

php是一门极其灵活的编程语言,它是高效开发web程序的最佳选择之一。但是灵活性往往带来安全性问题,这就需要我们工程师时刻审视自己的代码安全性。下面列举一些经常容易出现安全性问题的场景极其解决方案。

对于php的安全防患,是有一些基本原则的:

1.不信任任何从客户端传入的数据,如$SERVER,$_GET,$_POST,$_COOKIE,$FILES,$ENV,$REQUEST等。

2.最小化原则,将用户输入的数据的范围限制到最小化

3.安全的代码不依赖任何安全配置,不能寄希望与php.ini的安全性配置

4.程序的错误信息对外界屏蔽,程序的错误信息会给攻击者带来极大帮助

本文列举了数据库操作场景、文件操作场景、命令执行场景下容易出现的安全问题以及应对方案。

1 数据库操作场景

1.1 字符串变量注入

比如如下php代码:。

$user = $_POST['uesr'];
$password = $_POST['password'];
$query="select * from user where name = '$user' and password = '$password'";
$result=$mysqli->query($query);

这段代码没有对不可信输入做检查,当$_POST['user'] = "' OR '' = '"$_POST['password'] = "' OR '' = '",实际的sql为:select * from user where name = '' OR '' = '' and password = '' OR '' = '',这样的sql就可能将所有的数据库中用户信息泄露。

1.2 整形注入

比如如下php代码:。

$user = $_POST['id'];
$query="select * from user where id = $id";
$result=$mysqli->query($query);

这段代码没有对不可信输入做检查,当$_POST['id'] = "1 OR '' = ''",实际的sql为:select * from user where id = 1 OR '' = '',这样的sql就可能将所有的数据库中用户信息泄露。

安全编码建议:以上情况都是要使用客户端传来的参数,因此必须严格检查。对于字符串型变量最好使用mysql_real_escape_string进行过滤,而对于整形变量必须使用intval来保证类型。


2 文件操作场景

2.1 文件名安全问题

如下php代码段:

$file = $_GET['file'];
if(!empty($file)){
    include_once($file);
}

include,include_once,require,requre_once这些函数的本质是载入php文件并执行,因此使用这些函数时务必非常小心。这段代码非常不安全,比如$_GET['file']="../../../../../../../../etc/passwd%00.php"时,将会打开敏感文件/etc/passwd,因为%00\0url编码后的值,对于操作系统而言相当于字符串的结束符。

2.2 文件读写安全问题

如下php代码段:

$filename="test1.txt";
$file_info="user input:\n";
$file_info.= "$conent";
file_put_conent($filename,$conent);

$conent="eval($php_code)"时,会执行代码中的php_code,理论上攻击者可以运行任何php代码。这段代码主要问题在于用双引号包含用户提交的文件内容。

安全编码建议:将输出到文件的数据放到单引号中而非双引号。在php中表示一个字符串的方法有三种:单引号、双引号、定界符,和其他两种语法不同,单引号字符串中出现的变量和转义序列不会被变量的值替代。无论从效率还是安全性方面,都强烈推荐使用单引号。


3 命令行操作场景

如下php代码段:

uri = $request['uri'];
$from = $request['from'];
$to   = $request['to'];
$tmp = '/tmp/act_css_tmp_' . $uri;  
system("/usr/bin/wget $from -O $tmp");

$request变量来自于用户URL的输入,最终进入到system函数里作为命令来执行,但是这段代码没有安全处理用户的输入,任意用户都可以通过如下URL来在机上执行自己的命令, php?cmd=1190&func=sync_css&uri=hi&from=;cat /etc/passwd;&to=hi&1=2 最后导致系统的沦陷。

安全编码建议我们应该尽量避免使用systemexecpopenpassthru, 反引号(``)......等直接执行系统命令的函数如果必须使用这些函数的时候我们就需要在用户的参数进入system函数之前经过过滤。Php提供两个作为命令安全输入的函数一个是escapeshellarg一个是escapeshellcmd。


4.安全配置

register_globals = Off   

register_globals允许php将$_GET和$_POST,$_COOKIE等变量里的内容自动注册为全局变量,如果程序里的某些变量没有经过初始化而直接使用将导致安全问题。

isplay_errors = Off, log_errors = On 

如果脚本运行时出错,错误信息将提供非常多的信息给黑客,里面可能包含了web路径,一些调试信息甚至是部分的php代码。我们应该强制在线上业务关闭错误信息对外的显示该选项。并将error_log 指定为我们自定义的错误路径。

expose_php = Off

防止php在http头输出中加入版本信息防止恶意攻击者从中获取敏感信息强制执行将此选项为off。

 allow_url_include = Off

防止php将远程资源作为php源文件执行。从而从一定程度上防范文件包含漏洞。强制执行此选项为off。

max_input_vars = 1000 

设置用户输入生成的最大变量值。防止利用大量无用变量造成php程序hashtable冲突导致占用大量系统资源。建议执行为默认1000个值。