JS前端认证

文件上传

首先依旧是确定表单html代码,如下所示

<form class="upload" method="post" enctype="multipart/form-data"  action="">
<input class="uploadfile" type="file" name="upload" onchange="checkFileExt(this.value)"/><br />
<input class="sub" type="submit" name="submit" value="开始上传" />
</form>

然后引入js代码。这个js代码相当于别人封装好的一系列代码,我们通过script进行文件包含,然后我们就可以直接使用scriptjs声明好的函数

<script src="js/jquery-1.12.4.min.js"></script>

然后紧接着就是在js代码中进行相关的验证

<script>
function checkFileExt(filename)
{
var flag = false; //状态
var arr = ["jpg","png","gif"];
//取出上传文件的扩展名
//1.jpg index=1,ext=jpg
//lastIndexOf是返回最后一个字符"."的下标
//从指定位置复制字符串
var index = filename.lastIndexOf(".");
var ext = filename.substr(index+1);
//比较
for(var i=0;i<arr.length;i++)
{
if(ext == arr[i])
{
flag = true; //一旦找到合适的,立即退出循环
alert("上传的文件符合要求!");
break;
}
}
//条件判断
if(!flag)
{
alert("上传的文件不符合要求,请重新选择!");
location.reload(true);
}
}
</script>

这个功能之前我们也实现过,主要是实现对文件上传的后缀名进行验证,符合要求的我们才进行上传,但是我们是用PHP实现的,如下代码所示

<?php
header("Content-Type:text/html;charset=utf-8");
@$file_name=$_FILES['upload']['name'];
//获取上传文件类型
@$file_type=$_FILES['upload']['type'];
//获取上传文件大小
@$file_size=$_FILES['upload']['size'];
//获取上传文件临时文件名
@$file_tmpname=$_FILES['upload']['tmp_name'];
//获取上传文件是否错误
@$file_error=$_FILES['upload']['error'];

echo $file_name."<hr>";
echo $file_type."<hr>";
echo $file_size."<hr>";
echo $file_tmpname."<hr>";
echo $file_error."<hr>";

if (@$file_error>0){
echo '上传出错!';
}
else{
move_uploaded_file(@$_FILES["upload"]["tmp_name"], "../upload/" . @$_FILES["upload"]["name"]);
echo "文件存储在: " . "upload/" . @$_FILES["upload"]["name"];
}
?>

从上我们可以看出,我们既可以通过PHP实现,也可以通过JS进行实现,但是两个的区别在于,PHP的代码是看不见的,只能通过黑盒测试(去猜),JS的代码是我们可以看见的,是白盒测试,也就是我们平常说的,一种是前端验证,一种是后端验证

至于如何判断是否采用JS验证,我们可以查看页面源码,看看有没有相关的代码,同时要注意,任何可疑的JS文件都要查看一下,因为有可能被封装成js文件,通过文件包含进行引用

同时,我们可以通过禁用JS来限制这部分代码,有相关插件,火狐上我装的是这个,具体浏览器可以去搜一下,都有相关插件的

image-20240527110535840

Ajax数据传输

Ajax(Asynchronous Javascript And XML),即是异步的JavaScript和XML,Ajax其实就是浏览器与服务器之间的一种异步通信方式,它可以异步地向服务器发送请求,在等待响应的过程中,不会阻塞当前页面,在这种情况下,浏览器可以做自己的事情。直到成功获取响应后,浏览器才开始处理响应数据。

使用Ajax需要提前导入jquery-1.12.4.min.js文件,即<script src="../js/jquery-1.12.4.min.js"></script>

下面使用Ajax进行数据传递

login.html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Ajax登录</title>
</head>
<body>
帐号:<input type="text" class="user">
密码:<input type="password" class="pass">
<button>用户登录</button>

<script src="../js/jquery-1.12.4.min.js"></script>
<script>
$('button').click(function () {
$.ajax({
type:'post',
url:'ajax.php', //发给ajax.php文件。
dataType:'json',
data:{
myUname:$('.user').val(),
myUpass:$('.pass').val()
},
success:function (res) {
//console.log(res);
if(res.infoCode==1){
alert('登录成功');
}else{
alert('登录失败');

}
}
});

});

</script>
</body>
</html>

ajax.php

<?php
$username=$_POST['myUname'];
$password=$_POST['myUpass'];
$success=array('msg'=>'ok');
if($username=='xiaodi' && $password=='123456'){
$success['infoCode'] = 1; //成功登录
}else{
$success['infoCode'] = 0; //失败登录
}
echo json_encode($success);

当我们进行登录的时候,我们控制台的返回如下

6f65df2ae81b026759af48f667aa6b62

同时,通过抓包也可以看到返回值

image-20240527112927975

对于我们上面书写的代码,对于下块区域

image-20240527113142347

我们很容易发现判断是否success是在前端判断的,通过infoCode来判断是否登录成功,这个时候我们就可以拦截从服务器发回前端页面的数据,将infoCode改为1,就可以绕过前端验证

右键点击Do intercept

image-20240527113402206

将服务器发回的包拦截,修改InfoCode,实现绕过

image-20240527113533937

image-20240527113549939

商品购买案例

设计一

设计一通过商品的价格以前端设置的为准,后端接受前端传回来的价格进行运算,判断能否执行购买

user.php-前端页面

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>购买设计1</title>
</head>
<body>
<img src="iphone.jpg" width="270" height="270" alt=""/><br>
价格:8888<br>
数量:<input type="text" class="num">
<button>购买</button>

<script src="js/jquery-1.12.4.min.js"></script>
<script>
$('button').click(function () {
$.ajax({
type:'post',
url:'shop.php',
dataType:'json',
data:{
//前端传回数据
price:'8888',
number:$('.num').val()

},
success:function (res) {
//console.log(res);
if(res.code==1){
alert('购买成功');
}else{
alert('购买失败');

}
}
});

});
</script>
</body>
</html>

shop.php-进行验证

<?php
header("Content-Type:text/html;charset=utf-8");
$success=array('msg'=>'ok');
$price=$_POST['price'];
$num=$_POST['number'];
$m=$price*$num;

if($m<10000){
$success['code']=1;
}else{
$success['code']=0;
}
echo json_encode($success);
?>

image-20240527135600600

由于是书写在前端的,同时判断是否购买成功也是在前端,所以我们这里有两种绕过方式,其中一种和上面一样,使用Do intercept,将code改为1

第二种方式,由于POST是从前端接受传入的数据,所以我们可以更改price,如下所示

image-20240527140240144

设计二

设计二我们将商品价格设置以数据库设置价格为准,数据接受价格后运算

user1.php

<?php
header("Content-Type:text/html;charset=utf-8");
include('/config/conn1.php');
//


$sql="select * from shop where id=1";

$result=mysql_query($sql,$conn);
while($row=mysql_fetch_array($result)){
$imgsrc=$row['imgsrc'];
$price=$row['price'];
echo "<img src='$imgsrc' width='270' height='270' alt=''/><br>";
echo "价格:$price<br>";
echo "数量:<input type='text' class='num'>";
echo "<button>购买</button>";

}
?>

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>购买设计2</title>
</head>
<body>

<script src="js/jquery-1.12.4.min.js"></script>
<script>
$('button').click(function () {
$.ajax({
type:'post',
url:'shop1.php',
dataType:'json',
data:{
price:<?php echo $price;?>,
number:$('.num').val()

},
success:function (res) {
//console.log(res);
if(res.code==1){
alert('购买成功');
}else{
alert('购买失败');

}
}
});

});
</script>
</body>
</html>

shop1.php

<?php
header("Content-Type:text/html;charset=utf-8");
$success=array('msg'=>'ok');
$price=$_POST['price'];
$num=$_POST['number'];
$m=$price*$num;

if($m<10000){
$success['code']=1;
}else{
$success['code']=0;
}

echo json_encode($success);
?>

看起来规范了很多,但是我们发现shop.php并没有实质性的改变,只是你没办法修改它前端页面显示的价格,在传输过程中,$price仍然接收的是$_POST传进来的,我们依旧可以通过bp抓包进行价格修改,进而实现绕过

设计三

价格进行写死,如下所示

image-20240527141411480

此时无论怎么修改bp抓的包,都无法进行修改,但是还有一个问题,没对数量进行限制,如果我输入小数,是不是这个逻辑也能判断成功呢?如果我输入负数,是不是更能成功呢?所以我们应该同时对数量进行正则限制,限制只能输入正整数

至于如何判断是否是前端验证,我们可以观察返回值是否有json、code、msgbox等关键字,类似于{"code":200,"data":"111111111","msg":'"}这种形式,一般都是前端验证,可以尝试绕过