一、XSS 基本原理
XSS 攻击的是使用系统的 用户,而不是像SQL注入一样攻击系统本身
XSS 将JS代码放在 <script></script>
中,或 onclick
事件中,或 超链接的 href
中
1、情景
<?php if(isset($_GET['content'])){ $content=$_GET['content']; echo "输入的内容是:".$content; } else{ echo "没输入!"; }
阿一 发现了这个网站存在 XSS 漏洞,于是构造了一个 url 发给了阿二
这段 url 实际是
http://localhost:63342/XSS学习/index.php?content=<button οnclick=alert("别点了!")>点我!</button>
阿二 兴致勃勃地点开链接,发现有个按钮,按钮还在勾引阿二点它,于是阿二点击按钮,被攻击
2、利用
?content=<button οnclick=alert("别点了!")>点我!</button> ?content=<a href='javascript:alert("别点了!")'>点我!</a>
称之为 试探 。发现网站可以被传入任意字符。
后面就可以上传JavaScript脚本,进行钓鱼等操作。
如果PHP代码这样写:
echo "输入的内容是:".'<input type="text" , value="'.$content.'" />';
payload 1 :
?content=<script>alert('别点了!')</script>
查看源代码:
输入的内容是:<input type="text" , value="<script>alert('别点了!')</script>" />
payload 2 :
?content=我就上传7个字" οnclick="alert('别点了!')
点击触发弹窗。
二、PHP 基础
$conn->beginTransaction();
是一个用于数据库操作的PHP方法,它用于开始一个新的 事务。事务是一组数据库操作的逻辑单元,这些操作要么全部成功执行,要么全部回滚(撤销)到执行前的状态。此方法在需要对数据库进行一系列操作且要求这些操作要么全部成功执行,要么全部不执行的场景下非常有用。它确保了数据库的一致性和完整性。
使用方法: 调用 $conn->beginTransaction(); 来开始一个事务。 在事务中执行必要的数据库操作。 根据操作结果,选择使用 $conn->commit(); 来提交事务(永久保存所有更改),或者使用 $conn->rollBack(); 来回滚事务(撤销所有更改)。
示例:
$conn->beginTransaction(); try { // 执行数据库操作... // 如果所有操作成功,则提交事务 $conn->commit(); } catch (Exception $e) { // 如果发生异常,则回滚事务 $conn->rollBack(); // 处理异常... }
三、给画廊写一个发表评论的功能
1、新增代码
``` gallery.php 新增代码 <?php ...... // 查询评论数据 $sqlComment = "SELECT user, role, comment FROM comments"; $stmtComment = $conn->prepare($sqlComment); $stmtComment->execute(); $comments = $stmtComment->fetchAll(PDO::FETCH_ASSOC); ?> <!DOCTYPE html> ...... <br><hr><br> <div style="width: 100%;margin: auto;text-align: center;"><a href="add_comment.php">我要发表评论!</a></div> <br><hr><br> <div style="width: 100%;margin: auto;text-align: center;">这里是 评论!</div> <br> <?php // 如果有评论,则在页面合适的位置显示评论列表 if (!empty($comments)) { echo '<div class="comments comments-table">'; echo '<table>'; echo '<thead><tr><th>用户</th><th>选择的角色</th><th>评论</th></tr></thead>'; echo '<tbody>'; foreach ($comments as $comment) { echo '<tr>'; echo '<td>' . $comment['user'] . '</td>'; echo '<td>' . $comment['role'] . '</td>'; echo '<td>' . $comment['comment'] . '</td>'; echo '</tr>'; } echo '</tbody>'; echo '</table>'; echo '</div>'; echo '<br><hr>'; } ?> ......
```add_comment.php <?php session_start(); if (!isset($_SESSION['username'])) { die('请先登录!'); } ?> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>发表评论</title> <style> #user{ width: 40%; background-color: #f0f0f0; text-align: center; line-height: 50px; border: #0C0C0C solid; margin-left: auto; margin-right: auto; } #user div{ font-size: 20px; margin: 20px; } #user div input{ width: 150px; } </style> <script type="text/javascript" src="static/jquery-3.7.1.min.js"></script> <script> function add_comment(){ var role = $("#role").val(); // 使用.val() 获取jQuery对象的值 var comment = $("#comment").val(); if (role == "" || comment == ""){ alert("请填写完整!"); } else { // var a = role + comment; // alert(a); $.ajax({ url: "comment.php", // 当调用此函数时,向 comment.php 发送请求 type: "POST", data: //在 JavaScript 中,这个 data 是一个对象。有两个属性:role 和 comment { role: role, //键 值 对 comment: comment }, success: function (data) { alert(data); } /**在这段JavaScript代码中,success 是一个回调函数, * 通常用于处理AJAX请求成功后的响应数据。 * 当AJAX请求成功完成并且从服务器接收到响应时,success 函数会被调用, * 并将服务器返回的数据作为参数 data 传递给该函数。 */ }); } } </script> </head> <body> <div id="user"> <div>你是谁?你是 <?php echo $_SESSION['username'];?> !</div> <hr> <div>你选择的角色:<input type="text" id="role"></div> <div>输入你的评论:<textarea id="comment"></textarea></div> <div><input type="button" value="发表评论" οnclick="add_comment()" style="background: #00F7DE"></div> </div> </body> </html>
```comment.php 把评论信息插入到数据库 <?php require_once 'common.php'; /**require_once:如果包含的文件不存在或无法读取,PHP会终止脚本执行并输出致命错误(E_COMPILE_ERROR) * include:同样情况下,生成一个警告错误(E_WARNING),脚本仍会继续执行 */ $conn->beginTransaction();//开始一个新的事务 try { // 获取POST数据 $role = isset($_POST['role']) ? trim($_POST['role']) : null; $comment = isset($_POST['comment']) ? trim($_POST['comment']) : null; if (empty($role) || empty($comment)) { throw new Exception('不完整!'); } $stmt = $conn->prepare("INSERT INTO comments (user, role, comment) VALUES (?, ?, ?)"); /**在名为"comments"的数据库表中插入的新值。 * 三个问号(?),作为占位符,代表将要插入的实际值。 */ $stmt->bindParam(1, $_SESSION['username']); //在实际执行SQL语句时,第一个问号将被当前登录用户的用户名替换 $stmt->bindParam(2, $role); $stmt->bindParam(3, $comment); // 执行SQL语句 $stmt->execute(); // 提交事务 $conn->commit(); echo '评论成功!'; } catch (PDOException $e) { $conn->rollBack();// 回滚事务 echo iconv('gbk', 'utf-8', $e->getMessage()); // iconv 函数将错误信息从GBK编码转换成UTF-8编码,以便在UTF-8编码的网页中正确显示。 } catch (Exception $e) { // 输出异常信息 echo '发表失败'.$e->getMessage(); } // 不论是否成功,最后都应关闭数据库连接 $conn = null;
2、XSS 漏洞
(1)、利用
试探
啊啊啊啊啊!!我的小可爱啊!让我抱抱!啊啊啊!! <br> <img src="img/让我摸摸.jpg" style='width: 200px' οnclick="location.href='https://www.bilibili.com/video/BV1uc411K7tE/?spm_id_from=333.999.0.0&vd_source=7e0119c85d6fbd2c38b073b5ce048274'"> <br> 你是踏碎星河落入我梦境的幻想啊!!!!
插入图片并设置事件,点击图片跳转到某链接。
发现可以执行 JS 代码
如果此时写一段死循环进去,将会一直消耗 用户的CPU资源 ,而不是 服务器资源 。
<script> var r = 1; while (true){ r--;} </script>这就是 XSS 与 SQL 的区别
写死循环这种方式 极其过分!仅作为举例演示!
(2)、防御
$role = htmlspecialchars($role, ENT_QUOTES, 'UTF-8'); $comment = htmlspecialchars($comment, ENT_QUOTES, 'UTF-8'); $stmt->bindParam(1, $_SESSION['username']); //在实际执行SQL语句时,第一个问号将被当前登录用户的用户名替换 $stmt->bindParam(2, $role); $stmt->bindParam(3, $comment);
htmlspecialchars() 函数的作用:
在数据库中可以发现,尖括号、引号等敏感字符被替换(编码)了。