网络攻防期末大作业选题:防sql注入的登录网站【网络攻防CTF】(保姆级图文)


欢迎关注 『网络攻防CTF』 系列,持续更新中
欢迎关注 『网络攻防CTF』 系列,持续更新中

1. 结合mysql数据库设计一个web登录页面

数据库sql搭建

另存为sql_test.sql文件导入即可
在这里插入图片描述

/*
 Navicat Premium Data Transfer

 Source Server         : localhost
 Source Server Type    : MySQL
 Source Server Version : 50734
 Source Host           : localhost:3306
 Source Schema         : sql_test

 Target Server Type    : MySQL
 Target Server Version : 50734
 File Encoding         : 65001

 Date: 13/05/2022 10:15:53
*/

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for user
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user`  (
  `username` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `pwd` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `user` VALUES ('admin', 'admin');

SET FOREIGN_KEY_CHECKS = 1;

在这里插入图片描述
在这里插入图片描述

项目结构如下:

为了美观引用了layui框架(也可以没有,只是样式)
在这里插入图片描述

Login.html效果图如下:

输入用户名密码测试登陆。

在这里插入图片描述

html代码

layui文件可以在gitee官网上下载https://gitee.com/sentsin/layui

<!DOCTYPE html>
<html>

<head>
    <meta http-equiv="Content-Type" content="text/html; charset=gb2312">
    <title>防止SQL注入的登录页面</title>

    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
    <title>基于layui框架的放sql注入网站</title>
    <link rel="stylesheet" href="layui-master/src/css/layui.css">
    <link rel="stylesheet" href="layui-master/src/css/modules/code.css">
    <script src="layui-master/src/layui.js" type="text/javascript" charset="UTF-8"></script>

    <script type="text/javascript">
        function Mycheck(str) {
            var mess = "不允许输入的字符:\r\n";
            var mark = "yes";
            if (str.indexOf(";") >= 0) {
                mark = "no";
                mess += " ; ";
            }
            if (str.indexOf("&") >= 0) {
                mark = "no";
                mess += " & ";
            }
            if (str.indexOf("<") >= 0) {
                mark = "no";
                mess += " < ";
            }
            if (str.indexOf(">") >= 0) {
                mark = "no";
                mess += " > ";
            }
            if (str.indexOf("--") >= 0) {
                mark = "no";
                mess += " -- ";
            }
            if (str.indexOf("/") >= 0) {
                mark = "no";
                mess += " / ";
            }
            if (str.indexOf("%") >= 0) {
                mark = "no";
                mess += " % ";
            }
            if (str.indexOf("'") >= 0) {
                mark = "no";
                mess += " ' ";
            }
            if (str.indexOf("#") >= 0) {
                mark = "no";
                mess += " # ";
            }
            if (mark == "no") {
                alert(mess);
                return false;
            } else return
            return true;
        }
    </script>


</head>

<body style="font-size:12px">
<table width="382" border="0" align="center" cellpadding="0" cellspacing="0">
    <tr>
        <td height="99" background="images/login_01.jpg">&nbsp;</td>
    </tr>
    <tr>
        <td height="160" bgcolor="#FEF7C3">
            <table class="layui-table" lay-size="lg" lay-even lay-skin="row" width="300" border="0" align="center"
                   cellpadding="3" cellspacing="0">
                <form method='post' action='login.php' name="form1" onSubmit="Mycheck(form1.username.value)">
                    <tr>
                        <td height="22" colspan="2" align="center">&nbsp;</td>
                    </tr>
                    <tr>
                        <td height="22" align="right">mzh</td>
                    </tr>
                    <tr>
                        <td height="22" align="right">网工191</td>
                    </tr>
                    <tr>
                        <td height="22" align="right">19145120</td>
                    </tr>

                    <tr>
                        <td height="22" align="right">用户</td>
                        <td height="22"><input name="username" type="text" class="layui-input-inline" id="txt_name"
                                               size="18" maxlength="50"></td>
                    </tr>
                    <tr>
                        <td height="22" align="right">密码:</td>
                        <td height="22"><input name="passwd" type="password" class="layui-input-inline"
                                               id="txt_passwd" size="19" maxlength="50"></td>
                    </tr>
                    <tr>
                        <td height="22" colspan="2" align="center"><input name="login" type="submit" id="login"
                                                                          value="登 录"
                                                                          class="layui-btn layui-btn-radius layui-btn-warm">
                            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
                            <input type="reset" name="Submit2" value="重 置"
                                   class="layui-btn layui-btn-radius layui-btn-warm"></td>
                    </tr>
                </form>
            </table>
        </td>
    </tr>
</table>
<!-- Code injected by live-server -->
<script type="text/javascript">
    // <![CDATA[  <-- For SVG support
    if ('WebSocket' in window) {
        (function () {
            function refreshCSS() {
                var sheets = [].slice.call(document.getElementsByTagName("link"));
                var head = document.getElementsByTagName("head")[0];
                for (var i = 0; i < sheets.length; ++i) {
                    var elem = sheets[i];
                    var parent = elem.parentElement || head;
                    parent.removeChild(elem);
                    var rel = elem.rel;
                    if (elem.href && typeof rel != "string" || rel.length == 0 || rel.toLowerCase() ==
                        "stylesheet") {
                        var url = elem.href.replace(/(&|\?)_cacheOverride=\d+/, '');
                        elem.href = url + (url.indexOf('?') >= 0 ? '&' : '?') + '_cacheOverride=' + (new Date()
                            .valueOf());
                    }
                    parent.appendChild(elem);
                }
            }

            var protocol = window.location.protocol === 'http:' ? 'ws://' : 'wss://';
            var address = protocol + window.location.host + window.location.pathname + '/ws';
            var socket = new WebSocket(address);
            socket.onmessage = function (msg) {
                if (msg.data == 'reload') window.location.reload();
                else if (msg.data == 'refreshcss') refreshCSS();
            };
            if (sessionStorage && !sessionStorage.getItem('IsThisFirstTime_Log_From_LiveServer')) {
                console.log('Live reload enabled.');
                sessionStorage.setItem('IsThisFirstTime_Log_From_LiveServer', true);
            }
        })();
    } else {
        console.error('Upgrade your browser. This Browser is NOT supported WebSocket for Live-Reloading.');
    }
    // ]]>
</script>
</body>

</html>

php验证代码

<?php

session_start();//开启session对话,必须在html前

//post方法获取表单用户名,密码
$username = $_POST['username'];
$passwd = $_POST['passwd'];


//连接数据库
$link = mysqli_connect('localhost','root','123456','sql_test');

if (!$link)
{
    die("连接失败:".mysqli_connect_error());
}

//检查用户名密码是否在数据库里已保存注册
$sql = 'select * from user where username="'.$username.'"and pwd="'.$passwd.'"';

$result = mysqli_query($link,$sql);
$rows = mysqli_fetch_array($result);//查询数据表每一行

if($rows){//数据库中查到用户名,密码匹配
    $_SESSION['username'] = $username;//保存session数据,全局变量
    echo '
    ######################登陆成功###################
    ';
}else{
    echo '
    ######################用户名或密码错误######################
    ';
}
?>



2. 能够防住简单注入和宽字节注入

简单注入

注入用户名19145120mzh' or 1=1#'
密码随意输入

这里检查是否含有特殊的'引号字符,防止了注入,具体代码在html的js部分

            if (str.indexOf("'") >= 0) {
                mark = "no";
                mess += " ' ";
            }

在这里插入图片描述

双拼注入

类似单注入,同样成功防止了注入。

注入用户名19145120mzh' 'oorr 1=1#'
密码随意输入

这里检查是否含有特殊的'引号字符,防止了注入,具体代码在html的js部分

            if (str.indexOf("'") >= 0) {
                mark = "no";
                mess += " ' ";
            }

宽字节注入

首先输入测试用户密码得到格式标准化的url
我这里随便输入了用户mzh密码123

得到了urlhttp://127.0.0.1:5500/login.html?username=mzh&pwd=123&login=%E7%99%BB+%E5%BD%95
在这里插入图片描述
在url后面添加%df%27%20or%201=1%23注入代码

把url改为http://127.0.0.1:5500/login.html?txt_name=mzh&txt_passwd=123%df%27%20or%201=1%23&login=%E7%99%BB+%E5%BD%95
追加的%df%27%20or%201=1%23表示url编码的空格or空格1=1#(这里的空格就是空格,一个字符,我这么写是为了方便大家理解)

常用的理解。%df一般是用来转换编码的
%df’(浏览器自动进行url编码%27)->%df%27

下图登录失败了,宽字节注入也失败了。

因为我们的js检查了url

            if (str.indexOf("%") >= 0) {
                mark = "no";
                mess += " % ";
            }
                function refreshCSS() {
                    var sheets = [].slice.call(document.getElementsByTagName("link"));
                    var head = document.getElementsByTagName("head")[0];
                    for (var i = 0; i < sheets.length; ++i) {
                        var elem = sheets[i];
                        var parent = elem.parentElement || head;
                        parent.removeChild(elem);
                        var rel = elem.rel;
                        if (elem.href && typeof rel != "string" || rel.length == 0 || rel.toLowerCase() ==
                            "stylesheet") {
                            var url = elem.href.replace(/(&|\?)_cacheOverride=\d+/, '');
                            elem.href = url + (url.indexOf('?') >= 0 ? '&' : '?') + '_cacheOverride=' + (new Date()
                                .valueOf());
                        }
                        parent.appendChild(elem);
                    }
                }

在这里插入图片描述


3. 能够基本防住手动注入和sqlmap攻击(测试案例)

防止手动注入

随便输入异常符号都无法成功的注入

select * from news where id=http://……?id=1

在这里插入图片描述
因为是post的方法,并且js对url处理,url也被锁死。
哪怕我在url中注入正确的用户名admin和密码admin都无法成功注入,哪怕是异常字符也会被过滤掉。
在这里插入图片描述

防御sqlmap攻击

url已经隐藏,无法通过url进行注入攻击了。
在这里插入图片描述


4. 能够防止sql注入原因分析

使用js代码分析、处理并屏蔽客户端上的不安全字符,过滤字符串

功能介绍:检查是否包含“\ \”、“/” “%” "'"等字符。

function Mycheck(str) {
            var mess = "不允许输入的字符:\r\n";
            var mark = "yes";
            if (str.indexOf(";") >= 0) {
                mark = "no";
                mess += " ; ";
            }
            if (str.indexOf("&") >= 0) {
                mark = "no";
                mess += " & ";
            }
            if (str.indexOf("<") >= 0) {
                mark = "no";
                mess += " < ";
            }
            if (str.indexOf(">") >= 0) {
                mark = "no";
                mess += " > ";
            }
            if (str.indexOf("--") >= 0) {
                mark = "no";
                mess += " -- ";
            }
            if (str.indexOf("/") >= 0) {
                mark = "no";
                mess += " / ";
            }
            if (str.indexOf("%") >= 0) {
                mark = "no";
                mess += " % ";
            }
            if (str.indexOf("'") >= 0) {
                mark = "no";
                mess += " ' ";
            }
            if (mark == "no") {
                alert(mess);
                return false;
            } else return
            return true;
        }

使用正则表达式等方式替换、过滤传入的参数

function refreshCSS() {
                    var sheets = [].slice.call(document.getElementsByTagName("link"));
                    var head = document.getElementsByTagName("head")[0];
                    for (var i = 0; i < sheets.length; ++i) {
                        var elem = sheets[i];
                        var parent = elem.parentElement || head;
                        parent.removeChild(elem);
                        var rel = elem.rel;
                        if (elem.href && typeof rel != "string" || rel.length == 0 || rel.toLowerCase() ==
                            "stylesheet") {
                            var url = elem.href.replace(/(&|\?)_cacheOverride=\d+/, '');
                            elem.href = url + (url.indexOf('?') >= 0 ? '&' : '?') + '_cacheOverride=' + (new Date()
                                .valueOf());
                        }
                        parent.appendChild(elem);
                    }
                }

使用php的sql过滤设置

(其实类似我前面的js代码转化过滤)
打开magic_quotes_gpc来防止SQL注入。php.ini中有一个设置:magic_quotes_gpc = Off这个默认是关闭的,如果它打开后将自动把用户提交对sql的查询进行转换,比如把 ’ 转为 '等,对于防止sql注射有重大作用。

如果magic_quotes_gpc=Off,则使用addslashes()函数。

在这里插入图片描述


总结

大家喜欢的话,给个👍,点个关注!继续跟大家分享敲代码过程中遇到的问题!

版权声明:

发现你走远了@mzh原创作品,转载必须标注原文链接

Copyright 2022 mzh

Crated:2022-3-6

欢迎关注 『网络攻防CTF』 系列,持续更新中
欢迎关注 『网络攻防CTF』 系列,持续更新中
【网络攻防CTF】草稿(保姆级图文)
【更多内容敬请期待】


  • 8
    点赞
  • 68
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

发现你走远了

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值