20222412 2021-2022-2 《网络与系统攻防技术》实验八实验报告
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.1 Web前端HTML
2.1.1 Apache
- Apache HTTP Server是一个开放源码的网页服务器,Apache起初由伊利诺伊大学香槟分校的国家超级电脑应用中心(NCSA)开发,后来被开放源代码团体的成员不断地发展与完善。它因跨平台和安全性而被广泛使用,成为世界上最受欢迎的Web服务器端软件之一。Apache的特点包括快速、可靠以及可通过简单的API扩展。它可以将Perl/Python等解释器编译到服务器中,从而支持多种编程语言和应用程序。这使得Apache成为一个灵活且强大的工具,适用于从小型个人网站到大型企业级应用的各种场景。此外,Apache还具有丰富的模块和扩展功能,可以通过编译额外的模块来增强其性能和功能。
使用apt-get安装Apache服务。
systemctl start apache2 //开启Apache服务
systemctl status apache2 //查看Apache服务状态
可以看到Apache服务正常启动。再使用指令查看Apache占用的端口。
netstat -aptn //查看端口状态
如图,Apache服务使用的是端口80。
在浏览器上打开127.0.0.1(本机ip),可以看到Apache的默认网页,证明启动成功。
systemctl stop apache2 //关闭Apache服务
关闭Apache后,再次查看Apache服务状态,可以看到已经关闭。
2.1.2 编写一个含有表单的HTML
- HTML是一种用于创建网页的标准标记语言,全称为超文本标记语言。HTML是一种简单的标记语言,用于创建超文本文档,这些文档可以从一个平台移植到另一个平台。它通过一系列的标签来描述网页内容,并方便链接,从而形成一个有机的整体。HTML文件是带有格式标识符和超文本链接的内嵌代码的ASCII文本文件,通常以.html或.htm为后缀。
- HTML表单(Forms)是网页与用户交互的关键组成部分,它允许用户输入数据并将数据提交到服务器进行处理。HTML表单由元素定义,所有表单元素都必须放在标签内。元素有两个关键属性:action和method。action属性指定表单数据提交的目标URL,而method属性则指定提交数据的方式,常用的有GET和POST两种。
- GET和POST是HTTP协议中两种常见的请求方法,它们在数据传输方式、安全性以及数据量限制等方面存在区别。GET和POST各有其特点和适用场景。在实际开发中,应根据具体需求选择合适的请求方法。如果需要从服务器获取数据或进行查询操作,且数据量不大,可以选择GET方法;如果需要向服务器提交数据或进行修改操作,且数据量可能较大,应选择POST方法。
进入kali的网站目录下创建一个html文件
cd /var/www/html //进入kali的网站目录下
touch 20222412.html //创建一个html文件
将写好的代码写入该文件。该代码是一个简单的HTML表单示例,它包含文本输入框、单选按钮、复选框和提交按钮。这个表单可以用来收集用户的基本信息,并且使用CSS进行简单的样式设计,使表单看起来更美观。
使用浏览器打开刚才创建好的html文件。
可以看到,成功实现含有表单的html的编写。
2.2 Web前端javascipt
2.2.1 基本概念
-
JavaScript 是一种高级的、解释型的编程语言。它的设计初衷是为了在网页浏览器中实现动态交互功能,让网页从静态的展示转变为可以与用户进行交互的动态页面。随着互联网的飞速发展,JavaScript 也不断演进。从最初简单的表单验证和简单的特效,到如今构建复杂的单页应用程序(SPA)、服务器端应用(Node.js)等多种应用场景。
-
JavaScript的基本功能
-
动态内容操作:
-
修改HTML元素,可以通过获取页面中的元素,然后修改其属性来更新内容。
-
创建新的 HTML 元素,再通过
appendChild
等方法将其添加到页面中的指定位置。 -
删除现有元素:获取要删除的元素,然后通过其父元素调用
removeChild
方法来实现元素的删除。
-
-
事件处理:
-
添加事件监听器:使用
addEventListener
方法为 HTML 元素添加各种事件的监听器。 -
鼠标事件:像
click
(点击)、mouseover
(鼠标移入)、mouseout
(鼠标移出)等。 -
键盘事件:如
keydown
(按下键盘按键)、keyup
(松开键盘按键)等。
-
-
表单验证:
-
验证输入类型:可以检查表单输入框中的数据类型是否符合要求。
-
必填项验证:确保某些表单字段不能为空。
-
-
与服务器交互(AJAX):使用
XMLHttpRequest
对象或者更现代的fetch
API 来发送异步请求到服务器获取数据或者提交数据,而不用刷新整个页面。 -
数据操作:
-
算术运算:对于数字类型的数据,可以进行加、减、乘、除等基本算术运算。
-
逻辑运算:使用布尔值进行
&&
(与)、||
(或)、!
(非)等逻辑运算,常用于条件判断中。 -
字符串操作:可以拼接字符串、获取字符串长度、截取子字符串等。
-
数组操作:能对数组进行创建、添加元素(如
push
方法)、删除元素(如pop
方法)、遍历(如forEach
方法)等操作。 -
对象操作:可以创建对象、访问对象属性、修改对象属性、添加新的属性等。
-
-
-
DOM(Document Object Model)即文档对象模型,它是一个将 HTML 或 XML 文档表示为树状结构的编程接口。在这个模型中,整个文档被看作是一个由节点组成的树。节点可以是元素节点(如
<div>
、<p>
等 HTML 标签)、文本节点(标签内的文本内容)、属性节点(元素的属性,如<img src="image.jpg">
中的src
属性)等。 -
DOM 节点类型
- 元素节点:是构成 HTML 文档结构的主要部分,对应 HTML 标签。例如
<div>
、<a>
等。可以通过document.createElement()
方法创建新的元素节点。 - 文本节点:包含在元素节点内部的文本内容。可以通过节点的
textContent
属性来获取或修改文本节点的内容。 - 属性节点:表示元素的属性,如
<img src="image.jpg">
中的src
属性。可以通过getAttribute()
和setAttribute()
方法来获取和设置属性节点的值。
- 元素节点:是构成 HTML 文档结构的主要部分,对应 HTML 标签。例如
-
DOM 操作方法
- 获取节点
- 通过 ID 获取:使用
document.getElementById()
方法,这是获取单个元素最常用的方法之一。 - 通过标签名获取:
document.getElementsByTagName()
方法返回一个包含指定标签名的所有元素的 HTMLCollection。 - 通过类名获取:
document.getElementsByClassName()
方法返回一个包含指定类名的所有元素的 HTMLCollection。 - 通过 CSS 选择器获取(querySelector 和 querySelectorAll):
document.querySelector()
方法返回匹配指定 CSS 选择器的第一个元素,document.querySelectorAll()
返回匹配指定 CSS 选择器的所有元素。
- 通过 ID 获取:使用
- 创建和添加节点
- 创建节点:使用
document.createElement()
创建新的元素节点。 - 添加节点:可以通过
appendChild()
方法将新节点添加到指定节点的子节点列表末尾。
- 创建节点:使用
- 删除节点:通过
removeChild()
方法来删除节点。首先要获取要删除节点的父节点,然后调用父节点的removeChild()
方法并传入要删除的节点。;`。 - 修改节点内容和属性
- 修改内容:可以使用元素节点的
innerHTML
属性来修改元素包含的 HTML 内容,或者使用textContent
属性只修改纯文本内容。。 - 修改属性:通过
getAttribute()
和setAttribute()
方法来获取和修改属性,也可以直接通过元素节点的属性来修改。
- 修改内容:可以使用元素节点的
- 获取节点
2.2.2 编写JavaScript验证用户名、密码的规则。在用户点击登陆按钮后回显“欢迎+输入的用户名”
新增的JavaScript大致如下:
<script>function validateForm() {const name = document.getElementById('name').value;const email = document.getElementById('email').value;const password = document.getElementById('password').value;const messageDiv = document.getElementById('message');const nameRegex = /^[a-zA-Z\u4e00-\u9fa5]{2,15}$/; // 用户名只能包含字母和汉字,长度为2到15个字符const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; // 简单的邮箱格式验证const passwordRegex = /^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d]{6,}$/; // 密码必须包含字母和数字,且长度至少为6个字符if (!nameRegex.test(name)) {messageDiv.textContent = '用户名格式不正确';return;}if (!emailRegex.test(email)) {messageDiv.textContent = '电子邮件格式不正确';return;}if (!passwordRegex.tezst(password)) {messageDiv.textContent = '密码格式不正确';return;}messageDiv.textContent = `欢迎 ${name}`;}</script>
修改代码并保存。
再次打开html文件,并且尝试不按照规则输入,以密码必须包含字母和数字,且长度至少为6个字符为例,只输入5个字符。
再次修改密码使其达到标准,但是改变邮箱格式。
这次完全按照规则进行输入,可以看到,成功出现回显。
2.2.3 尝试注入攻击:利用回显用户名注入HTML及JavaScript
这里有一点要注意,一般希望通过回显用户名注入的方式实现攻击一定要将长度限制改一下,通常注入需要输入长文本才行,以及,现在通常会对输入字符进行限制,为了完成实验,我把用户名只能包含字母和汉字,这条规则直接删除。
还有注意回显所使用的函数,选择安全度高的函数可以有效的阻止注入攻击,但是为了完成实验,改为选用安全度较低的document.write
。我之前使用的安全度高,会阻止这样的注入攻击
20222412wyg<script>alert("你被攻击了!");</script> //注入JavaScript
20222412wyg<h1>你被攻击了!</h1> //注入HTML
2.3 Web后端:MySQL基础
2.3.1 启动MySQL
systemctl start mysql //启动mysql服务
systemctl status mysql //查看mysql服务状态
2.3.2 建库
登录数据库,默认情况下没有密码。
mysql -u root -p //登陆数据库
use mysql //开始使用mysql
create database 20222412_DB; //创建一个名为20222412_DB的数据库
2.3.3 创建用户
create user 'wuyanguo'@'%' IDENTIFIED BY '20222412';
//创建一个密码为20222412的用户,用户名是wuyanguo@%
GRANT ALL PRIVILEGES ON 20222412_DB.* TO 'wuyanguo'@'%';
//把数据库20222412_DB的所有权限都给用户wuyanguo@%
FLUSH PRIVILEGES; //刷新授权表,不刷新有可能导致权限无法及时更新
SHOW GRANTS FOR 'wuyanguo'@'%'; //查看用户权限
2.3.4 修改密码
ALTER USER 'wuyanguo'@'%' IDENTIFIED BY '123456'; //修改用户的密码
可以看到,修改后再次查看用户,发现密钥(虽然是加密值。但还是能看出变化)已经发生改变,证明修改成功。
2.3.5 建表
use 20222412_DB; //使用该数据库
SHOW TABLES; //查看当前表//新建表,设置结构,其中userID是主键
CREATE TABLE `userlogin` (`userID` int(4) NOT NULL,`userName` varchar(20) NOT NULL,`userPwd` varchar(20) NOT NULL,PRIMARY KEY (`userID`)
);//插入数据
INSERT INTO `userlogin` (`userID`, `userName`, `userPwd`) VALUES
(1, '张三', '333'),
(2, '李四', '444'),
(3, '王五', '555');//表结构
SHOW TABLES;
SELECT * FROM userlogin;
2.4 Web后端:编写PHP网页
2.4.1 编写PHP功能文件
<?php
// 设置数据库服务器的名称
$servername = "localhost";
// 设置连接数据库的用户名
$username = "wuyanguo";
// 设置连接数据库的密码
$password = "123456";
// 设置要连接的数据库名
$dbname = "20222412_DB";// 使用mysqli创建一个新的数据库连接
$conn = new mysqli($servername, $username, $password, $dbname);// 检查连接是否成功
if ($conn->connect_error) {// 如果连接失败,输出错误信息并停止脚本执行die("连接数据库失败: ". $conn->connect_error);
}// 对从POST请求获取的用户输入进行预处理(这里简单使用mysqli_real_escape_string来转义特殊字符,防止SQL注入)
$name = mysqli_real_escape_string($conn, $_POST['name']?? '');
$password = mysqli_real_escape_string($conn, $_POST['password']?? '');// 创建一个SQL查询语句,用于从userlogin表中查找与给定用户名(这里用的是name字段,你可根据实际表结构调整)和密码匹配的用户
$sql = "SELECT * FROM userlogin WHERE userName = '$name' AND userPwd = '$password'";// 执行SQL查询并获取结果
$result = $conn->query($sql);// 检查查询结果中的行数是否大于0,即是否找到了匹配的用户
if ($result->num_rows > 0) {// 如果找到了匹配的用户,输出登录成功的消息echo "欢迎! 登陆成功!";
} else {// 如果没有找到匹配的用户,输出用户名或密码错误的消息echo "用户名或密码错误!";
}// 关闭数据库连接
$conn->close();
?>
2.4.2 使用PHP脚本处理登陆验证操作
将表单中的action字段指向新建的php文件即可。
这里有几点需要注意,PHP脚本进行登陆验证时注意一定要使用你存储数据时使用的数据库,例如此处我是做了一个登陆验证系统,验证是从mysql数据库中读取数据实现该项功能,所以连接数据库的参数十分重要,并且使用的数据库表内的数据一定要存登陆相关的信息,这里我就存了用户名以及密码(就是2.3创建的表内数据,张三、李四、王五.......)。
还有就是在设置action字段时,指向路径最好使用尽量精确的路径,我使用的就是“localhost/20222412.php”,很多人直接使用“20222412.php”就能成功实现功能,但是不知道为啥我的不一样,出现该问题的原因是,浏览器会根据当前 HTML 文件的位置来寻找这个 PHP 文件。如果 HTML 文件和 PHP 文件的相对位置没有被服务器正确解析,就可能出现无法正确访问 PHP 文件的情况。localhost代表本地服务器,浏览器会向本地服务器的根目录去请求20222412.php文件。这种方式明确地告诉浏览器从服务器的根目录开始查找文件,在一些服务器配置场景下,这样的请求更容易被正确解析。
2.4.3 验证登陆
首先,使用正确的账号登陆,以张三,333,为例。
如果,我修改密码,没有使用数据库中存储的正确密码,就会回显错误,如下。
2.5 SQL注入,XSS攻击
2.5.1 SQL注入
原始的查询意图是通过用户名和密码来查找匹配的用户记录。但是注入后的语句,由于or 1 = 1
这个条件,使得WHERE
子句的条件基本上总是成立。因为只要1 = 1
这个条件满足(这是一个恒等式),就会返回所有记录(假设表中有数据)。数据库中有用户表userlogin
,包含字段id
、userName
、userPwd
,正常情况下,只有当输入的用户名和密码与数据库中存储的某一行记录完全匹配时,才会返回这一行记录。但是注入了'or 1 = 1 #
后,就会忽略原本正确的用户名和密码匹配条件,而返回所有记录,从而可能绕过登录验证等安全机制。
'or 1=1 #
可以看到,即使我输入的用户名以及密码没有,也是能够成功登陆,绕过验证。
2.5.2 XSS攻击
<script>alert("20222412")</script>
可以看到成功注入。
2.6 DVWA或WebGoat平台
(1)SQL注入
先使用以下注入内容。
' or 1=1; #
可以看到,成功实现sql注入,并且还能获取到数据库中表内的所有数据。
为了进一步获取更多信息,可以尝试增加获取数据库信息的sql注入语句。
' or 1=1 union select version(),database(); #
可以看到,通过使用union,我们还获取到了数据库版本号和数据库名。
(2)XSS攻击(DOM型)
可以看到,如图所示,只能选择语言,没有输入文本的地方,但是测试发现,选择语言后,网站的url发生变化,出现了default=English。
由此,猜测该网页是使用GET传递参数,于是,我们可以直接改变url,在其后面直接添加注入语句。
<script>alert("20222412")</script>
可以看到成功弹窗。
3.问题及解决方案
- 问题1:编写js代码,实现js注入攻击时,无法实现。
- 问题1解决方案:查看js注入的代码段,我最开始使用的是
messageDiv.textContent
函数,该函数阻止启动脚本,无法将用户输入作为代码使用,改为不阻止安全性低的document.write
函数即可。 - 问题2:在编写php脚本时,使用html启动脚本,会直接跳转到代码页,而不是从网页上启动脚本。
- 问题2解决方案:出现这个问题是由于配置的apache可能无法正确的解析php,目前我暂时还没有找到好的解决办法,但是可以直接使用浏览器打开php网页,即可正确解析,所以只要在html上将php指向地址改为“http://localhost/20222412.php”就可以了。
4.学习感悟、思考等
实验让我意识到,Web开发不仅仅是编写代码那么简单,它涉及HTML、JavaScript等前端技术,以及MySQL、PHP等后端技术。每一部分都有其独特的价值和复杂性,需要深入学习并理解其工作原理。同时,我也认识到,这些技术之间是相互关联、相互支持的,只有掌握了它们之间的协同工作,才能构建出高效、安全的Web应用。
在实验中,我深刻体会到了Web安全的重要性。无论是前端还是后端,都存在被攻击的风险。通过尝试注入攻击,我意识到即使是最简单的漏洞也可能导致严重的安全问题。因此,在开发过程中,必须时刻保持警惕,采取有效的安全措施,如输入验证、编码转换等,以确保应用的安全性。
通过SQL注入、XSS攻击测试以及攻防实践平台的体验,我对Web安全有了更加深刻的认识。我意识到,Web安全不仅关乎技术层面的问题,更关乎用户的数据安全和隐私保护。因此,在未来的开发和工作中,我将更加注重安全问题的防范和解决,为用户提供更加安全、可靠的Web服务。