php安全之我见
1.把握整站的结构,避免泄露站点敏感目录
问题:老网站一般在跟目录下放上index.php、register.php、login.php,访问注册页面跳转到http://localhost/register.php,不易扩展和维护
解决: 如果url为http://localhost/act=register这种,通过变量来跳转到相应页面便于管理,dvwa靶机环境用的就是种搭建的思想
优点:1.不会暴露网站后台绝对路径http://localhost/act=admin.php推测不出网站的后台目录
2.易维护,不需修改太多代码,http://localhost/act=admin.php想修改后台地址,只需修改swtich的代码和后台文件名
3.结构严谨,有层次感
4.统一管理身份认证。可在在入口处进行身份认证,如游客不可访问网站,只有登录会员才有权限浏览,可在入口页面管理
5.通过绝对路径访问页面报错, http://localhost/register.php报错
在页面添加<?php if(!defined('WWW_ROOT')) {header("HTTP/1.1 404 Not Found"); exit;} ?>实现
2.使用预编译语句,避免sql注入
2.1.数据与代码未区分
一条sql语句select * from admin where username='admin' password='xxxxx',admin和xxxx是数据,如未做处理,用户可以输入admin=' or 1=1 #,这条语句变成select * from admin where username='' or 1=1 #' password='xxxxx' ,#将后面的代码注释掉,username=''为假,1=1为真,所以最终结果为真,将所有数据都查询出来
2.2 预编译
后端SQL语句:select * from admin where username='?' password='?',将这条sql语句编译成stmt对象中,方法stmt->bind_param将用户输入的数据绑定到?的位置,这样通过类来操作,所以sql语句的执行都要进行预编译。
Mysqli的预处理
1.创建连接
$conn = new mysqli($servername, $username, $password, $dbname);
2.预处理,也就是封装成stmt类
$stmt = $conn->prepare("INSERT INTO MyGuests (firstname, lastname, email) VALUES (?, ?, ?)");
3.绑定参数
$stmt->bind_param("sss", $firstname, $lastname, $email);
4.设置参数值
$firstname=’firstname’
5.执行
$stmt->execute();
不过现在php常用pdo来进行sql操作
1.pdo实例化
$conn = new PDO("mysql:host=$servername;dbname=$dbname", $username, $password);
2.预处理
$stmt = $conn->prepare("INSERT INTO MyGuests (firstname, lastname, email) VALUES (:firstname, :lastname, :email)");
3.绑定参数
$stmt->bindParam(':firstname', $firstname);
$stmt->bindParam(':lastname', $lastname);
$stmt->bindParam(':email', $email);
4.赋值及执行
$firstname = "John";
$lastname = "Doe";
$email = "john@example.com";
$stmt->execute();
3预防XSS代码,如果不需要使用cookie就不使用
不幸被xss注入,页面不使用cookie,可降低危害
4. 限制用户权限,预防CSRF
4.1举一个例子,给某篇文章点赞,一开始设计的是get请求的方式,如A用户点赞某篇文章的url请求是
http://localhost/?act=support&articleid=12,A用户可以将这个请求发送给B用户,B用户点击此链接也发起了一个点赞的请求
4.2post请求。Get请求太容易利用,如是设计成post来发起这个点赞的请求,如以下代码:
<form action="http://localhost/?act=support" method="POST">
<input type="hidden" value="12" name="articleid">
<input type="submit" value="赞">
</form>
第一个input中出现了文章的id,可以构造form表格,或ajax,或利用burpsuite构造攻击页面,发送给B,B点击发起了点赞的post请求
4.3验证码来限制。这样会降低用户体验感,现实中也未见点个赞还需要输入验证码的情形。
4.4增加token验证。客户端每次访问http://localhost/?act=support&articleid=12页面时,服务器都会随机生成一个token,并发送给客户端,客户端点赞时发送这个参数和服务端比较,如果一样点赞成功,这里如果页面存在xss的漏洞,可以通过js获取到token值,成功发起攻击,这种方式是目前常用且有效的手段
4.5 referer验证。访问http://localhost/?act=support&articleid=12点赞时,验证请求包中的rerferer值,来验证其页面来源,理想情况下,当A用户将攻击页面发给B,B点击,referer来源肯定不一致导致点赞失效,但是攻击者可以修改攻击页面的网站名,文件名,目录名为点赞域名以混过rerferer检测
5严格控制上传文件类型
5.1前端验证不可靠的
5.2mime验证不可靠的
5.3白名单验证,就是取文件名, 如array('jpg','gif','png','bmp'),文件名为数组中的元素才可上传,但是要注意解析漏洞
5.4 重命名,现在一般命名规则为日期时间+随机数+白名单后缀对上传的文件进行重命名,这样就算被上传webshell,也因为攻击者无法猜测出文件名而导致无法访问webshell
5.5禁止php代码的执行,可以参考文章webshell禁止你执行
6.加密混淆javascript代码,提高攻击门槛
很多xss漏洞都是在本地阅读网页源码发现的,加密javascript代码提高阅读门槛
7. 使用更高级的hash算法保存数据库中重要信息
目前一般破解hash的手段
7.1彩虹表。可以去官网下载,几百g,经常那这个去破解系统的sam文件
7.2 md5网站,百度一下就有,解密简单的
8.验证码安全
验证验证码是否安全可以通过一下几个方式:
8.1 验证码是否前端生成,可抓包绕过
8.2 单个验证码是否有有效期,单个验证码可重复使用
8.3 验证码内容输出到客户端,攻击者可通过js代码获取到
8.4 验证码太弱
验证码太简单,导致开源的tessertact OCR就可以识别。这里有一个最新机器识别绕过12306
火车票验证码的实例
参考链接:https://www.leavesongs.com/PENETRATION/php-secure.html