一、实验要求

(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分)

  1. 使用root身份输入service apache2 start命令打开apahce2
  2. 访问 http://127.0.0.1 查看默认页面
  3. 随后,输入cd /var/www/html/进入apache的工作目录
  4. 用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
  1. 访问 http://127.0.0.1/test.html 查看刚刚写好的页面

Web前端javascipt

理解JavaScript的基本功能,理解DOM。
在(1)的基础上,编写JavaScript验证用户名、密码的规则。在用户点击登陆按钮后回显(1分)

  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>


  1. 输入用户名lhq,密码20212217,页面显示"欢迎你,lhq"
  2. 输入其他用户名或密码,页面显示"用户名不存在或密码错误"

Web后端:MySQL基础

MySQL基础:正常安装、启动MySQL,建库、创建用户、修改密码、建表(1分)

由于我使用的是kali-WSL中的最小子系统,不支持安装MySQL,我使用了mariadb,它是MySQL的一种发行版,一般使用和MySQL并无区别

  1. 安装mariadb:
  2. 启动MySQL:使用service mariadb start
  3. 以root身份登录,默认无密码,密码随便输mysql -u root
  4. 查看库:show databases;
  5. 使用mysql库:use mysql;
  6. 查看用户:select user, authentication_string, host from user;
  7. 修改密码:ALTER USER 'root'@'localhost' IDENTIFIED BY '1234567';
  8. 更新:flush privileges;
  9. 退出并重新登录: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>

178bbf2433687f1eb.jpg

最简单的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/ 访问

  1. 首先注册一个用户,我这里的用户名是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语言才能说明白。

posted on 2024-05-16 09:45  亦知亦行  阅读(117)  评论(0编辑  收藏  举报