Web安全实践
- 1.实验内容
- 2.实验过程
- 2.1 Web前端HTML
- 2.1.1 正常安装、启停Apache
- 2.1.2 编写一个含有表单的HTML
- 2.1.2.1 基础知识
- 2.1.2.2 实践
- 2.2 Web前端javascipt
- 2.2.1 基础知识
- 2.2.2 实践
- 2.3 Web后端:MySQL基础
- 2.3.1 正常安装、启动MySQL
- 2.3.2 创建用户、修改密码
- 2.3.3 建库、建表
- 2.4 Web后端:编写PHP网页,连接数据库,进行用户认证
- 2.5 最简单的SQL注入,XSS攻击测试
- 2.6 安装Webgoat或类似平台,并完成SQL注入、XSS、CSRF攻击
- 2.6.1 下载安装Webgoat
- 2.6.2 SQL注入
- 2.6.3 XSS攻击
- 2.6.4 CSRF攻击
- 3.问题及解决方案
- 4.学习感悟、思考等
- 参考资料
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) 安装Webgoat或类似平台,并完成SQL注入、XSS、CSRF攻击。
2.实验过程
2.1 Web前端HTML
2.1.1 正常安装、启停Apache
- 开启Apache服务
systemctl start apache2
- 打开浏览器访问
http://127.0.0.1
(注意不能是https),若成功应该会显示以下界面
- 关闭Apache服务
systemctl stop apache2
2.1.2 编写一个含有表单的HTML
2.1.2.1 基础知识
- HTML
- HTML是一种用于创建网页和网页应用的标记语言。它由一系列的标签组成,这些标签定义了网页的结构和内容,例如标题、段落、列表、链接等。
- 表单
- 表单是HTML的一部分,它允许用户输入数据,如文本、数字、选择等,然后将这些数据发送到服务器。 表单通常包含输入字段、复选框、单选按钮、提交按钮等元素。
- GET与POST方法
- GET是一种HTTP方法,用于从服务器请求数据。GET请求的数据以URL的形式附加在Query String(查询字符串)中,这意味着数据对用户可见且可以被缓存。
- POST也是一种HTTP方法,通常用于向服务器发送数据进行处理,例如用户注册、文件上传等。与GET不同,POST请求的数据不会显示在URL中,而是在HTTP请求主体中。
2.1.2.2 实践
- 创建一个含表单的HTML
vi /var/www/html/20212416.html
,编写一个简单的HTML界面代码:
<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"><title>Login</title>
</head>
<body><div id="div1" style="text-align: center"><h1>系统登录</h1><form name="form1" method="post" action="LoginServlet">用户名:<input type="text" name="usrname" /><br><br>密码:<input type="password" name="pwd" /><br><br><input type="submit" name="sub1" value="确定"/><input type="reset" name="ret1" value="重置"/></form></div>
</body>
</html>
- 打开编写好的HTML文件
2.2 Web前端javascipt
2.2.1 基础知识
- JavaScript
- JavaScript是一种高级、解释性、就地紧凑的编程语言。常用于网页开发,也可被用于其他类型的应用。JSON(JavaScript对象表示法)也是一种基于JavaScript的语法,用于数据交换格式。
- JavaScript基本功能
- 变量和数据类型:在JavaScript中,你可以使用不同的关键字(如var, let, const)声明变量,并可存储各种数据类型,如数字(number)、字符串(string)、布尔值(bool)、对象(object)等。
- 控制结构:包括条件语句(if, else, switch)和循环语句(for, while, do-while, for-of, for-in)等。
- 函数:JavaScript支持函数的定义和调用,这使得代码的复用和模块化变得更容易。
- 对象和原型:JavaScript使用基于原型的对象,这意味着对象是由其他对象派生的,这会带来许多高级功能,如继承。
- 数组:JavaScript中的数组非常灵活,可以存储不同类型的元素。
错误处理:可以捕获和处理错误,使用try, catch和finally语句。 - 事件驱动:JavaScript是异步和事件驱动的语言,这意味着它特别适用于处理用户交互。
- 异步编程:ES6引入了Promises和async/await模式来处理异步操作,这使得编写异步代码变得更加简单。
Web APIs:JavaScript可以通过Web APIs与网页的其它部分交互,比如Fetch API用于调用Web服务,Canvas API用于渲染图形。
- DOM
- DOM(Document Object Model,文档对象模型是一个Web标准,它将Web文档(尤其是HTML和XML文档)表示为树形结构,每个节点都是对象(节点对象)。DOM允许JavaScript通过编程方式动态地访问和修改文档的内容、结构和样式。
2.2.2 实践
- 编写JavaScript验证用户名、密码的规则:若输入的用户名或密码为空则不可提交表单
<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"><title>Login</title><script>// JavaScript函数,用于在表单提交前检查用户名和密码function validateForm() {var username = document.forms["form1"]["usrname"].value;var password = document.forms["form1"]["pwd"].value;if (username == "" || password == "") {alert("用户名和密码不能为空!");return false; // 阻止表单提交}return true; // 允许表单提交}</script>
</head>
<body><div id="div1" style="text-align: center"><h1>系统登录</h1><form name="form1" method="post" action="" onsubmit="return validateForm()">用户名:<input type="text" name="usrname" /><br><br>密码:<input type="password" name="password" /><br><br><input type="submit" name="sub1" value="确定"/><input type="reset" name="ret1" value="重置"/></form></div>
</body>
</html>
- 编写success.php用于用户点击登录后,回显“欢迎+输入的用户名”
<!DOCTYPE html><head><meta charset="UTF-8"><title>Welcome!</title>
</head>
<body>
<h1 align="center">欢迎!<?php echo $_POST['username'];?></h1>
</body>
</html>
修改表单
<form name="form1" action="loginsuccess.php" method="POST" onsubmit="return checked()">
测试
- 尝试注入攻击:利用回显用户名注入HTML及JavaScript。
<script type="text/javascript"> alert("JavaScript注入攻击20212416") </script>
2.3 Web后端:MySQL基础
2.3.1 正常安装、启动MySQL
service mysql start #开启MySQL服务
mysql -u root -p #使用root权限进入,默认的密码是password
show databases; #查看数据库基本信息
use mysql; #选择使用mysql数据库
2.3.2 创建用户、修改密码
- 创建新用户xxn20212416
grant select,insert,update,delete on mysql.* to xxn20212416@localhost identified by "123456";
- SELECT, INSERT, UPDATE, DELETE:这些关键字指定要授予的权限类型。在这个例子中,被授予 SELECT(查询数据)、INSERT(插入数据)、UPDATE(更新数据)和 DELETE(删除数据)权限。
- on mysql.*:指定这些权限应用于 mysql 数据库中的所有表(用 * 表示)。
- to ‘xxn20212416@localhost’:指定要授予权限给的用户账号,格式为 用户名@主机名。在这个例子中,用户名为 xxn20212416 而主机名为 localhost 意味着该用户仅能够从当前主机登录。
- identified by ‘123456’:指定用户账号的密码。这部分是可选的,但如果你包含它,则该用户需要使用这个密码来登录。
-
exit退出后使用新的用户名和密码进行登录
mysql -u xxn20212416 -p
-
修改密码
SET PASSWORD FOR 'xxn20212416'@'localhost' = PASSWORD('20212416');
-
查看当前用户信息
select user, password, host from user;
可以看到密码序列发生变化,密码修改成功 -
更新权限
flush privileges;
退出数据库,使用新的密码登录quit
2.3.3 建库、建表
create database xxndb; #建立数据库
use xxndb; #使用新建的xxn数据库
create table login (username VARCHAR(20),password VARCHAR(20)); #建立数据库表login,设置字段基本信息(username和password)
insert into login values('xioooning','2416'); #插入数据
insert into login values('xxn','20212416'); #插入数据
2.4 Web后端:编写PHP网页,连接数据库,进行用户认证
- 编写login.php
<?php
$uname=$_POST["username"];
$pwd=$_POST["password"];
echo $uname;
$query_str="SELECT * FROM login where username='$uname' and password='$pwd';";
$mysqli = new mysqli("127.0.0.1", "root", "123456", "xxndb");
$query_str1="use xxndb;";/* check connection */
if ($mysqli->connect_errno) {echo "failed connection";printf("Connect failed: %s\n", $mysqli->connect_error);exit();
}
echo " Successfully connected!";
/* Select queries return a resultset */
if ($result = $mysqli->query($query_str1))
echo"<br>Success into database!";
echo$uname;
if ($result = $mysqli->query($query_str)) {if ($result->num_rows > 0 ){echo "<br> {$uname}:Welcome! <br> ";} else {echo "<br> Login Fail! <br> " ; }/* free result set */$result->close();
}
$mysqli->close();
?>
- 修改前端表单
<form name="form1" action="login.php" method="POST" onsubmit="return checked()">
- 测试
- 登录成功
- 登录失败
2.5 最简单的SQL注入,XSS攻击测试
- SQL注入
' or 1=1#
- 我在login.php中使用的查询语句为
SELECT * FROM login where username='$uname' and password='$pwd';
,与SQL注入的语句连接起来就是SELECT * FROM login WHERE username='' or 1=1# AND password='$pwd';
这是一个永真式,不管输入的用户名和密码正确与否,都能登录成功
- XSS攻击
- 在用户名框中输入
<script> alert("来自20212416的XSS攻击") </script>
2.6 安装Webgoat或类似平台,并完成SQL注入、XSS、CSRF攻击
2.6.1 下载安装Webgoat
- 下载链接
可以直接搜索“webgoat-8.1.0.jar”
- 下载后放到kali解压
java -jar webgoat-server-8.1.0.jar
- 登录
- 在浏览器中输入
http://localhost:8080/WebGoat/login
- 输入用户名和密码注册并登录,登录成功界面如下
2.6.2 SQL注入
- SQL注入的目的就是构造SQL语句使得条件判断永远为真,操作如图:
-
String SQL injection
注入后的SQL语句为SELECT * FROM user_data WHERE first_name = 'John' and last_name = 'Smith' or '1' = '1'
图中绿色部分是获得的数据。 -
Numeric SQL injection
注入后的SQL语句为SELECT * From user_data WHERE Login_Count = 1 and userid= 1 or 1=1
其实Login_Count 无所谓填什么数字,因为后面会或上一个1,此式为永真式。
2.6.3 XSS攻击
- Reflected XSS
- 输入
<script> alert("20212416_Reflected XSS") </script>
- DOM-Based XSS
- 在空栏处输入
start.mvc#test/
,其实是构造一个输入(带着你想触发程序的路径),而提示中给出了这个路径
2.6.4 CSRF攻击
- CSRF(跨站请求伪造),是一种常见的网络攻击方式,它利用了用户已认证的会话信息(如Cookie)来强制用户在不知情的情况下对网站进行未授权的操作。
-
选择一个基础题来尝试,提示我们答案和flag有关
-
尝试先点击“提交查询”,这时会跳转另一个界面,可以看到这里flag的值为null
-
右键点击“查看选中部分源代码”,看一下提交查询按钮的源代码,发现其type为hidden,表明该字段在页面上并不可见,我们无法直接看到或修改它。然而,该字段仍然会在表单提交时发送到服务器。并且其value=“false”,设置了这个隐藏输入的初始值为字符串"false",其action指向了一个网页(也就是我们刚刚点击提交查询时跳转的网页)。可以推测,csrf可能是一个CSRF令牌(服务器在用户开始与表单交互时生成的一个随机值,以此来确保提交表单的是原始用户而不是攻击者)。
所以我们如果找到了正确的csrf的值(也就是flag),可能就能实现攻击。 -
新建一个html文件,将提交查询按钮部分的html代码复制进去,修改action部分为
"http://localhost:8080/WebGoat/csrf/basic-get-flag"
-
打开这个页面
- 点击提交查询,可以得到有效的flag值为59399
- 回到WebGoat,输入59399,成功
3.问题及解决方案
-
问题1:使用默认密码也无法登录数据库
-
问题1解决方案:在root权限下使用
mysql -u root
不带密码进入数据库,再用set password for 'root'@'localhost' = PASSWORD('yournewpassword');
修改密码,别忘了分号
-
问题2:使用新建的用户不能建表
-
问题2解决方案:因为我在创建新用户xxn20212416的时候没有赋予它建表的权限,可以在root下使用
GRANT CREATE ON xxn.* TO 'xxn20212416'@'localhost';
赋建表权,但我在完成的时候就直接是用root身份连接的数据库
4.学习感悟、思考等
- 这次实验我是有苦说不出,之前的课程搭建好的网站文件都找不到了,所有都得从头再来。最考验耐心的应该是数据库那部分,我没有完全按照学长学姐的步骤来做,走了一些弯路,但是也在这个过程中更深刻地理解了其中的逻辑关系,解决问题的过程也就是理清思路的过程。
- 在最后一个实践(我愿称之为刷题部分)中,同种类型不同方式的题目加深了我对这三种攻击原理以及实现方式的理解,特别是探究为什么要把“提交查询”的html代码复制到另一个文件并访问,为什么要找有效的flag值,它的意义是什么……这些过程令我受益匪浅。
参考资料
一个好用的GPT