安全开发-web应用-PHP-文件访问和操作
前面我们学习了php普通的留言板功能和登录的操作,还学习了三种身份验证的小知识
相信经过自己的敲敲,已经对这部分的相应漏洞已经有所了解了,哪些地方有漏洞,哪些地方可以注入,学习开发就是了解这些最基本的原理
现在我们继续学习关于php的小芝士
首先来学习关于文件上传的小芝士
文件上传:学习FILES&过滤机制的实现
文件显示:目录遍历&过滤机制实现
通过实现这个功能捏来让我们知道关于这些的漏洞的原理
我们直接开干
依旧老文件夹创建两个文件
upload.html //前端
upload.php //后端
//upload.html <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>文件上传</title> <style> body { font-family: 'Helvetica Neue', sans-serif; background-color: #f0f2f5; display: flex; justify-content: center; align-items: center; height: 100vh; } .upload-container { background-color: #ffffff; padding: 40px; border-radius: 12px; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); text-align: center; } .upload-container h2 { margin-bottom: 20px; color: #333; } .file-input { margin-bottom: 20px; } input[type="file"] { padding: 10px; border: 1px solid #ccc; border-radius: 6px; } .submit-btn { background-color: #4CAF50; color: white; padding: 10px 20px; border: none; border-radius: 6px; cursor: pointer; font-size: 16px; } .submit-btn:hover { background-color: #45a049; } </style> </head> <body> <div class="upload-container"> <h2>上传你的文件</h2> <form action="upload.php" method="post" enctype="multipart/form-data"> <div class="file-input"> <input type="file" id="file" name="fileToUpload" required> </div> <button type="submit" class="submit-btn">上传</button> </form> </div> </body> </html>
这样简单的一个文件上传前端页面就整好了
首先关于文件上传我们要认识一个全局变量
$_FILES 他是php中预定义的超全局变量,用于在上传文件时从客户端接收文件,并保存到服务器上,他是一个包含文件上传文件信息的数组,包括文件名,类型,大小,临时文件名等信息
然后我们先来调试一下后端代码
//upload.php <?php $name = $_FILES['fileToUpload']['name']; //获取上传文件的名称 $type = $_FILES['fileToUpload']['type']; //获取上传文件的类型 $size = $_FILES['fileToUpload']['size']; //获取上传文件的大小 $tmp_name = $_FILES['fileToUpload']['tmp_name']; //获取上传文件的临时存储路径 $error = $_FILES['fileToUpload']['error']; //获取上传文件的错误信息 echo "文件名称: $name <br>"; echo "文件类型: $type <br>"; echo "文件大小: $size <br>"; echo "临时存储路径: $tmp_name <br>"; echo "错误信息: $error <br>"; ?>
现在来看看效果
随便上传一个图片或者啥东西
可以看到他输出了我们定义的各种值
现在我们来修改一下代码,让文件上传到服务器上,首先我们在网站本地路径创建一个接收文件的文件夹uploads
然后稍微修改一下代码,把前面我们调试输出的给注释了,现在我们来整上传
//upload.php if(move_uploaded_file($tmp_name, 'uploads/' . $name)){ echo "文件上传成功!"; }; //将临时文件移动到指定目录
测试一下
可以看到文件已经上传成功了
然后我们就要写文件过滤了,不然啥叽里咕噜都能传,直接是上传一个木马那不就炸了吗,我来演示一下
这里使用的是中国蚁剑
因为这里没有过滤,我们就可以直接上传一个一句话木马,具体以后再讲,然后现在假如我们知道了他的目录,然后我们首先去浏览器访问一下看能不能访问
可以看到他能正常访问,现在我们来连接一下,具体的还是以后讲漏洞的时候再说哈,这里直接看使用
可以看到也是连接成功了,我们打开看看
可以看到这就拿下服务器权限了,然后不就可以随便查看别人的敏感文件了吗,然后像上次说的关于session会话岂不是也可以拿下了吗。
所以说啊,关于文件过滤非常重要哈,不能让小黑客上传一些叽里咕噜,小心服务器炸冈了啊
首先文件过滤一般有三种个过滤方式-白名单,黑名单和MIME类型过滤
这三种还是非常好理解的哈
首先黑名单就是写好代码固定的过滤掉里面不让上传的文件类型,比如写一个php,就静止上传php文件
首先我们来看看他是怎么使用的
//upload.php $black_ext = array('php', 'html', 'js', 'css'); //黑名单文件后缀 $fenge = explode('.', $name); //将文件名按.分割成数组 $ext = end($fenge); //获取文件后缀名 echo $ext;
首先看看他的工作原理,这里定义了两个变量来接受值,然后使用explode来分割文件名,然后用数组表示,最后调试输出看看效果
可以看到上传一个jpg图片文件的话这里就会输出一个jpg后缀,那么黑名单就根据这个来匹配上面我们定义的进禁止上传的文件,接着看看实现
//upload.php $black_ext = array('php', 'html', 'js', 'css'); //黑名单文件后缀 $fenge = explode('.', $name); //将文件名按.分割成数组 $ext = end($fenge); //获取文件后缀名 if(in_array($ext, $black_ext)){ echo "文件类型不允许上传!".$ext; exit; } else{ echo "文件类型允许上传!".$ext; }
再来实验一下
可以看到如果上传了黑名单中的文件类型,会被直接拒绝掉,这样就保证了安全捏
但是想想还有点问题捏,黑名单写起来太麻烦了,那么多文件类型,怎么写的过来,比如说我们这里限制了php,但是如果还有别的类型的php文件呢,比如php5.我们来看看
前面我们限制了php上传,但是我用php5上传试试呢
可以看到上传上去了,然后我们访问一下
也能成正常访问,补豪,我的服务器
所以说啊,黑名单还是有局限性,所以我们现在来使用白名单来过滤
白名单其实也很好理解,跟黑名单相反,写入的可以上传,那么没有写入的不就全都被过滤了吗,非常方便~
他的代码也就是跟黑名单相反
//upload.php $allow_ext = array('jpg', 'jpeg', 'png', 'gif'); //允许上传的文件后缀名 $fenge = explode('.', $name); //将文件名按.分割成数组 $ext = end($fenge); //获取文件后缀名 if(!in_array($ext, $allow_ext)){ echo "文件类型不允许上传!".$ext; exit; } else{ echo "文件类型允许上传!".$ext; }
只要允许的文件和判断逻辑改一下就行,我们再来看看
可以看到前面黑名单没有写到的php5在这里也是被ban了哈,所以说捏,白名单更好用点捏,但是他也可以绕过嘞,但是这里就不提了,这个就是后面文件上传绕过该说的了
然后我们再来看看第三种,MIME类型过滤
MIME(Multipurpose Internet Mail Extensions)类型是描述文件内容类型的一种方式,常见格式是:
文件类型 | MIME 类型 |
---|---|
PNG 图片 | image/png |
JPEG 图片 | image/jpeg |
PDF 文件 | application/pdf |
Word 文档 | application/msword |
ZIP 压缩包 | application/zip |
这个一般会出现在流量包里面,我们抓个包就明白了
可以看到我们上传图片的那个包中,会出现一个这个content-type标签,这个是浏览器对应给文件带上的类型,每个文件的类型都不同,所以现在我们根据这个来过滤
//upload.php $allow_type = array('image/jpeg', 'image/png', 'image/gif'); if(!in_array($type, $allow_type)){ echo "文件类型不允许上传!".$type; exit; } else{ echo "文件类型允许上传!".$type; }
写法也是差不多的,只是判断的变成了文件类型而已
同样的判断类型后不符合的就拒绝,允许的就上传,不过这个判断的话也是非常的不安全,这一抓包然后修改一下类型立马就G了呀
可以看到我这里上传的是php文件,然后类型是他php文件类型,要是我把他改成图片格式呢
然后发包
补豪,我的服务器又被攻击了,所以说啊,这三种各有各的有点,当然还是要配合使用的啦
文件上传和过滤到这里就差不多了,我们继续来看下一个芝士
文件管理
功能:显示,上传,下载,删除,编辑,包含
打开目录读取文件列表
递归循环读取文件列表
判断是文件还是文件夹
PHP.INI 目录访问控制
通过学习开发这个文件管理嘞,来知道这部分有哪些安全漏洞,所以直接开干,创建相关文件
file-mange.php
//file-mange.php <?php $dir = './';//读取当前目录 $dakai = opendir($dir); //打开目录 while(($file=readdir($dakai))!==false){ //读取目录 echo "<a href='$file'>$file</a><br>"; //输出文件名 } ?>
这串代码的功能就是首先dir读取当前目录,然后用一个变量接受打开目录的值,这就读取到了目录里的文件,然后用一个循环来读取目录,如果他读取到了就为true然后下面输出读取到的文件,到最后为flase就结束循环,这就是一个简单的文件读取操作
可以看到当前目录下的文件他都读取到了,非常好用~
但是我们也可以看到问题,里面的admin和upditor还有uploads是文件夹呀,但是他还是以文件的形式输出的,这样导致点击之后有时候就不会正常输出了,所以我们现在再来添加一下识别文件和文件夹的代码
//file-mange.php <?php $dir = './';//读取当前目录 $dakai = opendir($dir); //打开目录 while(($file=readdir($dakai))!==false){ //读取目录 //echo "<a href='$file'>$file</a><br>"; //输出文件名 if(is_dir($file)){//判断是否是目录 echo "<a href='$file'>文件夹:$file</a><br>"; //输出目录名 }else{ echo "<a href='$file'>文件:$file</a><br>"; //输出文件名 } } ?>
就用is_dir判断是否为文件或者文件夹,这里的函数具体去php用法里去搜,这里就不细说
可以看到他这里就正常的判断出了哪些是文件哪些是文件夹,但是现在点击文件夹可以看到是不能正常显示的,但是下面还有文件呀,所以我们继续来改进代码
//file-mange.php <?php $dir = $_GET['path'] ?? '.'; //获取目录路径,默认为当前目录 function show_file($dir){ $dakai = opendir($dir); //打开目录 while(($file=readdir($dakai))!==false){ //读取目录 if(is_dir($dir.'/'.$file)){//判断是否是目录 echo "<a href='file-mange.php?path=$dir/$file'>文件夹:$file</a><br>"; //输出目录名 }else{ echo "<a href='$dir/$file'>文件:$file</a><br>"; //输出文件名 } } closedir($dakai); //关闭目录 } show_file($dir); //调用函数显示目录下的文件和文件夹 ?>
现在访问下面的文件夹就正常了,这里就是使用了函数调用,首先定义一个值来接受当前目录,然后如果不为空我们就执行下面的循环,然后你点击文件夹的时候他当然不为空啦,他就会重新执行一遍循环体然后输出你点击过后的文件夹,这样就成功输出了目录下当前的文件。是不是非常的简单呢~~
但是这样也有一个风险,现在我们只是做了基础的文件显示,但是没有对上级目录进行限制,如果path地址你输入上级目录的话,是不是也是一个敏感信息泄露呢
要是一直输入../他就一直访问上级目录,结果给我整到服务器目录下面了,补豪,我的服务器信息
所以说,我们还要限制一下访问的权限,不能让他出这个网站的目录,可以在代码中过滤这个输入,但是在php.ini配置文件中也有一个限制目录的功能
这里面有一个open_basedir 参数,他的作用就是限制用户访问的目录
这是他php语言支持的,在这里写上你限制的目录,他就不能再访问到上级目录了,
把他控制在这个网站目录下,我们再去试试看
可以看到他再想访问这个上级目录的话就会直接报错了,这样就限制他了捏,然后在代码中再限制一下www的访问权限,就可以让这个目录变的安全一点点捏
//file-mange.php $black_str = array("../","./../"); if(in_array($dir, $black_str)){ echo "<script>alert('禁止访问');</script>"; exit; }else{ show_file($dir); }
前面我们学习了黑名单过滤,我们现在就用上了,但是黑名单的短板也很明显哈,如果我输入的不是这个黑名单里规定的样式,还是防不住哈,但是这里不过多介绍了,自己琢磨自己实现~
现在就变得更安全咯,但是我要是用特殊的写入方法呢
随便构造一下语句就还是能正常访问,这就是黑名单的弊端了,除非我们把./都屏蔽了哈,这部分就自己琢磨吧~这个就演示完毕了
现在就然后顺便美化一下这个页面
//file-mange.php <?php $dir = $_GET['path'] ?? '.'; function show_file($dir){ echo "<!DOCTYPE html> <html> <head> <meta charset='UTF-8'> <title>文件管理器</title> <style> body { font-family: Arial, sans-serif; background-color: #f9f9f9; padding: 20px; } h1 { color: #333; } .file-list { max-width: 600px; margin: auto; background: #fff; border: 1px solid #ddd; border-radius: 8px; padding: 20px; box-shadow: 0 2px 5px rgba(0,0,0,0.1); } .file-item { margin: 8px 0; padding: 8px 12px; border-radius: 5px; transition: background 0.3s; } .file-item:hover { background: #f0f0f0; } .folder { color: #2b6cb0; font-weight: bold; } .file { color: #4a5568; } a { text-decoration: none; } </style> </head> <body> <div class='file-list'> <h1>📁 当前目录: $dir</h1> "; $dakai = opendir($dir); while(($file = readdir($dakai)) !== false){ if ($file === '.' || $file === '..') continue; $fullpath = $dir . '/' . $file; if (is_dir($fullpath)) { echo "<div class='file-item folder'>📂 <a href='file-mange.php?path=" . urlencode($fullpath) . "'>$file</a></div>"; } else { echo "<div class='file-item file'>📄 <a href='" . htmlspecialchars($fullpath) . "'>$file</a></div>"; } } closedir($dakai); echo "</div></body></html>"; } show_file($dir); ?>
好看捏~
文件显示这部分差不多了,我们继续来完成后面的功能
首先我们来说文件包含
这个是php中最基础的参数了include,相信现在已经不陌生了,最基础的连接数据库都是要用到他的,他的功能就是引用别的文件然后来实现在当前页面的功能,这个也是非常的重要
但是这个也是有一个安全隐患,有的时候如果代码写得不规范,错误的使用了文件包含,那也是非常的危险啊,因为他引用的时候会直接执行代码,那如果是一个后门代码呢,我们来举个例子,比如我们之前写的上传文件的页面,我们把上传和检测的页面合并在一起呢要是
可以看到他就直接把我们前面写的前端代码就直接引用过来了,那现在我们再测试一个东西,我们把这个文件包含代码稍微修改一下
include($_GET['page']);
让他接受get传参,我们再来看看会发生什么
可以看到他这里直接就是把我们前面写的留言板就引用过来了,要是这时候别人上传了一个后门文件然后引用一下呢
这里我就假装上传了一个1.txt文件
我们首先正常的访问一下
他只会把他当做一个文件然后用html渲染到浏览器上,也就是一个纯文本,但是这时候要是引用一下这个txt文件呢
那加入我写的是一个后门文件呢
来测试一下
蛙趣了,可以看到直接是成功注入了,太危险力,补药啊
从这个例子就可以看到关于文件包含的一些漏洞了,也是非常的哈人哈
这样关于文件包含的相关部分也就说到这里,我们继续来看
首先我们对文件页面进行一个按钮的添加,让他显示出该有的功能,首先创建一个file-test.php文件
//file-test.php <?php $path = $_GET['path'] ?? './'; function getlist($path) { $file_list = ['dir' => [], 'file' => []]; // 初始化数组 if (!is_dir($path)) return $file_list; $handle = opendir($path); while (($file_name = readdir($handle)) !== false) { if ($file_name !== '.' && $file_name !== '..') { $file_path = $path . '/' . $file_name; $file_type = filetype($file_path); $file_size = is_file($file_path) ? filesize($file_path) : 0; $file_list[$file_type][] = [ 'file_name' => $file_name, 'file_path' => $file_path, 'file_size' => round($file_size / 1024, 2), 'file_mtime' => date('Y-m-d H:i:s', filemtime($file_path)), ]; } } closedir($handle); return $file_list; } $file_list = getlist($path); ?> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <table width="100%" style="font-size: 10px; text-align:center;"> <tr> <th>图标</th> <th>文件名</th> <th>日期</th> <th>大小</th> <th>路径</th> <th>操作</th> </tr> <?php foreach ($file_list['dir'] as $v): // 遍历输出目录,file_type分为dir和file // dir表示目录,file表示文件 ?> <tr> <td><img src="./images/1.png" width="20" height="20"></td> <td><?php echo $v['file_name']; ?></td> <td><?php echo $v['file_mtime'] ?></td> <td>-</td> <td><?php echo $v['file_path'] ?></td> <td><a href="?path=<?php echo ($v['file_path']); ?>">打开</a></td> </tr> <?php endforeach; //结束遍历输出目录 ?> <?php foreach ($file_list['file'] as $v): ?> <tr> <td><img src="./images/2.png" width="20" height="20"></td> <td><?php echo $v['file_name']; ?></td> <td><?php echo $v['file_mtime'] ?></td> <td><?php echo $v['file_size'] ?> KB</td> <td><?php echo $v['file_path'] ?></td> </tr> <?php endforeach; ?> </table> </body> </html>
首先基础的完成打开文件夹的操作
这样算是正常访问了,也能正常打开子目录下的文件,现在我们继续完成关于文件的操作
//file-test.php $path = $_GET['path'] ?? './'; $action = $_GET['a'] ?? ''; // 执行删除操作 if ($action === 'del') { if (is_file($path)) { unlink($path); // 删除后跳转回上级目录,防止继续显示当前被删除的文件 header('Location: ' . $_SERVER['PHP_SELF'] . '?path=' . urlencode(dirname($path))); exit; } else { die('非法操作:不是文件'); } } // 显示文件列表逻辑(只处理目录) if (!is_dir($path)) { die('路径错误'); }
首先添加删除逻辑
<td><a href="?a=del&path=<?php echo ($v['file_path']); ?>" onclick="return confirm('确认删除该文件吗?')">删除</a></td>
当首先上面定义了一个变量action记录当前的用户操作,然后在表格中添加删除按钮,当用户点击之后
php代码就会接收到用户发出的get请求,也就是
$path = $_GET['path'] ?? './'; $action = $_GET['a'] ?? '';
表示从请求中提取出 path
(文件路径)和 a
(操作类型)。如果用户点击了删除链接,这里就会变成:
$path = './test.txt'; $action = 'del';
然后进入删除逻辑
is_file($path)
检查路径是否真的是一个文件,避免用户传入一个目录或非法路径。
unlink($path)
是 PHP 删除文件的函数。
删除后使用 header('Location: ...')
重定向到当前脚本 + 上级目录,防止刷新页面时重复删除。
exit;
阻止继续执行后续逻辑。
然后经过重定向之后又会触发一次遍历目录,这时候删除的文件就消失了,防止报错
现在我们实验一下
首先我们用前面写过的随便上传一个文件
然后这里就可以看到刚才上传的文件了,我们点击一下删除看看
可以看到文件成功删除咯,耶~这个功能就写好咯
而下载功能和删除功能差不多,首先也是添加一个按钮
<td><a href="?a=down&path=<?php echo ($v['file_path']); ?>" onclick="return confirm('确认下载该文件吗?')">下载</a></td>
然后添加下载逻辑
// 下载操作 else if ($action === 'down') { if (!is_file($path)) { die('非法请求,目标不是文件'); } ob_clean(); flush(); header("Content-Type: application/octet-stream"); header("Content-Disposition: attachment; filename=" . basename($path)); header("Content-Length: " . filesize($path)); readfile($path); exit; }
如果get传入一个down值时,就会触发这部分代码,中间的一个参数具体使用自行百度
可以看到完整的路径就是这样的
http://192.168.153.139:8083/file-test.php?a=down&path=./1.txt
然后就触发下载咯~
ok啊这个功能也是完美的实现了
然后就剩下一个最麻烦的编辑
首先明白编辑的功能,点击编辑之后我们就可以对对应的文件进行编辑,说明是要打开这个文件并且在浏览器上显示内容
,然后并且可以编辑这个显示的内容,然后点击确定,就可以编辑成功
首先我们测试一下读取文件
else if ($action === 'edit') { if (!is_file($path)) { die('非法请求,目标不是文件'); } header("Content-Type: text/plain; charset=utf-8"); //添加ua头防止乱码 $duqu = file_get_contents($path); echo $duqu; exit; }
我们打开看看
可以看到现在也是能正常的读取到文件里面的内容了,那现在我们来添加一下编辑功能
首先添加编辑模块
<td><a href="#" onclick="return openEdit('<?php echo ($v['file_path']); ?>')">编辑</a></td>
然后添加编辑弹窗的组件,这样点击之后页面会显示一个可编辑的文本框,这部分接到table标签后面即可
<div id="editModal" style="display:none; position:fixed; top:10%; left:50%; transform:translateX(-50%); background:#f9f9f9; border-radius:8px; box-shadow:0 0 10px rgba(0,0,0,0.3); width:80%; max-width:600px; padding:20px; z-index:9999;"> <h3 style="margin-top:0;">编辑文件内容</h3> <textarea id="editContent" style="width:100%; height:300px; font-family:monospace; padding:10px;"></textarea> <div style="text-align:right; margin-top:10px;"> <button onclick="saveEdit()" style="padding:5px 15px; background:#28a745; color:white; border:none; border-radius:5px; margin-right:10px;">保存</button> <button onclick="closeModal()" style="padding:5px 15px; background:#ccc; border:none; border-radius:5px;">取消</button> </div> </div> <div id="overlay" style="display:none; position:fixed; top:0; left:0; right:0; bottom:0; background:rgba(0,0,0,0.5); z-index:9998;"></div>
然后用js编写弹窗逻辑
<script> function openEdit(path) { fetch('?a=edit&path=' + encodeURIComponent(path)) .then(res => res.text()) .then(text => { document.getElementById('editContent').value = text; document.getElementById('editModal').style.display = 'block'; document.getElementById('overlay').style.display = 'block'; document.getElementById('editModal').dataset.path = path; }); return false; // 阻止默认跳转 } function closeModal() { document.getElementById('editModal').style.display = 'none'; document.getElementById('overlay').style.display = 'none'; } function saveEdit() { const path = document.getElementById('editModal').dataset.path; const content = document.getElementById('editContent').value; fetch('save.php', { method: 'POST', headers: {'Content-Type': 'application/x-www-form-urlencoded'}, body: 'path=' + encodeURIComponent(path) + '&content=' + encodeURIComponent(content) }) .then(res => res.text()) .then(msg => { alert(msg); closeModal(); location.reload(); // 保存后刷新页面 }); } </script>
这部分不用太深究,因为是大肘子写的代码,关于前端并不是我们需要了解滴,实现功能即可
然后新建一个save.php用来处理编辑后的内容
//save.php <?php $path = $_POST['path'] ?? ''; $content = $_POST['content'] ?? ''; if (!$path || !is_file($path)) { die('文件路径无效'); } //限制只允许编辑特定文件类型或路径 file_put_contents($path, $content); echo '保存成功';
现在来测试一下
点击之后就可以看到文本内容并且可以编辑
可以看到内容也是成功的添加了,耶~~~也是成功了捏
总结一下
我们首先学习了文件上传,关于文件上传的过滤,这部分的漏洞相信现在也有所思路了,目标要是没有控制过滤,那木马岂不是随便传了,非常的危险。但是如果使用的是oss云存储,这部分就不用担心了,因为云存储只做存储,并不会执行任何程序或者命令,也就是不会解析,但是他也是有个风险的,因为配置这个oss上传配置文件的时候要使用到他的key,如果这部分没有注意的话那不就是敏感信息泄露吗,偷偷拿走之后把别人的学习资料都下载了,啊哈。
其次就是管理文件系统,首先我们显示了当前目录下的文件,然后点击还可以查看,但是这个首先想到的漏洞就是关于目录的,要是一个没限制,一下给我干c盘里了,也是非常滴危险,所以在php配置文件或者代码中要限制访问
然后就是实现三种功能,删除和下载其实经过前面的目录漏洞就应该有所了解,要是前面没有限制访问的话,他是不是直接通过这个按钮修改一下文件名直接是把别的盘的敏感文件都下载了呢,万一有学习资料呢,别人小黑客下载了给你删了,那不就直接炸冈了吗,呜呜呜呜,我的学习资料,编辑也差不多,这部分肯定是要做登录控制的,然后登录又一堆漏洞,呜呜呜,我就想把学习资料放在网上有这么难吗
还有一个文件包含,相信上面我的演示已经很明了的展示了漏洞,所以对文件包含这一部分也是要严格限制,不能给普通用户有操作权限,这部分最好还是写死吧
漏洞是根据使用的函数来决定使用的方法的,不同函数操作方法也不同,所以说啊,有漏洞都是开发的锅,骂他
这部分的功能也就实现的差不多咯
下期见
(未完待续)