一、cookie 与 session的区分
1)cookie
特点:存储小型文件(例如:用户名和密码);将登录用户的敏感信息以加密字符串形式存储在浏览器上;存储在浏览器上;如果不清除浏览器的cookie记录,那么记录会一直存在,相比安全性一般;
2)session
特点:存储较大型文件(例如:购物车、登录状态);将登录用户的敏感信息以文件形式存储在服务器上;如果用户关闭了当前页面,会自动删除session文件,安全性高,相对应的维护成本也提高;
3)如何识别一个web是cookie还是session?
法1:目标规模大,一般是session;否则为cookie
**法2**:登陆后不动,一段时间(10min/30min/1h)后来看结果,需要重新登录的就是session
法3:关闭浏览器,还能登录是cookie;否则是session
二、token
唯一性
一个数据包对应唯一的token值,否则会被服务器认定为垃圾包,直接丢弃不予通过。
三、实际开发中不同验证方式的运用
前置要求:小皮开启web + navicat连接好数据库 +新建一张admin表
【1】Cookie
文件要求:创建好三个文件,分别负责登录、登出、登录成功后的首页
00x1 前端html制作
扔给gpt,指令:html写一个后台登陆漂亮的页面
00x2 登录(admin-c.php)逻辑考量
00x3 按照逻辑进行登录验证开发
// 1.接收输入的账号和密码 $user = $_POST['username']; $pass = $_POST['password']; // 2.判断账号密码正确性 $sql = "select * from admin where username='$user' and password='$pass';"; // 判断mysql查询结果 $data = mysqli_query($con,$sql); if ($_SERVER["REQUEST_METHOD"] == "POST"){ # 防止没有提交账密的情况下提示登录失败 if (mysqli_num_rows($data)>0){ # 利用返回行数函数来判断:如果用户输入的账号密码在mysql表中有记录,那么就一定返回>0行 # echo 'ok'; # 那么就可以确认账号密码是正确的 // 3.设置cookie并进行保存 $expire = time() + 60 * 60 * 24 * 30; # time()截取当前时间;整行意为一个月过期 setcookie('username',$user,$expire,'/'); setcookie('password',$pass,$expire,'/'); // 4.跳转至成功登录的页面 # echo "<script>alert('登录成功!')</script>"; # 给一个js弹窗登录成功 header('Location:admin-c.php'); # 确认账密正确,利用header跳转首页 }else{ echo "<script>alert('登录失败')</script>"; # 如果mysql表中没有这条记录,js弹窗给一个登陆失败的tips } }
验证一下:成功跳转!cookie也在。
补充:
我们刚刚跳转成功,但是用户可以直接访问index.php地址,绕过登录,所以我们进一步对index做代码限制,防止绕过登录。
00x4 相对应对登陆后首页(index-c.php)逻辑考量 & 开发
前端逻辑:
完善:防止他直接访问站点绕过登录,那么就是再加一个验证,验证cookie中接收到了username以及password
【如果缺一或均无 ---> 跳转到admin-c.php重新登陆】
【如果有 ---> 无事发生 继续留在index.php中】
<?php // 登录成功后的首页 include "../config.php"; // cookie中来判断是否登录 if (!isset($_COOKIE['username']) || !isset($_COOKIE['password'])) { header('Location: admin-c.php'); // 如果username/password中其一没有 --> 未登录 --> 跳转登录页 exit(); } ?>
00x5 对登出页面(logout-c.php)进行逻辑考量 & 开发
思路就是:将cookie清除,并跳转到登录页面
<?php //登出页面 // 将cookie值清空,时效为去除当前时间一个小时前的; setcookie('username', '', time() - 3600, '/'); setcookie('password', '', time() - 3600, '/'); // 跳转到登录页面 header('Location: admin-c.php'); exit;
*** 攻击手法 ***
可以进行测试,输入错误的用户名/密码,然后给cookie中加上username & password
直接路径访问index-c.php
发现成功了,也就意为着cookie是可以被提取的,从而拿到敏感信息被拿到。
所以就引入一个比cookie更安全的验证方式,session验证。
【2】Session验证
00x1 前端html
继续复用漂亮的前端页面代码
00x2 登录界面admin-s.php的逻辑考虑
<?php include "../config.php"; // 登陆文件采取session验证 //1、接收输入账号密码 $user = @$_POST['username']; //加@防止瞎报错 $pass = @$_POST['password']; // 相对应的去mysql查询记录 $sql = "select * from admin where username = '$user' and password = '$pass';"; $data = mysqli_query($con,$sql); // 第一层if防止未提交数据弹窗登陆失败 // 第二层if是确认用户名和密码正确,且执行生成session if ($_SERVER["REQUEST_METHOD"]=="POST"){ if (mysqli_num_rows($data) > 0){ session_start(); $_SESSION['username'] = $user; $_SESSION['password'] = $pass; header('Location:index-s.php'); // 确认后跳转首页 }else{ echo "<script>alert('登录失败!')</script>"; } }
00x3 查看session文件
去php路径下的ini文件中,搜索session.save_path
重启一下小皮 【web服务(apache /nigix)】
然后正确账密登录,去刚刚session存储路径发现了session文件
00x4 index首页逻辑
还是利用index-c.php的优雅前端页面,我们拿来用,只不过是提取session的值
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>后台首页</title> </head> <body> <h1>后台首页</h1> <p>欢迎您,<?php echo $_SESSION['username']; ?>!</p> <p><a href="logout-s.php">退出登录</a></p> </body> </html>
写一个身份验证,二次验证,防止用户直接绕过登录验证
注:一定要记得session_start(),且要在html上面【因为_session全局变量,需要先启动】
<?php session_start(); include "../config.php"; if (!isset($_SESSION['username']) || !isset($_SESSION['password'])) { header('Location: admin-s.php'); // 如果username/password中其一没有 --> 未登录 --> 跳转登录页 exit(); } ?>
测试一下功能,成功。
00x5 session特性验证
就是对应唯一的session文件,假如我在谷歌浏览器登入成功,然后我拿url地址去egde浏览器,会成功绕过吗?答案是不成功,因为两次访问得到的是两个不同的session文件,这就是为什么session相比cookie要更加安全。
谷歌先登入 -->复制url
拿url粘贴到egde,看结果
未成功,还是登入界面
原因:
谷歌的session文件:
edge的session文件:
说明完全是两个session文件,完全无关。
00x6 登出逻辑
要先清除一下session变量,并销毁,利用的是
session_unset(); session_destroy();
<?php // 跳转到登录页面 // 开始会话 session_start(); // 清除 SESSION 变量,并销毁会话 session_unset(); session_destroy(); // 重定向到登录页面 header('Location: admin-s.php'); exit; ?>
*** 攻击手法 ***
1、先拿到可以登录的session值(edge)
2、session的替换
在edge的页面未关闭的情况下,将edge的session值替换给谷歌浏览器
3、以许可session去访问index-s.php
【3】token
原理:前面得知session存储在服务器中;所以原理是:服务器按照某种加密方式,出一串密文然后与session绑定成为session-token,我们提交表单的时候,带着这串密文(session-token)一起,以表单形式post到检查的地方,到了负责检查的地方,确认个人信息在库,同时确认我们提交的密文(post-token)与一开始他加密(session-token)给我们的是一样的,那么就给予通过。
以用户角度而言:用户压根不知道有token的存在,session与token绑定以后,成为session-token,然后被隐式的以表单形式传递给check检查的地方,但是检查的地方是按照post来接收这串密文(post-session),最终与session-token来判断,由于一样 自然通过。
00x1 生成密文的文件token.php的开发逻辑
1)前端
还是借用美观的后台页面
2)先生成随机密文,再与session绑定,这里为了后续做csrf等渗透测试,与cookie也做绑定
<?php session_start(); // 生成随机的cookie $token = bin2hex(random_bytes(16)); // 将token绑定到session中 $_SESSION['token'] = $token ; // 将token绑定到cookie中 setcookie('token',$token,time()+3600,'/'); ?>
3) 生成密文以后,前端的表单中加上传向的位置(token_check.php)和隐式传递的session-token(以post方式拿到,所以是post-token)
00x2 检查密文对应的文件token_check.php的开发逻辑
验证token是否一致 ----> 不一致 ---> 进不去
----> 一致 ---> 作废验证过的token。进一步去验证用户信息
<?php session_start(); include "../config.php"; $user = @$_POST['username']; //加@防止瞎报错 $pass = @$_POST['password']; $token = $_POST['token'] ?? ''; // ??空合并运算符 --> 若有值赋值,若为空 赋空给变量token if ($token !== $_SESSION['token']) { // token不匹配,禁止访问 header('HTTP/1.1 403 Forbidden'); $_SESSION['token'] = bin2hex(random_bytes(16)); echo 'Access denied'; exit; }else{ // 重新生成新token,旧的作废 $_SESSION['token'] = bin2hex(random_bytes(16)); // 进一步验证用户信息 if($_POST['username']== $user && $_POST['password']== $pass ){ echo '登录成功!'; echo '你是管理员可以访问文件管理页面!'; }else{ echo '登录失败!'; } }
***验证唯一性效果***
00x1 bp抓包
故意输错密码,抓个包
00x2 发送到重放器尝试进行爆破
00x3 结果及原因分析
结果是尽管修改成正确的密码(或者给密码挂上一个字典,进行爆破),还是无法成功进入后台
原因:是因为我们第一次输错密码的时候,生成了一个session与token绑定,然后我们再次修改密码进行发包,这个时候旧的session-token就失效了,但是我们作为攻击者角度,是拿不到新的session-token进行提交的,所以自然访问也就失败了,这就是csrf-token防御的优秀之处,即使hacker拿到了敏感信息,但是拿不到session也就无法进入后台。