本篇利用3个实例 来引出前端验证的逻辑漏洞
一、文件上传
实例:利用JS实现
【1】代码实现
js:文件后缀筛选
php:文件保存
00x1 先利用js文件上传
就利用之前php原生写的upload.html的模板,再加上script的后缀过滤。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>文件上传页面</title>
<style>
body {
font-family: Arial, sans-serif;
background-color: #f2f2f2;
padding: 20px;
}
h1 {
text-align: center;
margin-top: 50px;
}
form {
background-color: #fff;
border-radius: 10px;
padding: 20px;
margin-top: 30px;
max-width: 600px;
margin: 0 auto;
}
input[type="file"] {
margin-top: 20px;
margin-bottom: 20px;
}
button {
background-color: #4CAF50;
color: #fff;
padding: 10px 20px;
border: none;
border-radius: 5px;
cursor: pointer;
}
button:hover {
background-color: #3e8e41;
}
</style>
</head>
<body>
<h1>文件上传</h1>
<form action="upload.php" method="POST" enctype="multipart/form-data">
<label for="file">选择文件:</label>
<br>
<!-- CheckFileExt当用户选择文件时触发验证函数 this.value获取完整文件名-->
<input type="file" id="file" name="f" onchange="CheckFileExt(this.value)">
<br>
<button type="submit">上传文件</button>
</form>
<script>
function CheckFileExt(filename){
var flag=false;
//规定白名单上传后缀
var exts=['png','gif','jpg'];
//1.php 1.php.jpg 接受传递的后缀名
var index=filename.lastIndexOf("."); <!-- 查找最后一个点号位置 取.及后面为后缀-->
var ext = filename.substr(index+1); <!-- index+1是把点号去除掉-->
//进行后缀检测
for(i=0;i<exts.length;i++){
if(ext==exts[i]){
var flag=true;
alert('文件后缀正确!');
break;
}
}
if(!flag){
alert('文件后缀错误!')
location.reload(true);
}
}
</script>
</body>
</html>
00x2 php实现文件存储
之前写原生php文件上传时候的代码拿来复用。
创建一个upload文件夹
<?php
// 从前端表单提取出来的信息,利用全局变量进行提出
$name=$_FILES['f']['name'];
$type=$_FILES['f']['type'];
$size=$_FILES['f']['size'];
$tmp_name=$_FILES['f']['tmp_name'];
$error=$_FILES['f']['error'];
if(move_uploaded_file($tmp_name, 'upload/' . $name)){
echo '<script>alert("上传成功!")</script>';
}
查看结果,也是将上传内容成功实现存储。
【2】利用JS前端验证衍生的安全问题
1)过滤代码能被看到 进行代码审计白盒绕过
js属于前端语言,意味着我们刚刚做的过滤限制是可以在前端被看到的,更进一步说明了用户可以白盒我们的页面,去进行过滤绕过。
2)可通过禁用JS / 删除过滤代码绕过
法1: 禁用JS
浏览器中可以直接禁止js
【后续也要讲js的调试,很重要】
法2: 删除过滤代码
漏洞复现:
step1、将前端源码复制到本地
step2、将源码中与过滤相关的函数 / 操作删除
step3、将新构建的前端页面的路径替换成实际可以上传到的路径
step4、验证
保存后将新构建的前端直接拖入浏览器,进行上传,上传在白名单之外的文件类型,查看是否成功(有js框提示上传成功 & upload文件夹里确实传入了非白名单类型的文件)
二、登录页面
实例1:利用JS实现登录页面
【1】代码实现
逻辑:首先借用之前我们原生php开发时候的优雅的html前端页面 ---> 然后进行js的代码编写,利用ajax将用户输入数据传递给后端进行验证的php文件 ---> 后端php写一个从数据库里提取用户信息并与接收到的进行对比的逻辑 (若有信息,则跳转index首页 ;若无信息,无操作)
00x1 先利用js实现前端页面
00x2 php进行用户信息后端验证
实际情况应该是连接数据库,在库中存储的数据与用户提交的数据进行对比,我这里写死给了一个用户信息。再简单的给一个首页文件
<?php
header('Content-Type: application/json'); // 明确声明返回JSON
$user=$_POST['myuser'];
$pass=$_POST['mypass'];
//真实情况需要在数据库获取
$success=array('msg'=>'ok');
if($user=='xiaodi' && $pass=='123456'){
$success['infoCode']=1;
}else{
$success['infoCode']=0;
}
echo json_encode($success);
<?php
echo '欢迎您成功进入到首页!';
?>
测试回显:
正确
错误
【2】写法中的安全问题 ---存在逻辑漏洞
漏洞原理:我们刚刚是将跳转写在了前端,意思是我们可以在前端获取到由后端php验证返回的json数据包,是这样的结构:{msg: 'ok', infoCode: 1 / 0},所以我们可以先输入正确的一个账密(字典爆破 / 暴力破解 ),拿到了账密正确返回的json数据包,bp抓一个任意用户的包,将json包改为可以正确登录的包,就可以实现任意用户登录。
00x1 输入正确的账密 拿到正确登录的json包
{msg: 'ok', infoCode: 1}
00x2 输入错误的登录信息
00x3 进行bp抓包拦截
抓到有响应包,将正确的替换错误json包
{msg: 'ok', infoCode: 1}
放行,看login.html的回显
【3】如何防止这种安全问题
我们刚刚在前端js中,确认code值为1后直接进行了跳转首页的操作,这个就是我们刚刚复现逻辑漏洞的主要原因,那么我们将跳转放到后端php文件中(服务器中),就算被替换了json数据包的值,但是真正的验证跳转是在服务器中,前端code为1没用只提示登陆成功但是没有任何操作,得是服务器中code值为1才会跳转。
没有跳转,也就不会触发任意用户登录。
三、购物商城
1、代码实现
思路:先构建一个前端页面,ajax去后端php文件进行逻辑判断,但是还是在前端按照infocode值去决定购买成功(1)与失败(0)
前端:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>商品购买</title>
</head>
<body>
<img src="iphone.png" width="300" height="300" alt=""><br>
金钱:10000<br>
商品价格:8888<br>
数量:<input type="text" name="number" class="number">
<button>购买</button>
</body>
</html>
<script src="js/jquery-1.12.4.js"></script>
<script>
$("button").click(function (){
$.ajax({
type: 'POST',
url: 'shop.php',
data: {
num:$('.number').val(),
},
success: function (res){
console.log(res);
if(res['infoCode']==1){
alert('购买成功');
//购买成功的流程
}else{
alert('购买失败');
}
},
dataType: 'json',
});
});
</script>
后端:
<?php
$num = $_POST['num']; // 将前端的num以遍历num接收
//真实情况需要在数据库获取
$success = array('msg' => 'ok');
if (10000>=($num*8888)) { // 进行总价与1w对比
$success['infoCode'] = 1;
} else {
$success['infoCode'] = 0;
}
echo json_encode($success);
验证:
2、逻辑漏洞利用
{msg: 'ok', infoCode: 1}
四、总结
1、如何判断js是否存在
F12 看网页文件 / 右击检查 看源码 里面有无js代码
2、如何敏锐察觉js可能存在安全隐患
1)如果在js代码中写了判断逻辑(有注释 / 很多代码)就引起重视【前端验证】
2)优先关注高敏感代码:任何涉及用户输入,URL参数,Cookie,LocalStorage的代码(如 document.cookie
、location.hash
、eval()
)。
3)可以用工具扫描