本文档的目标是协助编写安全的 PHP 代码,降低出现 Web 漏洞的风险。
虽然本文档是针对 PHP 设计的,但是在使用 Python、ASP.NET、Java 等语言开发 Web 后台时,也可适当参考本文档的约定。
数据库操作推荐使用国外成熟框架,如 Laravel、CodeIgniter 、YII 等。通过 PDO 预编译 SQL 语句也是一个好办法。
当必须使用 SQL 语句拼接时,使用 intval/floatval 对数值型参数过滤,使用 mysql_real_escape_string 对字符串型参数进行过滤,
对于数值型和字符串型参数都需要用 ' 包裹进行保护。
使用 mysql_set_charset 设置当前数据库字符集与前端页面字符集一致,建议全部字符集统一为 UTF-8。
对于将要输出在前端页面的变量,必须使用 htmlspecialchars 进行过滤。
攻击者可能会构造 伪协议 实施攻击:
<a href="javascript:alert(1);">test</a>还可以使用 dataURL、vbscript 等伪协议:
<a href="data:text/html;base64,PHNjcmlwdD5hbGVydCgxKTs8L3NjcmlwdD4=">test</a>上面这段代码是指用 test/html 的格式加载编码为 base64 的数据,加载完成后实际上是:
<script>alert(1);</script>或者通过 闭合引号 引入 事件:
<a href="x" onclick="alert(1)">test</a>**解决方法:**检查变量是否以 http 开头,再对变量进行 urlencode。
攻击者会尝试使用 ../../etc/passwd 之类的系统 file 路径寻找文件包含或者任意下载漏洞。
open_basedir 可以用来限制 PHP 可读写的文件目录。
黑名单检测往往容易被绕过,应使用 strrpos 来截取后缀名判断其是否在白名单中。
$allowedType = array('jpg', 'gif', 'bmp', 'png', 'jpeg');
$extpos = strrpos($fileName, '.');
$ext = substr($filename, $extpos + 1);
if(!in_array($ext, $allowedType)){
return false;
}如果不能重命名文件,应该对文件名进行 过滤,过滤方法请参考上文。
尽量对文件重命名,并且不要返回给用户重命名后的文件名。
建议使用 日期 + 随机字符串 的形式重命名文件。
万一上传被突破,取消执行权限 可以防止恶意脚本的执行。
旧版本的 Web Server 如 IIS 6 、Nginx 0.8 等存在高危解析漏洞,应及时升级 Web Server 并按时打补丁。
检查 HTTP 请求头中的 Referer 是否来源于本域名。
在每个表单中增加一个 一次性 且 随机 的 token 隐藏字段,提交时与用户 session 中的 token 进行比对。
对于每个变量应尽可能初始化,在 php.ini 中关闭全局变量注册 register_global=Off。
避免使用 eval、system 等调用系统命令的函数。
https://www.owasp.org/index.php/PHP_Security_Cheat_Sheet PHP_Security_Cheat_Sheet
http://drops.wooyun.org/papers/4544 论PHP常见的漏洞
http://drops.wooyun.org/papers/155 CSRF简单介绍及利用方法
http://zone.wooyun.org/content/1910 PHP上传绕过及缺陷经验解说
http://zone.wooyun.org/content/1872 PHP变量覆盖经验解说