20232423 2025-2026-1 《网络与系统攻防技术》实验八实验报告
一、实验内容
(1)Web前端HTML
能正常安装、启停Apache。理解HTML,理解表单,理解GET与POST方法,编写一个含有表单的HTML。
(2)Web前端javascipt
理解JavaScript的基本功能,理解DOM。
在(1)的基础上,编写JavaScript验证用户名、密码的规则。在用户点击登陆按钮后回显“欢迎+输入的用户名”
尝试注入攻击:利用回显用户名注入HTML及JavaScript。
(3)Web后端:MySQL基础:正常安装、启动MySQL,建库、创建用户、修改密码、建表
(4)Web后端:编写PHP网页,连接数据库,进行用户认证
(5)最简单的SQL注入,XSS攻击测试
(6)安装DVWA或WebGoat平台,并完成SQL注入、XSS、CSRF攻击。
二、实验目的
通过搭建Web应用环境,实践前后端开发,并深入理解SQL注入、XSS等常见Web安全漏洞的原理与防护方法。
三、实验环境
虚拟机VMware中Kali的linux环境
四、实验过程
4.1Web前端HTML
4.1.1启动Apache
在kali虚机中通过命令systemctl start apache2启动Kali虚拟机中自带的Apache服务,同时为了下次开机能使用,可通过命令systemctl enable apache2设置 Apache服务开机自启。然后通过命令systemctl status apache2.service可确认Apache状态,命令systemctl stop apache2可关闭Apache服务

然后打开kali自带的火狐浏览器,输入localhost,可以看到Apache的欢迎页面,说明Apache Web服务器启动成功。

4.1.2HTML表单功能实现
进入虚拟机的/var/www/html目录,使用root权限打开该文件夹,即可创建html文件并进行编写。为进行GET与POST方法区别的理解,创建两个html文件,分别使用GET和POST方法。代码如下图。


双击这两个文件,可以在kali的浏览器中打开,界面如下


然后在界面中输入用户名和密码,跳转后的界面如下图,第一张图片为GET的跳转界面,第二张图片为POST的跳转界面。可以看到GET跳转界面在上方URL显示了你输入的用户名和学号,即数据直接拼接在URL中;而POST跳转界面没有拼接参数,数据藏在请求体中,URL不可见。


4.1.3 内容理解
(1)HTML表单的理解:其是用户与网页交互的主要方式,用于收集用户输入的数据。就像上面编写的登录界面一样,可以搜集用户输入的昵称和密码的信息
(2)GET与POST方法对比:通过上面的时间演示,可以看到GET方法数据在URL中可见;POST方法数据在请求体中传输,URL不可见。除此之外,通过网上资料的学习,还知道如下图所示的内容。

4.2 Web前端javascipt
4.2.1JavaScript表单功能实现
为实现表单验证用户名、密码,同时在用户点击登陆按钮后回显“欢迎+输入的用户名”的功能,就得使用JavaScript进行实现。
JavaScript的基本功能有:数据处理(变量、运算、逻辑判断、循环等)、交互控制(响应用户操作、修改页面内容/样式)、环境操作(操作浏览器内置对象、本地存储)
使JS要能实现以上功能,DOM必不可少。DOM即文档对象模型,就是将 HTML标签、属性、文本都转换成JS能操作的对象,让JS可以“操控”页面。没有DOM,JS只能处理内存中的数据,无法和页面交互;有了DOM,JS才能进行读取页面内容、修改页面结构/样式等操作。
使现在设计一个JavaScript登录表单,代码如下
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>注入攻击测试-登录页</title>
<!-- 极简样式,仅保证基础展示 -->
<style>
body { margin: 50px; font-family: Arial; }
.error { color: red; font-size: 12px; }
.welcome { color: green; font-size: 16px; margin-top: 10px; }
</style>
</head>
<body>
<h1>Login</h1>
<form id="loginForm">
<label for="name">用户名:</label>
<input type="text" id="name" name="name">
<div class="error" id="nameError" style="display: none;">用户名不能为空</div>
<br><br>
<label for="password">密码:</label>
<input type="password" id="password" name="password">
<div class="error" id="pwdError" style="display: none;">密码不能为空(不少于8位)</div>
<br><br>
<input type="submit" value="提交">
<div class="welcome" id="welcome" style="display: none;"></div>
</form>
<script>
// 获取元素
const form = document.getElementById('loginForm');
const nameInput = document.getElementById('name');
const pwdInput = document.getElementById('password');
const nameError = document.getElementById('nameError');
const pwdError = document.getElementById('pwdError');
const welcome = document.getElementById('welcome');
// 表单提交事件
form.onsubmit = function(e) {
e.preventDefault(); // 阻止默认提交
// 重置提示
nameError.style.display = 'none';
pwdError.style.display = 'none';
welcome.style.display = 'none';
// 获取输入值
const username = nameInput.value;
const password = pwdInput.value;
let isValid = true;
// 简单验证
if (!username) {
nameError.style.display = 'block';
isValid = false;
}
if (!password) {
pwdError.textContent = '密码不能为空';
pwdError.style.display = 'block';
isValid = false;
} else if (password.length < 8) {
pwdError.textContent = '密码不少于8位';
pwdError.style.display = 'block';
isValid = false;
}
// 验证通过后直接拼接字符串回显
if (isValid) {
welcome.innerHTML = '欢迎 ' + username; // 用innerHTML而非textContent,便于XSS注入测试
welcome.style.display = 'block';
}
}
</script>
</body>
</html>
当用户点击提交按钮后,程序会检查用户的输入是否满足要求,如果用户名或密码为空,则在对应位置给出错误提示;若密码长度不满足(至少八位),则弹出弹框给出错误信息;若所有条件均满足,则回显用户登录信息,如下图所示。



4.2.2利用回显用户名注入攻击
可以看到在上面显示的代码中,并未对用户的输入进行安全检查或转义处理,在验证通过后,使用了innerHTML将用户名直接拼接到页面中。
welcome.innerHTML = '欢迎 ' + username;
innerHTML会将拼接的内容作为HTML解析并执行,而不是作为纯文本展示。当用户输入包含HTML或JavaScript代码的内容时,这些代码会被浏览器解析并执行,从而造成 XSS 攻击。
(1)注入html
在用户名输入框中输入<h1 style="color:red">20232423注入html</h1>,如果其余字段满足验证逻辑,“20232423注入html”(红色的)会被回显到页面,如下图所示。可以看到原本绿色的回显内容,现在变成了红色加大版的“20232423注入html”,说明注入html成功。

(2)注入JavaScript
在用户名输入框中输入<img src="x" onerror="alert('20232423你的账号已被劫持')">,这个代码的作用是将将图片源设置为无效地址"x",当图片加载失败时触发JavaScript代码,因为"x"不是有效图片地址,所以在密码输入满足要求时,图片必定加载失败,从而必定触发onerror事件执行其中的JavaScript代码——弹出警告框,显示20232423你的账号已被劫持。如下图所示,注入JavaScript成功。

4.3 Web后端:MySQL基础
4.3.1分析文件基本信息
在kali中使用命令systemctl start mysql启动kali虚拟机自带的MySQL,通过命令systemctl status mysql可查看服务的启用情况。如下图所示

在输入mysql可进入数据库,随后进行数据库创建,用户创建、授权,建表、插入和查看数据等操作。具体代码如下,操作过程如下图。
CREATE DATABASE db20232423; //创建数据库
SHOW DATABASES; //查看所有数据库
USE db20232423; //进入数据库
CREATE USER 'zt' IDENTIFIED BY 'user@zt'; //创建新用户zt
GRANT ALL PRIVILEGES ON db20232423.* TO 'zt'; //授予用户所有权限
FLUSH PRIVILEGES; //刷新权限
ALTER USER 'zt' IDENTIFIED BY 'user@2423'; //修改用户密码
CREATE TABLE user (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50) NOT NULL,
password VARCHAR(100) NOT NULL
);//建表
INSERT INTO user VALUES (1,'zhangtan','20232423'),(2,'zt','zt232423'); //插入数据
SELECT * FROM user; //查看表中所有内容


4.4 使用PHP连接数据库
在保持上面网页的登录功能的基础上,这部分加上的功能是:查询输入的用户是否存在于数据库中,如果存在密码是否匹配,最终根据结果回显成功信息或者提示失败信息。代码如下,运行结果如下图:
<?php
// 数据库连接配置
$servername = "localhost";
$dbuser = "zt";
$dbpass = "user@2423";
$dbname = "db20232423";
// 创建连接
$conn = new mysqli($servername, $dbuser, $dbpass, $dbname);
if ($conn->connect_error) {
die("数据库连接失败: " . $conn->connect_error);
}
$nameError = "";
$pwdError = "";
$welcome = "";
if ($_SERVER["REQUEST_METHOD"] == "POST") {
$username = $_POST['name'];
$password = $_POST['password'];
$isValid = true;
// 基础验证
if (empty($username)) {
$nameError = "用户名不能为空";
$isValid = false;
}
if (empty($password)) {
$pwdError = "密码不能为空";
$isValid = false;
}
if ($isValid) {
// 1. 先查询用户是否存在(存在SQL注入风险)
$userSql = "SELECT * FROM user WHERE name='$username'";
$userResult = $conn->query($userSql);
if ($userResult->num_rows == 0) {
// 用户不存在
$nameError = "用户名不存在";
} else {
// 2. 用户存在时验证密码(存在SQL注入风险)
$pwdSql = "SELECT * FROM user WHERE name='$username' AND password='$password'";
$pwdResult = $conn->query($pwdSql);
if ($pwdResult->num_rows > 0) {
// 登录成功(存在XSS风险)
$welcome = "欢迎," . $username;
} else {
// 密码错误
$pwdError = "密码错误";
}
}
}
$conn->close();
}
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>攻击测试页面</title>
<style>
.error { color: red; }
.welcome { color: green; margin-top: 10px; }
form { margin: 20px; }
input { margin: 5px 0; }
</style>
</head>
<body>
<h1>用户登录</h1>
<form method="post" action="">
用户名: <input type="text" name="name" value="<?php echo $_POST['name'] ?? ''; ?>">
<span class="error"><?php echo $nameError; ?></span><br>
密码: <input type="password" name="password">
<span class="error"><?php echo $pwdError; ?></span><br><br>
<input type="submit" value="登录">
<div class="welcome"><?php echo $welcome; ?></div>
</form>
</body>
</html>



4.5 SQL注入、XSS攻击测试
4.5.1 SQL注入
以上编写的PHP代码中直接将用户输入的用户名和密码拼接进SQL查询语句,未做任何过滤或参数化处理,导致攻击者可构造恶意输入篡改SQL逻辑。
在已知用户名的情况下,可在用户名后面或者密码框中注入' OR '1'='1实现成功登陆。
情况一,如下图,在已知用户名后面注入' OR '1'='1,然后密码随便输入(不满足8位的要求都可以),点击登录,发现回显成功登录信息。
这是因为当在用户名输入框输入zt' OR '1'='1拼接后的SQL会变成:SELECT * FROM users WHERE username = 'zt' OR '1'='1' AND password = '密码';
SQL中AND的优先级高于OR,所以实际执行逻辑是:(username = 'zt') OR (('1'='1') AND (password = 'abc'));
由于'1'='1恒为TRUE,整个条件简化为:(username = 'zt') OR (TRUE AND password = 'abc');
最终等价于:username = 'zt' OR password = 'abc'
所以只要满足用户名正确或者密码正确其中一个条件,就可以成功登录。

情况二,如下图,已知用户名,在密码框注入' OR '1'='1,点击登录,发现回显成功登录信息。
这是因为输入后,拼接后的SQL变为:SELECT * FROM users WHERE username = 'zt' AND password = '' OR '1'='1';
对 SQL 的执行逻辑进行拆解,变为:(username = 'zt' AND password = '') OR ('1'='1');
外层逻辑是OR连接两个条件,只要其中一个为TRUE,整个查询条件就为TRUE;第二个条件'1'='1'恒为TRUE,因此无论前半部分是否匹配,整个WHERE条件最终结果都是TRUE;所以能成功登录。

即使不知合法账号,攻击者也可在用户名与密码栏中均输入' OR '1'='1这类永真条件,从而绕过整个身份验证逻辑,实现非法登录。如下图。

4.5.2 XSS攻击
代码在输出用户输入的用户名时未做转义处理,导致跨站脚本攻击风险。登录成功后,代码直接输出用户名,若攻击者输入的用户名包含恶意脚本,该脚本会被直接嵌入到页面HTML中并执行,可能导致窃取Cookie、会话劫持等攻击。
在用户名输入框内输入<img src=x onerror=alert('20232423XSS成功')>,并在密码框输入任意值提交。这里的JavaScript代码的原理和上面的一样,当用户提交包含JavaScript代码的用户名时,代码中对输入的original_username变量未进行任何转义处理,直接将其拼接进$welcome变量中,导致用户输入的恶意代码被直接执行。如下图。

4.6 安装DVWA平台,并完成SQL注入、XSS、CSRF攻击
安装DVWA平台,参考链接(https://blog.csdn.net/qq_64290057/article/details/127539229)
4.6.1 SQL注入
输入1+2+3,输出也是1+2+3,判定是字符型注入

输入'1 or 1=1'直接报错500,所以存在sql注入

使用1' union select password,user from users #获取users 表中所有用户的用户名(user)和密码(password),如下图

4.6.2 XSS攻击
情况一:XSS(DOM)
先随机选择语言,然后点击select,可以看到URL处出现了变化“?default=English”

再将网址处的English替换为<script>alert(20232423)</script>,就可以看到如下图所示的弹窗。

情况二:XSS(reflected)
直接在输入框中输入<script>alert(20232423)</script>,点击submit可以得到如下图所示的弹窗。


情况三:XSS(stored)
Name中随机输入内容,然后在Massage中输入<script>alert(20232423)</script>,点击Sign Guestbook,可以看到弹窗。


4.6.3 CSRF攻击
首先在输入框中输入两次一样的密码123456,可以在点击change后的URL处看到我输入的密码“http://127.0.0.1/DVWA/vulnerabilities/csrf/?password_new=123456&password_conf=123456&Change=Change#”

如果输入的两次密码不一样,页面会提示密码不匹配,修改密码失败。然后在URL中也会显示出两次输入的密码内容,可以看到第一次输入的是20232423,第二次输入的是zhangtan。


现在在URL中将后面的“zhangtan”修改为“20232423”,即让前后两次输入的密码一样,回车之后会发现界面显示密码修改成功。攻击成功。

五、问题及解决
问题:php文件写好之后,无法打开,错误如下图

分析:Apache服务器没有权限读取或打开/var/www/html/lg.php文件
解决:执行以下命令,确保文件对www-data用户(Apache默认运行用户)有可读权限。然后运行php网页,就发现可以正常打开了。
// 给文件添加读取权限(所有用户可读取)
sudo chmod 644 /var/www/html/lg.php
// 确保文件的所有者或所属组包含www-data(Apache运行用户)
sudo chown www-data:www-data /var/www/html/lg.php
六、学习感悟
通过这次实验,我完整地体验了从搭建Web环境到基础的前后端开发,再到安全漏洞实践的全过程。
通过编写带有漏洞的html代码,我深入理解了该如何从代码层面避免基础的SQL注入和XSS攻击。
在DVWA上实践时,我看到了更多类型的攻击:XSS分好几种,CSRF甚至不用窃取密码就能冒充用户操作。这让我明白,漏洞不止一种,攻击方式也很多样。
整体来说,这次实验让我从“怎么实现功能”转向了“怎么避免被攻击”。自己动手尝试攻击,比只看理论更清楚漏洞是怎么产生的,也更明白以后写代码时该注意什么。安全不是最后才加的,而是从一开始就要考虑的。
浙公网安备 33010602011771号