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攻击。
2.实验过程
2.1Web前端HTML
2.1.1正常安装、启停Apache
1. 安装Apache
在kali中输入
apt install apache2
2. 启动Apache服务
在kali中输入
systemctl start apache2
停止apache服务则输入systemctl stop apache2
3. 配置防火墙
在kali中输入
ufw allow 'Apache'

4. 验证安装
打开kali自带的浏览器输入
http://localhost
看到以下Apache的欢迎页面,说明Apache Web服务器安装成功

2.1.2理解HTML,理解表单,理解GET与POST方法
- 理解html
HTML(超文本标记语言,HyperText Markup Language)是一种用于创建和设计网页的标记语言。它通过一系列标签将网络上的文档格式统一,使分散的Internet资源连接为一个逻辑整体。HTML文本由HTML命令组成,这些命令可以描述文字、图形、动画、声音、表格、链接等内容。 - 理解表单
HTML 表单用于收集用户的输入信息。 HTML 表单表示文档中的一个区域,此区域包含交互控件,将用户收集到的信息发送到== Web 服务器==。HTML 表单通常包含各种输入字段、复选框、单选按钮、下拉列表等元素。- 基本结构
- 表单定义:
<form>标签包裹,action(提交 URL)和method(提交方式) - 组成部分:表单控件、
<label>标签、<button>提交按钮
- 表单定义:
- 表单控件
- 单行文本输入框:
type="text",支持placeholder - 密码输入框:
type="password",支持required - 文本域:
<textarea>,含rows/cols - 单选按钮:
type="radio",同name互斥 - 复选框:
type="checkbox",同name为一组 - 下拉列表:
<select>+<option> - 文件上传:
type="file",支持accept限制类型 - 提交按钮:
type="submit"
- 单行文本输入框:
- 表单验证
- 前端验证:HTML5 内置属性(required/pattern/min/max)、JavaScript 验证
- 后端验证:校验数据格式、防注入攻击,不可替代前端验证
- 表单安全
- 防 XSS:过滤转义用户输入(替换&/</>等字符)
- 防 CSRF:添加 CSRF Token 验证
- 敏感数据传输:使用 HTTPS
- 基本结构
- 理解GET与POST方法
在 HTTP 协议中,GET 和 POST 是两种最常用的请求方法。它们在使用场景、数据传输方式、安全性等方面存在显著差异。- 基本定义
- GET 请求:用于从服务器获取数据。请求参数附加在 URL 后面,多个参数之间用 & 连接。
- POST 请求:用于向服务器提交数据。请求参数放在 HTTP 消息主体中,不显示在 URL 中。
- 数据传输方式
- GET 请求:参数直接附加在 URL 后面,格式为 ?name1=value1&name2=value2。由于 URL 长度限制,GET 请求传输的数据量较小,通常不超过 2048 个字符。
- POST 请求:参数放在 HTTP 消息主体中,格式为 name1=value1&name2=value2。POST 请求对数据长度没有限制,可以传输大量数据。
- 安全性
- GET 请求:由于参数包含在 URL 中,数据对所有人可见,安全性较低。不适合传输敏感信息。
- POST 请求:参数放在消息主体中,不会显示在 URL 中,安全性较高。
- 基本定义
2.1.3编写一个含有表单的HTML
1.进入进入/var/www/html/路径
在kali中输入
cd /var/www/html/
2.接着,创建并编辑HTML文件
在kali中输入
vim form20232324lzm.html
3.编写html(POST提交方式)
- 我编写了一个基础的 HTML 登录页面,主要实现用户登录表单的展示与提交功能。页面结构包含文档声明、头部元信息(编码、视口适配)和标题,主体部分展示 “登录” 标题及登录表单;
- 表单通过POST方法将用户名、密码数据提交到login.php处理,输入框绑定label提升可用性,且通过required实现前端必填验证;
<!DOCTYPE html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>登录页面</title>
</head>
<body>
<h2>登录</h2>
<form action="login.php" method="POST">
<label for="username">用户名:</label>
<input type="text" id="username" name="username" required><br><br>
<label for="password">密码:</label>
<input type="password" id="password" name="password" required><br><br>
<input type="submit" value="登录">
</form>
</body>
</html>

因为我使用的是POST方式提交,所以网址不会出现用户名及密码,如下图所示;

4.编写html(GET提交方式)
代码同上,只是将method="POST",改为了method="GET",我们可以在网址里面直接看见用户和明文密码,结果如下:

2.2Web前端javascipt
2.2.1理解JavaScript的基本功能、DOM
1.javascript基本功能
- JavaScript是一种轻量级、解释型的编程语言,广泛应用于网页开发中,主要用于增强网页的交互性和动态性。
- 它与HTML和CSS共同协作,HTML负责定义网页的内容结构,CSS处理样式和布局,而JavaScript则控制网页的行为和交互。
- 开发者可以利用JavaScript进行事件处理、表单验证、动画创建等多种功能。JavaScript可以实现复杂的功能,如实时内容更新、交互式地图和动画等。
2.什么是DOM
- 文档对象模型(DOM) 是 HTML、XML、SVG 等文档的编程接口,它将文档解析为树状结构(DOM 树),每个节点都是一个对象,允许脚本动态访问和修改文档的结构、样式和内容。
- DOM 与 JavaScript 紧密结合,但它本身是独立于语言的 Web API,也可用 Python、Java 等语言实现。
- 核心结构 DOM 树的根节点是 Document 对象,表示整个文档;Element 节点表示 HTML 标签;Text 节点表示文本内容;Attr 节点表示属性。节点之间通过父子、兄弟关系连接,形成可遍历的层级结构。
2.2.2编写JavaScript验证用户名、密码的规则
对form20232324lzm.html进行了修改。用户点击 “登录” 按钮→触发表单onsubmit事件→执行validateForm函数→依次校验用户名、密码→验证通过则回显欢迎语,验证失败则弹窗提示→始终阻止表单默认提交(避免页面刷新)。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>登录页面</title>
<script>
// 验证表单
function validateForm() {
var username = document.getElementById("username").value;
var password = document.getElementById("password").value;
// 验证用户名不能为空
if (username == "") {
alert("用户名不能为空!");
return false;
}
// 验证密码不能为空,且密码至少为6位
if (password == "") {
alert("密码不能为空!");
return false;
} else if (password.length < 6) {
alert("密码至少为6位!");
return false;
}
// 成功验证后回显用户名
document.getElementById("welcomeMessage").innerHTML = "欢迎 " + username;
return false; // 防止页面刷新
}
</script>
</head>
<body>
<h2>登录</h2>
<form action="login.php" method="POST" onsubmit="return validateForm()">
<label for="username">用户名:</label>
<input type="text" id="username" name="username" required><br><br>
<label for="password">密码:</label>
<input type="password" id="password" name="password" required><br><br>
<input type="submit" value="登录">
</form>
<!-- 用户名回显区域 -->
<div id="welcomeMessage"></div>
</body>
</html>
输入符合要求的用户名和密码,点击登录,下方会显示"欢迎20232324lzm"

而输入不符合规则的密码,就会弹出以下提示:

2.2.3尝试注入攻击:利用回显用户名注入HTML及JavaScript
攻击成功的核心原理是:
代码未对用户输入的用户名进行 HTML/JS 转义处理,直接将输入内容作为 HTML 内容插入页面,浏览器会将注入的 HTML 标签或 JavaScript 代码当作合法页面代码解析执行。
在kali中输入
<b>恶意用户名</b>
<b>:用于强调文本的元素。浏览器对该内容进行解析执行,“恶意用户名”显示以粗体形式在页面中。

2.3Web后端:mysql数据库操作
2.3.1安装、启动mysql
kali自带mysql,在kali中输入以下语句:
systemctl status mysql
systemctl start mysql

在kali中输入
mysql,进入mysql,然后就可进行数据库相关操作了

2.3.2建库、创建用户、修改密码、建表
1.建库
在kali中输入以下语句
CREATE DATABASE 20232324LZM;建立一个名为“20232324LZM”的数据库SHOW DATABASES;查看该数据库详细信息

2.创建用户
在kali中输入以下语句
CREATE USER '20232324lzm'@'localhost' IDENTIFIED BY 'password123';建立一个名为“20232324lzm”的用户名,设置其初始密码为“password123”GRANT ALL PRIVILEGES ON 20232324LZM.* TO '20232324lzm'@'localhost';将对20232324LZM数据库的所有操作权限都赋予给20232324lzm用户FLUSH PRIVILEGES;刷新权限使其生效

3.修改密码
在kali中输入以下语句
ALTER USER '20232324lzm'@'localhost' IDENTIFIED BY 'new_password123';20232324lzm用户的登录密码改为了“new_password123”FLUSH PRIVILEGES;刷新权限使其生效
我后面把密码还是改回password123,所有后面php文件中的密码也是password123
4.建表
在kali中输入以下语句
USE 20232324LZM;选择要操作的数据库CREATE TABLE lzm (
id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50) NOT NULL,
password VARCHAR(100) NOT NULL
);创建一个名为lzm的表,包含 id、username和 password。SHOW TABLES;显示所有的表DESCRIBE lzm;查看lzm表信息

2.4Web后端:编写PHP网页,连接数据库,进行用户认证
2.4.1编写PHP网页,连接数据库
1.进入/var/www/html/路径中
在kali中
cd /var/www/html/
2.创建并编辑20232324login.php
在kali中
vim 20232324login.php
其关键逻辑如下:
- 配置连接信息:定义
$servername(数据库服务器地址,本地为localhost)、$username(数据库用户名)、$password(数据库密码)、$dbname(要连接的数据库名),需按实际环境填写。 - 创建连接对象:通过
new mysqli($servername, $username, $password, $dbname)实例化 mysqli类,建立与 MariaDB/MySQL 数据库的连接,返回的$conn为连接句柄。 - 检查连接状态:通过
$conn->connect_error判断连接是否失败,若失败则输出错误信息(不中断脚本执行)。 - 关闭连接:脚本末尾调用
$conn->close()关闭数据库连接,释放资源。
<?php
// 开启错误显示(方便调试)
error_reporting(E_ALL);
ini_set('display_errors', 1);
// 数据库连接信息(按你的实际配置填写)
$servername = "localhost";
$username = "20232324lzm"; // 你的数据库用户名
$password = "password123"; // 你的数据库密码
$dbname = "20232324LZM"; // 你的数据库名
// 创建数据库连接
$conn = new mysqli($servername, $username, $password, $dbname);
// 检查连接(连接失败也不影响XSS测试,继续执行)
if ($conn->connect_error) {
echo "连接提示:" . $conn->connect_error . "<br>";
}
// 接收POST提交的用户名和密码
if ($_SERVER["REQUEST_METHOD"] === "POST") {
$user = $_POST['username']; // 正确接收用户名
$pass = $_POST['password'];
// 简化逻辑:只要用户名不为空,就直接输出(跳过复杂SQL验证,确保payload能被渲染)
if (!empty($user)) {
// 关键:直接输出用户名,不做任何过滤(去掉htmlspecialchars)
echo "<h2>登录成功</h2>";
echo "<p>欢迎用户:<strong>" . $user . "</strong></p>"; // 修正变量名:$user而非$use
echo "<a href='form20222409wqb.html'>返回登录页</a>";
} else {
echo "<h2>登录失败</h2>";
echo "<p>用户名不能为空!</p>";
}
}
// 关闭连接
$conn->close();
?>
3.修改form20232324lzm.html文件
相较于2.2.2的html文件,我作出了以下修改:
- 表单提交逻辑调整:
validateForm函数最后返回true(2.2.2返回false),目的是让前端验证通过后,表单能正常提交到后端 PHP 页面(而非阻止提交),实现前后端交互。 - 表单action属性修改:
从login.php改为20232324login.php,目的是指定正确的后端处理脚本路径,匹配实际的 PHP 文件名。 - 移除input标签的required属性:
2.2.2中用户名 / 密码输入框有required(HTML5 原生必填校验),删除该属性,目的是统一由 JS 脚本完成校验,避免原生校验与 JS 校验冲突。 - 删除前端回显相关内容:
移除<div id="welcomeMessage">及 JS 中前端回显用户名的代码,目的是改为由后端 PHP 页面展示欢迎信息(提交后跳转至 PHP 页面),前端无需保留无效的回显元素。 - JS 中相等判断优化:
将==改为===(严格相等),目的是避免类型隐式转换导致的校验逻辑错误,提升验证准确性。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>登录页面</title>
<script>
// 验证表单
function validateForm() {
var username = document.getElementById("username").value;
var password = document.getElementById("password").value;
// 验证用户名不能为空
if (username === "") {
alert("用户名不能为空!");
return false;
}
// 验证密码不能为空,且密码至少为6位
if (password === "") {
alert("密码不能为空!");
return false;
} else if (password.length < 6) {
alert("密码至少为6位!");
return false;
}
// 验证通过后,form会正常提交到PHP页面(不用再return false,否则会阻止提交)
return true;
}
</script>
</head>
<body>
<h2>登录</h2>
<!-- 修复onsubmit,调用验证函数 -->
<form action="20232324login.php" method="POST" onsubmit="return validateForm()">
<label for="username">用户名:</label>
<input type="text" id="username" name="username"><br><br>
<label for="password">密码:</label>
<input type="password" id="password" name="password"><br><br>
<input type="submit" value="登录">
</form>
<!-- 这个div在当前页面,提交后会跳转,所以可以删掉(欢迎信息由PHP页面显示) -->
<!-- <div id="welcomeMessage"></div> -->
</body>
</html>
4.创建用户数据
在mysql中输入
INSERT INTO wqb (username, password) VALUES ('20232324test', 'lzmtest');
创建了一个名为“20232324test”,密码为“lzmtest”的用户

2.4.2进行用户认证
1.确保form20232324lzm.html 和 20232324login.php 文件放置在 /var/www/html/ 目录下
2.在浏览器中输入 http://localhost/form20232324lzm.html
输入正确用户名及密码,结果如下图所示:

输入错误密码,结果如下图所示:

2.5最简单的SQL注入,XSS攻击测试
2.5.1SQL注入攻击测试
1.原理:
SQL注入是一种常见的网络攻击手段,攻击者通过在输入字段中插入恶意SQL代码,操控数据库执行未经授权的操作。以下是SQL注入攻击的主要流程:
- 攻击者首先识别应用程序中可能存在SQL注入漏洞的输入点,例如登录表单、搜索框或URL参数等。
- 在识别输入点后,攻击者构造恶意SQL语句。例如,通过输入' OR '1'='1,可以绕过身份验证,获取敏感数据。
- 数据库接收到恶意SQL语句后,直接执行这些代码。攻击者可以利用此漏洞获取数据库信息、修改数据,甚至删除表结构。
- 执行后的结果通常会返回给攻击者,从而泄露敏感信息或导致数据库破坏。
2.找到SQL注入漏洞
在php文件中,我么可以找到以下代码,这段 SQL 语句直接将用户输入的\(user和\)pass拼接进 SQL 字符串,未对用户输入做任何过滤或转义处理。
$sql = "SELECT * FROM wqb WHERE username='$user' AND password='$pass'";
$result = $conn->query($sql);
3.构造和实行攻击
在用户名输入框中,输入
' OR '1'='1' --

原来的SQL语句就会变成
SELECT * FROM wqb WHERE username= ' ' OR '1'='1' -- ' AND password='anypassword';
username= ' ':构造空字符串的用户名匹配条件
OR '1'='1':'1'='1'是永真表达式,结合OR后,无论前面的用户名条件是否成立,整个WHERE子句的条件都会变为 “真”;
--:SQL 的单行注释符,将后面的' AND password='anypassword';全部注释掉,使原本的密码验证逻辑完全失效;
攻击成功如下图所示:

2.5.2跨站脚本(XSS)攻击测试
1.原理
XSS是一种常见的Web安全漏洞,攻击者通过向网页注入恶意脚本,使其在其他用户的浏览器中执行,从而窃取敏感信息、劫持会话或执行未授权操作。常见的恶意代码多为 JavaScript,但也可能包括 HTML、Flash、VBScript 等。
2.类型
- 反射型(非持久化) 恶意代码通过URL参数传递,服务器原样返回到页面中,用户点击恶意链接即可触发。常见于搜索框、错误提示等。
- 存储型(持久化) 恶意代码被存储在数据库或文件中,所有访问该页面的用户都会触发攻击。常见于留言板、评论区。
- DOM型 基于浏览器端DOM解析的漏洞,恶意代码不经过服务器,直接在客户端执行,常见于前端JavaScript对URL参数的不安全处理。
3.找到漏洞
后端未对用户输入的内容进行 HTML 转义处理,直接将包含<script>标签的输入内容嵌入到页面 HTML 中;浏览器解析页面时,会将<script>标签识别为合法的 JavaScript 代码块并执行其中的alert()语句,从而触发 XSS 攻击。
4.构造和实行攻击
在用户框输入
<script>alert('XSS攻击成功!');</script>

攻击成功如下图所示:

2.6安装DVWA或WebGoat平台,并完成SQL注入、XSS、CSRF攻击
2.6.1下载并配置DVWA
1.下载dvwa
在kali自带的浏览器中搜索https://github.com/digininja/DVWA,找到zip文件下载至本地(往下翻翻就能找到)

2.解压DVWA-master,配置 config 文件
- 找到dvwa-master → config ,将 config.inc.php.dist 的 dist 后缀去掉

- 然后双击打开 config.inc.php,修改第 20、21 行的值:
$_DVWA[ 'db_user' ] = 'dvwa';
$_DVWA[ 'db_password' ] = 'dvwa';
- 赋予dvwa-master权限,并将dvwa-master移动到/var/www/html目录下
在kali中输入
chmod -R 777 /root/下载/DVWA-master
在kali中输入mv /root/下载/DVWA-master /var/www/html

3.建立数据库
- 启动并进入mysql
在kali中输入
service mysql start
在kali中输入mysql -u root -p,没有密码,直接回车就可进入
- 建表、建用户、设置密码、赋权,以下都是在mysql中操作
create user 'dvwa'@'localhost' identified by 'dvwa'; #创建用户名
grant all on *.* to 'dvwa'@'localhost'; #赋权
set password for 'dvwa'@'localhost' = password('dvwa'); #设置密码
exit #退出mysql

4.访问dvwa
在kali中输入
service apache2 start启动apache2服务
在浏览器中搜索http://127.0.0.1/DVWA-master/login.php
默认用户名:admin,密码:password

2.6.2SQL注入
1.设置安全级别
点击左侧标签
DVWA security,将难度从impossible改为low,点击submit确认。
2.SQL Injection
原理在上面解释过
打开 DVWA 左侧菜单,选择
SQL Injection。
在用户名输入框中输入:' OR '1'='1' --
显示了所有用户的信息得到的结果如下图所示:

2.6.3XSS攻击
1.dom
- 观察界面,当选择不同的标签时,URL栏中的default也会发生变化
- default有可能是个传参点

- 传入xss代码
<script>alert(1)</script>

2.reflect
- 随机输入值

无论我们输入什么值,在页面中都会显示输入的信息,并且url的name传参值就是我们输入的值 - 对URL中的name传入 xss代码
<script>alert(1)</script>

3.stored
- 发现输入的内容被进行了存储

- 输入xss代码
<script>alert(1)</script>

2.6.4CSRF攻击
1.原理
跨站请求伪造(CSRF,Cross-Site Request Forgery) 是一种常见的网络攻击方式,攻击者利用用户已登录的身份,在受信任的网站上执行未经授权的恶意操作。其核心在于攻击者伪造用户请求,欺骗服务器信任并执行操作。
2.更改网站密码
- 网站的本意是让我们在网站里更改密码
- 我们更改的密码,可以直接在url栏看到,说明我们在网站上输入的信息是会在url栏这里进行一个传输执行

- 更改url的参数
http://127.0.0.1/dvwa/vulnerabilities/csrf/?password_new=20232324lzm&password_conf=20232324lzm&Change=Change#

3.测试
先输入原本的密码20232324

再输入url参数中设置的密码

3.问题及解决方案
- 问题1:建立完php后显示为空白页
- 问题1解决方案:在php文件代码开头,加入
error_reporting(E_ALL);和
ini_set('display_errors', 1);这两条语句。这样就可以找到其错误原因,其实就是数据库设置的密码和php文件中的密码没有设置成一样导致的。
Fatal error: Uncaught mysqli_sql_exception: Access denied for user '20232324lzm'@'localhost' (using password: YES) in /var/www/html/20232324login.php:10 Stack trace: #0 /var/www/html/20232324login.php(10): mysqli->__construct() #1 {main} thrown in /var/www/html/20232324login.php on line 10
4.学习感悟、思考等
在本次实验我上学期的web课程知识的理解加深了,比如Web前端html表单、JavaScript交互验证和Web后端数据库操作MySQL、编写 PHP 网页连接数据库并实现用户认证等等。
与此同时还让我认识到了许多web中的安全漏洞,SQL注入源于数据库查询的不安全拼接,XSS源于前端渲染的输入失控,CSRF源于身份验证机制的缺陷。这些实践打破了我的的片面认知,意识到安全是贯穿前后端、数据库全链路的工程。

浙公网安备 33010602011771号