• Day23:安全开发-PHP应用&后台模块&Session&Cookie&Token&身份验证&唯一性


    目录

    具体安全知识点

    身份验证-Cookie使用

    身份验证-Session使用

    唯一性判断-Token使用

    总结

    源码

    思维导图


    PHP知识点:

    功能:新闻列表,会员中心,资源下载,留言版,后台模块,模版引用,框架开发等

    技术:输入输出,超全局变量,数据库操作,逻辑架构,包含上传&下载删除;

    技术:JS&CSS混用,Cookie,Session操作,MVC架构,ThinkPHP引用等。

    具体安全知识点

    Cookie和Session都是用来在Web应用程序中跟踪用户状态的机制
    1、存储位置不同:
    Cookie是存储在客户端(浏览器)上的,而Session是存储在服务器端的。
    2、安全性不同:
    Cookie存储在客户端上,可能会被黑客利用窃取信息,而Session存储在服务器上,更加安全。
    3、存储容量不同:
    Cookie的存储容量有限,一般为4KB,而Session的存储容量理论上没有限制,取决于服务器的硬件和配置。
    4、生命周期不同:
    Cookie可以设置过期时间,即便关闭浏览器或者重新打开电脑,Cookie仍然存在,直到过期或者被删除。而Session一般默认在浏览器关闭后就会过期。
    5、访问方式不同:
    Cookie可以通过JavaScript访问,而Session只能在服务器端进行访问。
    6、使用场景不同:
    Cookie一般用于存储小型的数据,如用户的用户名和密码等信息。而Session一般用于存储大型的数据,如购物车、登录状态等信息。


    总之,Cookie和Session都有各自的优缺点,选择使用哪一种方式,取决于具体的应用场景和需求。一般来说,如果需要存储敏感信息或者数据较大,建议使用Session;如果只需要存储少量的数据,并且需要在客户端进行访问,可以选择使用Cookie。

    在Web应用程序中,使用token和不使用token的主要差异在于身份验证和安全性。
    1.身份验证:采用token机制的Web应用程序,用户在登录成功后会收到一个token,这个token可以在每次请求时发送给服务器进行身份验证。而不采用token机制的Web应用程序,一般会使用session机制来保存用户登录状态,服务器会在用户登录成功后创建一个session,之后的每个请求都需要在HTTP头中附带这个session ID,以便服务器能够验证用户身份。
    2、安全性:采用token机制的Web应用程序,在服务器上不会存储用户的登录状态,只需要存储token即可。因此,即使token被盗取,黑客也无法获得用户的密码或者其他敏感信息。而不采用token机制的Web应用程序,一般会在服务器上存储用户的登录状态,因此如果服务器被黑客攻击,黑客可能会获得用户的敏感信息。
    3、跨域访问:采用token机制的Web应用程序,在跨域访问时,可以使用HTTP头中的Authorization字段来传递token信息,方便实现跨域访问。而不采用token机制的Web应用程序,在跨域访问时,需使用cookie或session来传递用户身份信息,比较麻烦。
    总之,采用token机制可以提高Web应用程序的安全性,并且方便实现跨域访问。不过,使用token机制也需要开发者自己来实现身份验证和token的生成和验证,相对来说比较复杂。而不采用token机制,使用session机制则相对简单,但是安全性相对较低。因此,具体采用哪种机制,需要根据实际情况进行权衡和选择。

    下面的实验都是使用PHP开发的,php代码执行在后端,只有除此之外的代码会返回给浏览器

    身份验证-Cookie使用

    生成cookie的原理图过程:见图

    1、客户端向服务器发送HTTP请求。

    2、服务器检查请求头中是否包含cookie信息。

    3、如果请求头中包含cookie信息,则服务器使用该cookie来识别客户端,否则服务器将生成一个新的cookie。

    4、服务器在响应头中设置cookie信息并将其发送回客户端。

    5、客户端接收响应并将cookie保存在本地。

    6、当客户端发送下一次HTTP请求时,它会将cookie信息附加到请求头中。

    7、服务器收到请求并检查cookie的有效性。

    8、如果cookie有效,则服务器响应请求。否则,服务器可能会要求客户端重新登录。

    setcookie(): 设置一个cookie并发送到客户端浏览器。

    unset(): 用于删除指定的cookie。

    Cookie安全:

    信息泄露:如果Cookie中包含敏感信息(如用户ID、密码等),攻击者可以通过窃取Cookie来获取这些敏感数据。为了防止信息泄露,应确保敏感信息在传输和存储过程中进行加密,并使用安 全的传输协议(如HTTPS)来保护Cookie的传输过程。


    跨站点脚本攻击(XSS):攻击者可以通过在Web应用程序中注入恶意脚本来获取用户的Cookie。为了防止XSS攻击,开发人员应对用户输入进行正确的验证和过滤,并对输出进行适当的转义,以防止恶意脚本的注入。


    跨站点请求伪造(CSRF):攻击者可以通过欺骗用户访问恶意网站来利用用户的身份进行非法操作。为了防止CSRF攻击,可以使用随机生成的令牌(CSRF令牌)来验证每个请求的合法性,并确保令牌在每个请求中都是唯一且难以预测的。


    会话劫持:攻击者可以通过窃取用户的会话Cookie来冒充用户身份。为了防止会话劫持,可以通过使用安全标志(如"Secure"和"HttpOnly")来限制Cookie的使用范围,并在会话身份验证上使用额外的保护措施,如双因素身份验证。


    不安全的存储:如果Cookie存储在用户计算机上的不安全位置,如明文存储或不加密的存储,攻击者可以轻易地访问和修改Cookie。为了保护Cookie的存储,应将Cookie存储在安全的位置,如服务器端的数据库或加密的本地存储。

    setcookie()有四个参数,分别是:Cookie名称,Cookie值,过期时间,Cookie在浏览器的存储路径("/",标识根目录,该Cookie在整个网站都可以访问)。

    创建admin-c.php登陆页面

    打开项目admin目录分别创建三个文件:

    • admin-c.php登陆文件
    • index-c.php登录成功的首页文件
    • logout-c.php登出文件

    使用chtgpt生成一个后台登录的html界面

    • 你需要在实际应用中将登录表单的 action属性指向后台处理登录的脚本(例如 login.php)由于当前就是登录文件为空即可

    进行编写登录的程序

    1、接收输入账号密码

    2、判断账号密码是否正确

    • 需要构建数据库admin【username,password】
    • 输入默认值【admin,123456】(当登陆成功的时候数据显示的,登录不成功数据显示为0)
    • 加入判断是否是POST请求,来防止一直提示登陆失败
    • 加入判断行数是否大于0来判断是否登录成功
    1. // 判断请求是否为 POST
    2. if ($_SERVER["REQUEST_METHOD"] == "POST") {
    3. // 检查查询结果行数是否大于 0
    4. if (mysqli_num_rows($data) > 0) {

    3.正确后生成cookie进行保存

    设置cookie值(过期时间,依据用户名密码等生成)

    1. $expire = time() + 60 * 60 * 24 * 30; // 设置 Cookie 过期时间为一个月后
    2. setcookie('username', $user, $expire, '/'); // 设置用户名 Cookie
    3. setcookie('password', $pass, $expire, '/'); // 设置密码 Cookie

    4.错误的账户密码进行提示*

    5.跳转至成功页面,进行跳转到登录成功页面

    1. // 重定向到 index-c.php 页面
    2. header('Location: index-c.php');
    3. exit(); // 终止脚本执行

    创建admin-c.php登陆成功的首页文件,创建logout-c.php登出文件

    构建登入成功的HTMl页面,并输出当前登录的用户

    • 给出退出登录的选项,如果触发则跳转到登录页面
    • 登陆前没有cookie是不显示任何用户名的,登陆后显示出用户名
    • 需要加入判断如果获取的cookie值,和数据库中对应的数据值不同,则要跳转到登录页面,使之继续登录,直至相符
    1. **//登录成功的首页文件
    2. if ($_COOKIE['username']!='admin'and$_COOKIE['password']!='123456')
    3. // 重定向到 index-c.php 页面
    4. header('Location: index-c.php');
    5. ?>**
    6. "utf-8">
    7. 后台首页
    8. 后台首页

    9. **

      欢迎您, echo $_COOKIE['username']; ?>

    构建登出成功的代码,将cookie值默认为空,并跳转至登陆页面

    1. **setcookie('username', '', time() - 3600, '/');
    2. setcookie('password', '', time() - 3600, '/');
    3. // 跳转到登录页面
    4. header('Location: admin-c.php');**
    5. exit;
    6. ?>

    admin/admin-c.php:登录验证并且成功后跳转到admin/index-c.php

    1. "en">
    2. "UTF-8">
    3. 后台登录
    4. class="login">
    5. <h2>后台登录h2>
    6. <form action="" method="post">
    7. <label for="username">用户名:label>
    8. <input type="text" name="username" id="username" required>
    9. <label for="password">密码:label>
    10. <input type="password" name="password" id="password" required>
    11. <input type="submit" value="登录">
    12. form>
    13. div>
    14. body>
    15. html>
    16. php
    17. include '../config.php';
    18. //登录文件
    19. /*
    20. * 1、接受输入的帐号密码
    21. * 2、判断帐号密码正确性
    22. * 3、正确后生成的cookie进行保存
    23. * 3、1错误的帐号密码就进行提示
    24. * 4、跳转至成功登录的页面
    25. */
    26. //1、接受输入的帐号密码
    27. $user=$_POST['username'];
    28. $pass=$_POST['password'];
    29. //2、判断帐号密码正确性
    30. //连接数据库 进行数据库查询将数据进行对比
    31. $sql="select * from admin where username='$user' and password='$pass';";
    32. $data=mysqli_query($con,$sql);
    33. if($_SERVER["REQUEST_METHOD"] == "POST"){
    34. // 判断用户登录成功
    35. // 检查查询结果行数是否大于 0
    36. if(mysqli_num_rows($data) > 0){
    37. $expire = time() + 60 * 60 * 24 * 30; // 一个月后过期
    38. setcookie('username', $user, $expire, '/'); //
    39. setcookie('password', $pass, $expire, '/');
    40. //echo '';
    41. // 重定向到 index-c.php 页面
    42. header('Location: index-c.php');
    43. exit(); // 终止脚本运行
    44. }else{
    45. //判断用户登录失败
    46. echo '';
    47. }
    48. }

    admin/index-c.php:检测未授权访问,并跳转登录页面

    1. // 验证cookie不正确
    2. if($_COOKIE['username']!='admin' and $_COOKIE['password']!='123456'){
    3. header('Location: admin-c.php');
    4. }
    5. ?>
    6. "utf-8">
    7. 后台首页
    8. 后台首页

    9. 欢迎您, echo $_COOKIE['username']; ?>

    admin/login-c.php:退出登录

    1. setcookie('username', '', time() - 3600, '/');
    2. setcookie('password', '', time() - 3600, '/');
    3. // 跳转到登录页面
    4. header('Location: admin-c.php');
    5. exit;
    6. ?>

    身份验证-Session使用

    生成session原理:

    1、客户端向服务器发送HTTP请求。
    2、服务器为客户端生成一个唯一的session ID,并将其存储在服务器端的存储器中(如文件、数据库等)。
    3、服务器将生成的session ID作为一个cookie发送给客户端。
    4、客户端将session ID保存为一个cookie,通常是在本地浏览器中存储。
    5、当客户端在发送下一次HTTP请求时,它会将该cookie信息附加到请求头中,以便服务器可以通过该session ID来识别客户端。
    6、服务器使用session ID来检索存储在服务器端存储器中的与该客户端相关的session数据,从而在客户端和服务器之间共享数据。

    session_start(): 启动会话,用于开始或恢复一个已经存在的会话。
    $_SESSION: 用于存储和访问当前会话中的所有变量。
    session_destroy(): 销毁当前会话中的所有数据。
    session_unset(): 释放当前会话中的所有变量。

    Session安全:

    会话劫持:会话劫持是指攻击者通过窃取合法用户的会话标识符(如会话ID或令牌)来冒充用户身份。为了防止会话劫持,应采取以下措施:

    • 使用随机生成的、复杂的会话标识符,使其难以猜测。
    • 在会话标识符上实施安全标志,如"Secure"和"HttpOnly",以限制Cookie的使用范围。
    • 在用户身份验证过程中使用额外的保护措施,如双因素身份验证。

    会话固定攻击:会话固定攻击是指攻击者通过将自己的会话标识符强制应用于目标用户的会话来控制目标用户的会话。为了防止会话固定攻击,应采取以下措施:

    • 在用户认证之前生成新的会话标识符,而不是在认证后重新使用现有的会话标识符。
    • 在用户身份验证之前销毁旧会话,以确保新会话的安全性。

    跨站点脚本攻击(XSS):XSS攻击可以窃取用户会话数据或以其他方式干扰会话。为了防止XSS攻击,应采取以下措施:

    • 对用户输入进行正确的验证和过滤,以防止恶意脚本的注入。
    • 对输出进行适当的转义,以防止恶意脚本在浏览器中执行。

    跨站点请求伪造(CSRF):CSRF攻击可以利用用户的身份执行未经授权的操作。为了防止CSRF攻击,应采取以下措施:

    • 使用随机生成的、唯一的CSRF令牌来验证每个请求的合法性。
    • 将CSRF令牌嵌入到表单中,并在每个请求中验证令牌的有效性。

    会话超时和注销:应设定适当的会话超时时间,以确保长时间不活动的会话被及时注销。同时,提供明确的注销功能,使用户可以主动终止会话。

    Session存储路径:PHP.INI中session.save_path设置路径

    在php.ini中设置session存储路径(服务端)

    当登录成功后,生成如下文件:

    内如如下:

    username|s:5:"admin";password|s:6:"123456";

    sesion被存储在Cookie里

    退出登录后,服务端删除/tmp/tmp下的session文件,浏览器session失效

    PHPSEDDID的值就是服务端文件sess_后缀,服务端上这个文件存储铭文信息。服务端是通过这个字符串识别的。

    为什么安全?用户退出登录即失效,即使黑客抓到session也没用。

    唯一性判断-Token使用

    Token生成原理:

    1、生成Token并将其存储在Session
    2、生成Token并将其绑定在Cookie触发
    3、尝试登录表单中带入Token验证逻辑
    4、思考Token安全特性

    创建Token文件:Token.php,Token_check.php;前端页面类似,复制过来,修改一下有关toke代码

    1. class="login">
    2. <h2>后台登录h2>
    3. **
    4. <form action="token_check.php" method="post">
    5. <input type="hidden" name="token" value="php echo $_SESSION['token'] ; ?>">**
    6. <label for="username">用户名:label>
    7. <input type="text" name="username" id="username" required>
    8. <label for="password">密码:label>
    9. <input type="password" name="password" id="password" required>
    10. <input type="submit" value="登录">
    11. form>
    12. div>

    Toke生成的代码

    每次token随表单提交后都需要重置以保持token的唯一性。

    1. // 生成Token并将其存储在Session中
    2. **session_start();**
    3. //1.因为是用的session维持会话,token已经绑定到下面的表单了
    4. //2.token,生成之后直接存到session里,主要是方便重置token,
    5. //**每次token随表单提交后都需要重置以保持token的唯一性。**
    6. **$_SESSION['token'] = bin2hex(random_bytes(16));**
    7. ?>
    Token_check.php,完成有关toke检验的代码
    登录成功,token值保存在session中
    1. session_start();
    2. **// 从 POST 请求中获取 token,如果不存在则设为空字符串
    3. $token = $_POST['token'] ?? '';**
    4. **if ($token !== $_SESSION['token']) {
    5. // token不匹配,禁止访问
    6. header('HTTP/1.1 403 Forbidden');
    7. // 生成新的 token
    8. $_SESSION['token'] = bin2hex(random_bytes(16));
    9. // 输出访问被拒绝的信息
    10. echo 'Access denied';
    11. // 终止脚本执行
    12. exit;**
    13. }else{
    14. **// 生成新的 token
    15. $_SESSION['token'] = bin2hex(random_bytes(16));
    16. // 检查用户名和密码是否匹配
    17. if($_POST['username']=='admin' && $_POST['password']=='123456'){
    18. echo '登录成功!';**
    19. // 输出管理员访问信息
    20. echo '你是管理员可以访问文件管理页面!';
    21. }else{
    22. echo '登录失败!';
    23. }
    24. }
    25. ?>

    访问token.php,php代码在后端被执行,生成一个session给浏览器作为CooKie

    生成一个token值,存储在服务端的session文件里

    同时也保存在浏览器里

    输入账号密码提交

    登录成功

    Cookie的PHPSESSID不变

    但是token值变了,服务器上的

    刷新再次访问,还是上一次的token,登录失败

    token为什么具有唯一性,就是每次数据包交互之后token就会改变,流量包里的token永远是上一次的。

    总结

    Cookie:一旦生成就会作为身份凭据在有效期内不会再改变

    攻击者一旦获得Cookie就能以这个凭据登录

    Session:登录成功后,就会生成B/S之间的会话

    • 浏览器:PHPSESSID:session(字符串) 作为Cookie
    • 服务端:session_session文件,存储用户账号密码

    攻击者获得Session后却不能直接登录,因为这只是一个服务端对用户的标识,还需要输入密码正确才行。

    Token:token在服务端,浏览器都有存储,服务端保存在会话里。每次数据交互后都改变。

    攻击者从流量上获得的token永远是上一次的

    源码

    admin-c.php

    1. "en">
    2. "UTF-8">
    3. 后台登录
    4. class="login">
    5. <h2>后台登录h2>
    6. <form action="" method="post">
    7. <label for="username">用户名:label>
    8. <input type="text" name="username" id="username" required>
    9. <label for="password">密码:label>
    10. <input type="password" name="password" id="password" required>
    11. <input type="submit" value="登录">
    12. form>
    13. div>
    14. body>
    15. html>
    16. php
    17. include '../config.php';
    18. //登录文件
    19. /*
    20. * 1、接受输入的帐号密码
    21. * 2、判断帐号密码正确性
    22. * 3、正确后生成的cookie进行保存
    23. * 3、1错误的帐号密码就进行提示
    24. * 4、跳转至成功登录的页面
    25. */
    26. //1、接受输入的帐号密码
    27. $user=$_POST['username'];
    28. $pass=$_POST['password'];
    29. //2、判断帐号密码正确性
    30. //连接数据库 进行数据库查询将数据进行对比
    31. $sql="select * from admin where username='$user' and password='$pass';";
    32. $data=mysqli_query($con,$sql);
    33. if($_SERVER["REQUEST_METHOD"] == "POST"){
    34. // 判断用户登录成功
    35. // 检查查询结果行数是否大于 0
    36. if(mysqli_num_rows($data) > 0){
    37. $expire = time() + 60 * 60 * 24 * 30; // 一个月后过期
    38. setcookie('username', $user, $expire, '/'); //
    39. setcookie('password', $pass, $expire, '/');
    40. //echo '';
    41. // 重定向到 index-c.php 页面
    42. header('Location: index-c.php');
    43. exit(); // 终止脚本运行
    44. }else{
    45. //判断用户登录失败
    46. echo '';
    47. }
    48. }

    index-c.php

    1. // 验证cookie不正确
    2. if($_COOKIE['username']!='admin' and $_COOKIE['password']!='123456'){
    3. header('Location: admin-c.php');
    4. }
    5. ?>
    6. "utf-8">
    7. 后台首页
    8. 后台首页

    9. 欢迎您, echo $_COOKIE['username']; ?>

    logout-c.php

    1. setcookie('username', '', time() - 3600, '/');
    2. setcookie('password', '', time() - 3600, '/');
    3. // 跳转到登录页面
    4. header('Location: admin-c.php');
    5. exit;
    6. ?>

    admin-s.php

    1. "en">
    2. "UTF-8">
    3. 后台登录
    4. class="login">
    5. <h2>后台登录h2>
    6. <form action="" method="post">
    7. <label for="username">用户名:label>
    8. <input type="text" name="username" id="username" required>
    9. <label for="password">密码:label>
    10. <input type="password" name="password" id="password" required>
    11. <input type="submit" value="登录">
    12. form>
    13. div>
    14. body>
    15. html>
    16. php
    17. include '../config.php';
    18. //登录文件-采用session验证
    19. //1、接受输入的帐号密码
    20. $user=$_POST['username'];
    21. $pass=$_POST['password'];
    22. $sql="select * from admin where username='$user' and password='$pass';";
    23. $data=mysqli_query($con,$sql);
    24. if($_SERVER["REQUEST_METHOD"] == "POST"){
    25. // 登录密码可以查到,及正确,生成session
    26. if(mysqli_num_rows($data) > 0){
    27. session_start(); // 启动会话,用于开始或恢复一个已经存在的会话。
    28. // $_SESSION: 用于存储和访问当前会话中的所有变量。
    29. $_SESSION['username']=$user;
    30. $_SESSION['password']=$pass;
    31. header('Location: index-s.php');
    32. exit();
    33. }else{
    34. echo '';
    35. }
    36. }

    index-s.php

    1. //登录成功首页文件-采用session验证
    2. //判断省去了数据库查询获取帐号密码的操作 直接赋值
    3. session_start();
    4. if($_SESSION['username']!='admin' && $_SESSION['password']!='123456'){
    5. header('Location: admin-s.php');
    6. }
    7. ?>
    8. "utf-8">
    9. 后台首页
    10. 后台首页

    11. 欢迎您, echo $_SESSION['username']; ?>

    logout-s.php

    1. // 开始会话
    2. session_start();
    3. // 清除 SESSION 变量,并销毁会话
    4. session_unset(); // session_destroy(): 销毁当前会话中的所有数据。
    5. session_destroy(); // 释放当前会话中的所有变量。
    6. // 重定向到登录页面
    7. header('Location: admin-s.php');
    8. exit;
    9. ?>

    token.php

    1. // 生成Token并将其存储在Session中
    2. session_start();
    3. //1.因为是用的session维持会话,token已经绑定到下面的表单了
    4. //2.token,生成之后直接存到session里,主要是方便重置token,
    5. //每次token随表单提交后都需要重置以保持token的唯一性。
    6. $_SESSION['token'] = bin2hex(random_bytes(16));
    7. ?>
    8. "en">
    9. "UTF-8">
    10. 后台登录
    11. class="login">
    12. <h2>后台登录h2>
    13. <form action="token_check.php" method="post">
    14. <input type="hidden" name="token" value="php echo $_SESSION['token'] ; ?>">
    15. <label for="username">用户名:label>
    16. <input type="text" name="username" id="username" required>
    17. <label for="password">密码:label>
    18. <input type="password" name="password" id="password" required>
    19. <input type="submit" value="登录">
    20. form>
    21. div>
    22. body>
    23. html>

    token_check.php

    1. session_start();
    2. // 从 POST 请求中获取 token,如果不存在则设为空字符串
    3. $token = $_POST['token'] ?? '';
    4. if ($token !== $_SESSION['token']) {
    5. // token不匹配,禁止访问
    6. header('HTTP/1.1 403 Forbidden');
    7. // 生成新的 token
    8. $_SESSION['token'] = bin2hex(random_bytes(16));
    9. // 输出访问被拒绝的信息
    10. echo 'Access denied';
    11. // 终止脚本执行
    12. exit;
    13. }else{
    14. // 生成新的 token
    15. $_SESSION['token'] = bin2hex(random_bytes(16));
    16. // 检查用户名和密码是否匹配
    17. if($_POST['username']=='admin' && $_POST['password']=='123456'){
    18. echo '登录成功!';
    19. // 输出管理员访问信息
    20. echo '你是管理员可以访问文件管理页面!';
    21. }else{
    22. echo '登录失败!';
    23. }
    24. }
    25. ?>

    思维导图

  • 相关阅读:
    c++ 田忌赛马(史上最全)上海月赛乙组T3
    有了HTTP,为什么还要RPC?
    vs 自定义代码块 代码自动生成
    HTTP代理与SOCKS5代理,有什么区别?
    pytorch深度学习实战lesson16
    3D-NAND向500层进发,天花板在哪里?
    整人代码2
    OS - 操作系统实战 - 学习/实践
    阿里云无影研发负责人任晋奎:端云技术创新,打造全新用户体验
    VSCode配置ESP-IDF
  • 原文地址:https://blog.csdn.net/qq_61553520/article/details/136527416