一、实验要求
(1).Web前端HTML (1分)
能正常安装、启停Apache。理解HTML,理解表单,理解GET与POST方法,编写一个含有表单的HTML。
(2).Web前端javascipt (1分)
理解JavaScript的基本功能,理解DOM。
在(1)的基础上,编写JavaScript验证用户名、密码的规则。在用户点击登陆按钮后回显“欢迎+输入的用户名”
尝试注入攻击:利用回显用户名注入HTML及JavaScript。
(3).Web后端:MySQL基础:正常安装、启动MySQL,建库、创建用户、修改密码、建表 (1分)
(4).Web后端:编写PHP网页,连接数据库,进行用户认证 (1分)
(5).最简单的SQL注入,XSS攻击测试 (1分)
(6).选做Webgoat或类似平台的SQL注入、XSS、CSRF攻击各一例。 (1分)
2 报告内容:
2.1.基础问题回答
(1)什么是表单
(2)浏览器可以解析运行什么语言。
(3)WebServer支持哪些动态语言
(4)防范注入攻击的方法有哪些
2.2.实践总结与体会
2.3.实践过程记录
3.报告格式
3.1 报告整体观感:有带链接的目录,各级标题层次分明,易于阅读(1分)
3.2 文字表述:报告文字内容非常全面,表述清晰准确。(1分)
二、基础问题回答
什么是表单
表单(Form)是HTML中用于收集用户输入的一种方式,它允许用户输入、选择或提交数据。表单数据可以通过多种方式提交,包括GET和POST方法。表单由<form>
标签定义,内部可以包含多种类型的输入字段,如文本框、单选按钮、复选框、下拉菜单等。
浏览器可以解析运行什么语言
浏览器主要用于解析和执行以下语言:
- HTML (HyperText Markup Language): 用于创建网页结构的标记语言。
- CSS (Cascading Style Sheets): 用于设置网页的布局和样式。
- JavaScript: 一种脚本语言,用于为网页添加交互性。
此外,现代浏览器还支持WebAssembly,它允许在浏览器中以接近原生性能运行编译后的代码。
WebServer支持哪些动态语言
Web服务器本身不直接支持编程语言,但可以通过CGI(Common Gateway Interface)或各种插件来运行不同的动态语言。常见的动态语言包括:
- PHP: 一种广泛使用的开源脚本语言,特别适合于Web开发。
- Python: 一种高级编程语言,通过框架如Django或Flask可以用于Web开发。
- Ruby: 特别是Ruby on Rails框架,用于快速开发Web应用程序。
- JavaScript (Node.js): 通常在客户端运行,但Node.js允许在服务器端运行JavaScript。
- Perl: 一种强大的文本处理语言,也可用于Web开发。
- Java: 通过Servlet和JSP等技术,Java可以用于创建动态Web应用程序。
- ASP.NET: 微软开发的用于构建动态网站的Web应用框架。
防范注入攻击的方法有哪些
注入攻击,如SQL注入,是一种常见的Web安全漏洞,它允许攻击者在数据库中执行未授权的命令。以下是一些防范注入攻击的方法:
- 使用参数化查询: 避免直接将用户输入拼接到SQL语句中,使用参数化查询可以防止SQL注入。
- 数据校验: 对所有用户输入进行校验,确保它们符合预期的格式。
- 最小权限原则: 数据库账户应该只有执行其工作所需的最小权限。
- 使用Web应用防火墙(WAF): WAF可以提供一层额外的保护,帮助过滤恶意流量。
- 定期更新和打补丁: 保持服务器、数据库和应用程序的软件更新到最新版本。
- 使用安全框架: 许多现代Web框架提供了防止注入攻击的机制。
- 错误处理: 不要在页面上显示数据库错误信息,这可能会泄露敏感信息。
- 输入过滤: 对用户输入进行过滤,移除或转义潜在的危险字符。
- 使用ORM工具: 对象关系映射(ORM)工具可以减少直接SQL查询的使用,降低注入风险。
三、实践过程记录
Web前端HTML
能正常安装、启停Apache。理解HTML,理解表单,理解GET与POST方法,编写一个含有表单的HTML (1分)
- 使用root身份输入
service apache2 start
命令打开apahce2 - 访问 http://127.0.0.1 查看默认页面
- 随后,输入
cd /var/www/html/
进入apache的工作目录 - 用root身份创建一个test.html,写入网页代码(非root身份创建的文件类型为只读,不可修改,使用vi修改后须通过
:q!
强制退出)
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<form action="test.html" method="get">
用户名<input type="text" name="name" />
<br>
密码<input type="text" name="password" />
<br>
<button type="submit">发送</button>
</form>
</body>
</html>
不想使用vi编辑器可以直接在命令行输入以下命令编写文件
cat << EOF > test.html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<form action="test.html" method="get">
用户名<input type="text" name="name" />
<br>
密码<input type="text" name="password" />
<br>
<button type="submit">发送</button>
</form>
</body>
</html>
EOF
- 访问 http://127.0.0.1/test.html 查看刚刚写好的页面
Web前端javascipt
理解JavaScript的基本功能,理解DOM。
在(1)的基础上,编写JavaScript验证用户名、密码的规则。在用户点击登陆按钮后回显(1分)
- 将上述页面修改为
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<form action="#" method="get">
用户名<input type="text" name="name" id="name" />
<br />
密码<input type="text" name="password" id="password" />
<br />
<button type="submit" onclick="return checkUser()">发送</button>
</form>
</body>
<script>
const checkUser = () => {
const MyName = "lhq",
MyPassword = "20212217";
const name = document.getElementById("name").value;
const password = document.getElementById("password").value;
if (name === MyName && password === MyPassword) {
alert("欢迎" + MyName);
} else {
alert("用户名不存在或密码错误");
}
};
</script>
</html>
- 输入用户名
lhq
,密码20212217
,页面显示"欢迎你,lhq" - 输入其他用户名或密码,页面显示"用户名不存在或密码错误"
Web后端:MySQL基础
MySQL基础:正常安装、启动MySQL,建库、创建用户、修改密码、建表(1分)
由于我使用的是kali-WSL中的最小子系统,不支持安装MySQL,我使用了mariadb,它是MySQL的一种发行版,一般使用和MySQL并无区别
- 安装mariadb:
- 启动MySQL:使用
service mariadb start
- 以root身份登录,默认无密码,密码随便输
mysql -u root
- 查看库:
show databases;
- 使用mysql库:
use mysql;
- 查看用户:
select user, authentication_string, host from user;
- 修改密码:
ALTER USER 'root'@'localhost' IDENTIFIED BY '1234567';
- 更新:
flush privileges;
- 退出并重新登录:
mysql -u root -p
Web后端:编写PHP网页,连接数据库,进行用户认证
使用mysql -u root -p
回车,输入密码123456
登录,写入如下代码创建数据库
create database users;
use users;
create table login(username varchar(20), password varchar(20));
insert into login values ('lhq','20212217');
接着找到PHP.ini查看是否启动了mysql扩展
用vi打开php.ini,使用/mysql
命令进行正则搜索,去掉extions=mysql
前面的分号
在/var/www/html
中写入
<?php
error_reporting(0);
// header("Access-Control-Allow-Origin: *");
/*
240610708 => 0e462097431906509019562988736854
*/
?>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Login</title>
</head>
<body>
<form method="post" action="<?= $_SERVER['PHP_SELF'] ?>">
<input type="text" name="name" id="name">
<input type="text" name="password" id="password">
<input type="submit" value="submit">
</form>
<?php
$server = "localhost";
$username = "root";
$password = "123456";
$dbname = "users";
if (isset($_POST['name']) && isset($_POST['password'])) {
try {
$conn = new PDO("mysql:host=$server;dbname=$dbname", $username, $password);
// set the PDO error mode to exception
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$sql = ("SELECT * FROM login WHERE username='$_POST[name]' AND password='$_POST[password]'"); #
echo "<h1><pre>$sql</pre><h1>";
$stmt = $conn->prepare($sql);
$stmt->execute();
$result = $stmt->setFetchMode(PDO::FETCH_ASSOC);
if ($stmt->fetchAll()) {
echo "<h1>登录成功</h1>";
} else {
echo "<h1>登录失败</h1>";
}
} catch (PDOException $e) {
echo "Error: " . $e->getMessage();
}
$conn = null;
}
?>
</body>
</html>
最简单的SQL注入,XSS攻击测试
在SELECT * FROM login WHERE username='$_POST[name]' AND password='$_POST[password]'
这段代码中,程序直接将 $_POST['name']
和 $_POST['password']
的值插入到SQL查询字符串中,没有进行任何形式的转义或验证。这样一来,当用户输入 name=' or 1 # &password=
时,这个输入包含了SQL语法。具体来说:
'
(单引号)用于结束name
字段的值。or 1=1
是一个始终为真的条件,这意味着无论name
字段的实际值是什么,查询都会返回真。#
是一个注释符号,它将后面的所有内容(在这个例子中是&password=
)注释掉。
当这个输入被插入到SQL查询中时,查询变成了:
SELECT * FROM login WHERE username='' or 1=1 # AND password='...'
由于 or 1=1
始终为真,所以无论用户名和密码的实际值是什么,查询都会返回 login
表中的所有行。通过这种方式,攻击者可以绕过身份验证,访问他们不应该访问的数据。在更复杂的情况下,攻击者甚至可以利用SQL注入来执行更危险的操作,比如删除数据、提升权限或执行系统命令。
当输入框中写入下述js语句时
<script>alert(1)</script>
页面反馈如下
发生了XSS,这是由于input元素将value直接放在了HTML中,而该value可被当作js执行
选做Webgoat或类似平台的SQL注入、XSS、CSRF攻击各一例
Releases · WebGoat/WebGoat (github.com)
下载Jar即可,使用java -jar webgoat-2023.8.jar
启动服务,并在浏览器通过 http://127.0.0.1:8080/WebGoat/ 访问
- 首先注册一个用户,我这里的用户名是
20212217lhq
,密码是123
SQL注入
在WebGoat的/SqlInjectionAdvanced.lesson/2
路由上有一个练习SQLi注入的靶场
由于密码往往先哈希再进行SQL查询,很难产生注入。我们对用户名进行注入,将结果制成如下表格:
输入 | 输出 |
---|---|
\ | $\varnothing$ |
20212217lhq | $\varnothing$ |
' or 1=1 -- |
15条结果 |
1' order by 8-- |
invalid ORDER BY expression |
1' order by 7-- |
$\varnothing$ |
Snow | 2条结果 |
Snow' -- |
2条结果 |
' or ascii(substr(('a'),1,1))=97 -- |
15条结果 |
通过构造SQL语句可以查询到任意结果,可见存在SQLi注入 |
XSS
在CrossSiteScriptingStored.lesson/2
路由,打开XSS攻击的靶场
在猫的图片下有一个写评论的地方,写入的任何内容都会存储起来,展示在更下方的评论栏目里,这里存在典型的XSS攻击点
写<SCript>alert(1)</SCript>
,网页弹出了1
,执行了JS代码,可见存在XSS
但是JS作为运行在浏览器的语言,其功能受到浏览器的权限限制,一般来说通过XSS达不到getShell或者读取文件的目的,但可以偷取用户的Cookie,使得攻击者无需密码就能登录账户。
CSRF
在#lesson/CSRF.lesson/2
路由上,可以找到CSRF攻击演练模块
题目的大意是说,"提交"按钮点击后会发送请求,并获得flag。但是这个恶意请求必须来自其他站点,不能来自本页面。(WebGoat通过检查HTTP请求的Referer
字段来判断恶意请求是从这里点的,还是其他地方)要满足这个要求,就就需要将Form表单拷贝到新的html页面上,再用浏览器打开新的页面并点击提交。
首先按住Ctrl Shift C找到“提交”按钮所在的HTML元素
右键编辑为HTML,并新建一个新的test.html
保存代码,
<form accept-charset="UNKNOWN" id="basic-csrf-get" method="POST" name="form1" target="_blank" successcallback="" action="csrf/basic-get-flag">
<input name="csrf" type="hidden" value="false">
<input type="submit" name="submit">
</form>
这里的action采用了相对路由,我们需要将其改为绝对路由
<form accept-charset="UNKNOWN" id="basic-csrf-get" method="POST" name="form1" target="_blank" successcallback="" action="http://127.0.0.1:8080/WebGoat/csrf/basic-get-flag">
<input name="csrf" type="hidden" value="false">
<input type="submit" name="submit">
</form>
点击后跳转,拿到flag
(若没有跳转到flag,可以重新在浏览器中访问html,或者换一个浏览器访问)
四、实践总结与体会
虽然我不是信息安全专业的,但是为了能在技术竞赛上拿到名次,我之前就自学了Web安全的相关知识。因此本次实验操作起来没有那么困难。但是配置环境,解决bug确实是很繁琐的一件事,这个实验一开始时我装不上mysql费了好长时间,最后不得不以mariadb代替。
另外SQL注入、XSS和CSRF虽然实验操作上很简单,但是要想知道代码是怎么构造的,还需要下一番功夫才行,这里我就没有对构造代码的过程进行赘述了,因为需要了解MySQL语言、JS语言才能说明白。