实践目标
本实践目标是安装 LAMP 构建 Web 服务器,并进行一些简单的攻击实践。
回答实践问题
1.什么是表单?
- 表单在网页中主要负责数据采集功能。一个表单有三个基本组成部分:
- 表单标签:这里面包含了处理表单数据所用CGI程序的URL以及数据提交到服务器的方法。
- 表单域:包含了文本框(text)、密码框(password)、隐藏域(hidden)、多行文本框(TEXTAREA)、复选框(checkbox)、单选框(radio)、下拉选择框(select)和文件上传框(file)等。
- 表单按钮:包括提交(submit)按钮、复位(reset)按钮和一般(button)按钮;用于将数据传送到服务器上的CGI脚本或者取消输入,还可以用表单按钮来控制其他定义了处理脚本的处理工作。
2.浏览器可以解析运行什么语言?
- 支持HTML、XML及Python、PHP、JavaScript等脚本语言。
3.WebServer支持哪些动态语言?
- ASP(ActiveServerPages)
- JSP(JavaServerPages)
- PHP(HypertextPreprocessor)
实践过程
docker 启动 lamp 容器
由于 kali 虚拟机出现了些莫名奇妙的错误,暂时不想搞这个东西,本次实验通过 Ubuntu 20.04 的 docker 安装 HTTPd 容器来进行。
-
拉取
tutum/lamp
image。 -
以此构建运行
lamp
容器。- 映射端口:
11201 -> 80
和11202 -> 443
。 - 以交互式容器运行:
-i -t
。
可以看到容器列表:
- 映射端口:
-
以 Ubuntu
IP + 端口
访问容器的 Web 服务。
Web前端:HTML
能正常安装、启停Apache。理解HTML,理解表单,理解GET与POST方法,编写一个含有表单的HTML。
-
容器中 apache2 服务默认已启用,可直接以 Ubuntu
IP + 端口
访问容器的 Web 服务。-
如果要启用 apache2 :
sudo service apache2 start
-
-
该容器默认 web 服务的文件夹为
/var/www/html
。-
进入该文件。
cd /var/www/html
-
ls
可以看到index.php
,说明容器支持 PHP 。
-
-
重新编写
index.php
文件:- 以下代码中不包含 PHP 语句,仅包含 html 语句。
<html> <head> <title>Login</title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> </head> <h2 align="center">Login</h2> <center> <form action="login" method="post"> <input placeholder="Username" name="Name" class="user" type="email"> <br> </br> <input placeholder="Password" name="Password" class="pass" type="password"> <br> </br> <input type="submit" value="Login"> </form> </center> </body> </html>
-
重新以 Ubuntu
IP + 端口
访问容器的 Web 服务。
Web前端:JavaScipt
理解JavaScript的基本功能,理解DOM。编写JavaScript验证用户名、密码的规则。
-
以之前代码为基础,添加 一段 JavaScript 代码,结果编写为
index_add_js.php
。<html> <head> <title>User_Login</title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> </head> <body> <h2 align="center">Login</h2> <center> <form action="login.php" method="post" name="form_login"> <input placeholder="Username" name="Username" class="user" type="text" onfocus="if (this.value=='Your username') this.value='';" /> <br> </br> <input placeholder="Password" name="Password" class="pass" type="password" onfocus="if (this.value=='Your password') this.value='';"/> <br> </br> <input type="submit" value="Login" onClick="return validateLogin()"/> </form> </center> <script language="javascript"> function validateLogin(){ var sUserName = document.form_login.Name.value ; var sPassword = document.form_login.Password.value ; if ((sUserName =="") || (sUserName=="Your username")){ alert("请输入用户名!"); return false ; } if ((sPassword =="") || (sPassword=="Your password")){ alert("请输入密码!"); return false ; } } </script> </body> </html>
-
重新以 Ubuntu
IP + 端口 + index_add_js.php
访问容器的 Web 服务。 -
无用户名输入提示:
-
无密码输入提示:
Web后端:MySQL基础
-
容器中 mysql 服务默认已启用。
-
如果要启用 mysql :
sudo /etc/init.d/mysql start
-
用户信息操作
-
使用 root 权限进入 mysql 控制台:
mysql -u root -p
- 该容器 mysql 默认密码为 空。
-
或者:
update user set password=PASSWORD("yogile") where user='root';
更新权限:
flush privileges;
-
更新数据库 root 密码。
set password for 'root'@'localhost' =password('数据库root用户密码');
-
这时,退出并使用空密码尝试登录 mysql 控制台。
-
-
查看当前用户信息。
select user, password, host from user;
-
添加数据库新用户。
grant select,insert,update,delete on 数据库名.* to 用户名@登录主机 identified by "密码";
-
示例:
grant select,insert,update,delete on yogile_exp8.login to yogile@localhost identified by "yogile";
以 localhost IP 创建名为 yogile 、密码为 yogile 的数据库账号,并将 yogile_exp8 数据库下的 login 数据表的查找、插入、更新、删除 权限授予该账号。
-
以新用户身份登录。
-
数据库操作
-
查看数据库基本信息。
show databases;
-
创建数据库
yogile_exp8
。create database yogile_exp8;
-
选定操作名为
yogile_exp8
的数据库。use yogile_exp8;
-
建立数据库表
login
,并设置字段基本信息。create table login (username VARCHAR(20), password VARCHAR(20));
该图包含上面两点。
-
插入数据。
insert into login values('yogile', '20175223');
-
查询表中的数据.
select * from login;
-
指定字段信息,查询表中的数据。
select * from login where username = 'yogile';
-
指定字段信息,查询表中的某一字段的数据。
select username from login where username = 'yogile';
该图包含上面四点。
Web后端:PHP 与 MySQL
编写PHP网页,连接数据库,进行用户认证。
-
编写 PHP 文件
index_php_mysql.php
测试 PHP 以及数据库连接。<?php $servername = "localhost"; $mysqli_account = "yogile"; $mysqli_pwd = "yogile"; $mysqli_list = "yogile_exp8"; // 创建连接 $link = mysqli_connect($servername, $mysqli_account, $mysqli_pwd, $mysqli_list); ?> <html> <head> <title>Hello world!</title> <style> body { background-color: white; text-align: center; padding: 50px; font-family: "Open Sans","Helvetica Neue",Helvetica,Arial,sans-serif; } #logo { margin-bottom: 40px; } </style> </head> <body> <h1><?php echo "Hello world!"; ?></h1> <?php if(!$link) { ?> <h2>Can't connect to local MySQL Server!</h2> <?php } else { ?> <h2>Successful connect to local MySQL Server!</h2> <?php } ?> </body> </html>
-
如果 PHP 编译无误、数据库连接成功。
-
-
各项无误后,编写
login.php
文件,简单验证数据库登录。- 注意:这里
$_POST
获取参数值的参数名必须是 HTML<form>
语句中的<input>
的name
一致。
<?php $uname=$_POST["Username"]; $pwd=$_POST["Password"]; echo $uname; $query_str="SELECT * FROM login where username='$uname' and password='$pwd';"; $servername = "localhost"; $mysqli_account = "yogile"; $mysqli_pwd = "yogile"; $mysqli_list = "yogile_exp8"; $mysqli = new mysqli($servername, $mysqli_account, $mysqli_pwd, $mysqli_list); $query_str1="use yogile_exp8;"; /* check connection */ if ($mysqli->connect_errno) { printf("Connect failed: %s ", $mysqli->connect_error); exit(); } echo "connection ok!"; /* 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 failed!!!! <br> " ; } /* free result set */ $result->close(); } $mysqli->close(); ?>
- 注意:这里
-
login.php
文件编写完成后,重新访问index_add_js.php
网页。-
输入错误密码。
-
输入正确密码。
-
最简单的SQL注入、XSS攻击测试
SQL注入
-
就之前使用的代码,无论是在用户名,还是在密码的
<input>
中,输入' or 1=1#
都能判断登录成功。 -
说明:
select * from users where username='' or 1=1#' and password='' 或 select * from users where username='' and password='' or 1=1#' # 号后面的内容成为注释,or 1=1 使该SQL语句返回成功值。
-
解决办法:使用正则表达式。
- 下面是我编写的使用正则表达式的 JavaScript 表单检查函数。
/** * 提交表单前检查表单内容 * @param fromLogin * @returns {boolean} */ function checkFrom(fromLogin) { fromData[0] = fromLogin.name.value; fromData[1] = fromLogin.password.value; fromData[2] = fromLogin.verif.value; // 检查 空字符串 for (let i = 0; i < 6; i++) { if (fromData[i] === "") { alert(fromList[i] + "不可为空"); // flag_result = false; return false; } } // 检查 name if (/^[a-zA-Z][a-zA-Z0-9_-]{3,16}$/.test(fromData[0]) !== true) { fromData[0] = ""; alert("用户名不满足条件:可包含字母开头、数字、下划线、减号的4到16位字符"); return false; } // 检查 password let regExp_password = /^(?![a-zA-Z]+$)(?![A-Z0-9]+$)(?![A-ZW_!@#$%^&*`~()-+=]+$)(?![a-z0-9]+$)(?![a-zW_!@#$%^&*`~()-+=]+$)(?![0-9W_!@#$%^&*`~()-+=]+$)[a-zA-Z0-9!@#$%^&*`~()]{8,20}$/; if (regExp_password.test(fromData[1]) !== true) { fromData[2] = ""; alert("密码格式错误,密码长度为8-20位,至少含有以下四种字符的其中三种: 大写字母、小写字母、数字、特殊字符(!@#$%^&*`~())"); return false; } // 检查 verif if (/^[a-zA-Z0-9_-]{4}$/.test(fromData[2]) !== true) { fromData[2] = ""; alert("验证码错误,请重新获取"); return false; } if (fromData[2] !== verif_str) { fromData[2] = ""; verif_str = ""; alert("验证码错误,请重新获取"); return false; } return true; }
-
尝试SQL注入:
XSS攻击
-
将一张图片放在
/var/www/html
目录下,在用户名输入框输入<img src="xxxx.jpg" />
,密码随意,读取图片。 -
说明:
XSS攻击通常指的是通过利用网页开发时留下的漏洞,通过巧妙的方法注入恶意指令代码到网页,使用户加载并执行攻击者恶意制造的网页程序。这些恶意网页程序通常是JavaScript,但实际上也可以包括Java、 VBScript、ActiveX、 Flash 或者甚至是普通的HTML。攻击成功后,攻击者可能得到包括但不限于更高的权限(如执行一些操作)、私密网页内容、会话和cookie等各种内容。
-
解决办法:使用正则表达式。
- 我编写的使用正则表达式的表单检查函数在上一点。
-
尝试XSS攻击。
实现总结与体会
- 本次实验是安装 LAMP 组件构建 Web 服务器,并进行一些简单的攻击实践。
- 上学期上过相关 JavaWeb 的相关课程,我自己也学习过 PHP 、Python 等语言,了解到想要做好网站的安全功能以及安全维护是非常困难的。
- 所以对于不从事网络安全行业的所谓 “个人” 来说,使用现成已有的、商业化的 Web 服务,比如个人云盘 ownCloud、个人博客 WordPress 等等,都提供了基本可用的安全功能。