zoukankan      html  css  js  c++  java
  • php 单页面登陆注册实例,附 XSS 攻击试验实例

     php 单页面登陆、注册试验程序

      包括前后端验证,后端防 XSS 攻击,不包括 SQL 注入内容;密码散列值(hash)的创建与哈希验证。

    /* 这是 php 官方推荐的密码处理函数 */
    password_hash() //创建密码的散列(hash)
    password_verify() //验证密码是否和指定的散列值匹配。

      程序如下,分三部分:php 部分、html部分和javascript部分:

    <?php
    /**
     * php 后端程序部分 #############################
     * 
     */
     
    class manage{
        
        /**
         * 对 POST 请求进行过滤
         * 
         */
        public static function post($input){
            
            //既转换双引号也转换单引号。
            $str = htmlspecialchars($_POST[$input], ENT_QUOTES);
            return substr($str, 0, 30);
        }
        
        /**
         * 对 GET 请求进行过滤
         * 
         */
        public static function get($input){
            $str = htmlspecialchars($_GET[$input], ENT_QUOTES);
            return substr($str, 0, 30);
        }
        
        /**
         * 如果用上面的 POST、GET 过滤觉得万事大吉了,
         * 那也不一定够用,因为可以把非法代码进行各种
         * 形式的编码,使漏洞防不胜防。
         * 
         * 请参考下面的链接到 XSS 速查表,替换一些特征
         * 字符,把漏洞降到最低水平。
         * https://www.freebuf.com/news/153055.html
         */
        public static function customFilter($str){
            
            /**
             * 字符串替换函数替换敏感字符串
             */
             
            //搜索字符串示例
            $findStr = array(
                '%' //防十六进制编码
                //...省略
                );
                
            //替换字符串
            $replaceStr = array(
                ''
                //...省略
                );
                
            $str1 = str_replace($findStr, $replaceStr, $str);
            
            /**
             * 正则表达式替换敏感字符
             * 
             */
             
            //正则搜索字符串示例
            $patterns = array(
                '/javascript:/i',
                '/<script.*/script>/i'
                //...省略
                );
                
            //替换字符串
            $replacements = array(
                '[forbid]',
                '[forbid]',
                //...省略
                );
                
            return preg_replace($patterns, $replacements, $str1);
            
        }
    }
    
    //就当数据库来用
    $file = 'data.txt';
     
    //【1】登陆处理
    if(filter_has_var(INPUT_POST, "isVerify")){
        $isVer = manage::post('isVerify');
        if($isVer === 'display'){
            $email = manage::post('email');
            $pass  = manage::post('pwd');
            
            // filter 过滤器进行邮箱合规性检查
            if(!filter_var($email, FILTER_VALIDATE_EMAIL)){
                exit('输入不是一个合法邮箱,服务器已拒绝执行!');
            }else if(empty($pass)){
                exit('密码不能为空!');
            }else{
                $email = manage::customFilter($email);
                $content  = file_get_contents($file);
                $data = json_decode($content);
                
                //验证邮箱是否匹配
                $isUser = $email === $data->email;
                
                /**
                 * 验证密码是否和指定的散列值匹配。
                 * 
                 * 注:时序攻击(timing attacks)对此函数不起作用。
                 * 
                 */
                $isPass = password_verify($pass, $data->password);
                
                if($isUser && $isPass){
                    echo '<script>alert("登陆成功!")</script>';
                }else{
                    echo '<script>alert("登陆失败!")</script>';
                }
            }
        }
    }
    
    //【2】注册处理
    if(filter_has_var(INPUT_POST, 'isRegister')){
        $isReg = manage::post('isRegister');
        if($isReg === 'display'){
            $data['email'] = manage::post('email');
            $data['password']  = manage::post('pwd');
            
            // filter 过滤器进行邮箱合规性检查
            if(!filter_var($data['email'], FILTER_VALIDATE_EMAIL)){
                exit('不是一个合法邮箱,服务器已拒绝!');
            }else if(empty($data['password'])){
                exit('密码不能为空!');
            }else if(strlen($data['password']) < 6){
                exit('密码至少6位!');
            }else{
                $data['email'] = manage::customFilter($data['email']);
                /**
                 * 创建密码的散列(hash)
                 * 
                 * 1.使用默认算法散列密码,当前是 BCRYPT,并会产生 60 个字符的结果。
                 *   需要储存的空间能够超过 60 字符(255字符不错)。
                 * 2.注意 password_hash() 返回的散列包含了算法、 cost 和盐值。
                 *   因此,所有需要的信息都包含内。使得验证函数不需要储存额外盐值等信息即可验证哈希。
                 */
                $data['password'] = password_hash($data['password'], PASSWORD_DEFAULT);
                file_put_contents($file, json_encode($data));
                echo '<script>alert("注册成功!")</script>';
            }
        }
    }
    
    $tag = '';
    
    //接收参数,用于判断是否显示登陆页、注册页
    if(filter_has_var(INPUT_GET, "tag")){
        $tag   = manage::get('tag');
    }
    
    switch($tag){
        case 'register';
            $title  = '注册实例';
            $decide = false;
            $hidd   = '<input type="hidden" name="isRegister" value="display">';
            $butt   = '注册';
            break;
        case 'login':
        default:
            $title  = '登陆实例';
            $decide = true;
            $hidd   = '<input type="hidden" name="isVerify" value="display">';
            $butt   = '登陆';
    }
    
    ?>
    <?php
    /**
     * HTML 部分 #############################
     * 
     */
    ?>
    <!DOCTYPE html>
    <html>
        <head>
            <title><?=$title?></title>
            <meta charset="utf-8">
            <meta name="viewport" content="width=device-width, initial-scale=1">
            <link rel="stylesheet" href="https://cdn.staticfile.org/twitter-bootstrap/4.1.0/css/bootstrap.min.css">
            <script src="https://cdn.staticfile.org/jquery/3.2.1/jquery.min.js"></script>
            <script src="https://cdn.staticfile.org/popper.js/1.12.5/umd/popper.min.js"></script>
            <script src="https://cdn.staticfile.org/twitter-bootstrap/4.1.0/js/bootstrap.min.js"></script>
        </head>
    <body>
        <div class="container">
            <h3 style="text-align:center;color:#789"><?=$title?></h3>
            <form method="post" action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]);?>">
                <div class="form-group">
                    <label for="email">Email地址:</label>
                    <input type="text" class="form-control" id="email" name="email" maxlength="30" value="<?=$_POST['email']?>" />
                </div>
                <div class="form-group">
                    <label for="pwd">密码:</label>
                    <input type="password" class="form-control" id="pwd" name="pwd" maxlength="30" />
                </div>
                
                <?php if($decide): ?>
                
                    <div class="form-check">
                        <label class="form-check-label">
                            <input class="form-check-input" type="checkbox"> 记住我 
                        </label>
                    </div>
                
                <?php endif; ?> <?=$hidd?>
                
                <div style="text-align:right;padding-top:10px">
                    <button type="submit" class="btn btn-primary" onclick="check(event)"><?=$butt?></button>
                </div>
            </form>
            
            <?php if($decide): ?>
                <p style="padding-top:10px;text-align:center">
                    <a href="?tag=register">这里注册</a>
                </p>
            <?php endif; ?>
            
        <div>
    <?php
    /**
     * javascript 部分 #############################
     * 
     */
    ?>
        <script>
            function check(event){
                
                //邮箱字段验证
                var em = email.value;
                var reg = /^([a-zA-Z]|[0-9])+(w|-)+@[a-zA-Z0-9]+.([a-zA-Z]{2,4})$/;
                var ret = em.match(reg);
                if(ret === null){
                    event.preventDefault();
                    alert('请输入正确的邮箱格式!');
                    return false;
                }
                
                //密码字段验证
                var pass = pwd.value;
                if(isEmpty(pass)){
                    event.preventDefault();
                    alert('密码字段不能为空!');
                    return false;
                }
            }
            
            //判断字符串变量是否为空
            function isEmpty(obj){
                if(typeof obj == "undefined" || obj == null || obj == ""){
                    return true;
                }else{
                    return false;
                }
            }
        </script>
    </body>
    </html>

      XSS 攻击试验代码

      是用文件代替的数据库,刷新页面后只需点击“提交”,就会看见浏览器作出反应,提示:

    net::ERR_BLOCKED_BY_XSS_AUDITOR

    但为时已晚,已经被写入了“数据库”,只要刷新页面,就会看见提示框,如果能写提示框,当然也能写些别的代码,如非法获取 cookie,造成 cookie 劫持和 session 劫持。可以看出,浏览器的拦截简直是马后炮。此文只是希望读者有安全防范意识,不是教大家一步一步地做黑客,怎么干坏事,当然是该写的才写,不该写的不写。今天使用的代码如下:

    <img src=x onerror=alert("OK")>

    这个应该不难理解,img 标签读不出图片,会触发 onerror 事件,引号内的 js 代码会执行,所以要记得 js 代码并不一定要在js 标签内执行。

      XSS 攻击实验代码如下:

    <?php
    
    //模拟写入数据库
    if(!empty($_REQUEST['user'])){
        file_put_contents('test.txt', $_REQUEST['user']);
    }
    
    //模拟从数据库取出数据
    @$str = file_get_contents('test.txt');
    ?>
    
    <!DOCTYPE html>
    <html>
        <head>
            <title>XSS 攻击试验</title>
            <meta charset="utf-8">
            <meta name="viewport" content="width=device-width, initial-scale=1">
            <link rel="stylesheet" href="https://cdn.staticfile.org/twitter-bootstrap/4.1.0/css/bootstrap.min.css">
            <script src="https://cdn.staticfile.org/jquery/3.2.1/jquery.min.js"></script>
            <script src="https://cdn.staticfile.org/popper.js/1.12.5/umd/popper.min.js"></script>
            <script src="https://cdn.staticfile.org/twitter-bootstrap/4.1.0/js/bootstrap.min.js"></script>
        </head>
    <body>
        <div class="container">
            <?=$str?>
            <form action="" method="post">
                <input name="user" id="user">
                <input type="submit" class="btn btn-primary" value="提交" />
            </form>
        <div>
    <script>
        user.value = '<img src=x onerror=alert("ok") style=display:none>';
    </script>
    </body>
    </html>

      下面一条是编码后的 XSS 代码,经测试后会弹出警告框,能有效攻击,虽然此代码是无害的,万一别有用心的人写的不是弹框呢。

    <img src=x onerror="&#0000106&#0000097&#0000118&#0000097&#0000115&#0000099&#0000114&#0000105&#0000112&#0000116&#0000058&#0000097&#0000108&#0000101&#0000114&#0000116&#0000040&#0000039&#0000088&#0000083&#0000083&#0000039&#0000041">
  • 相关阅读:
    android ndk通过遍历和删除文件
    SVN提交忽略*.class、.classpath、.mymetadata、.project、.settings、.myeclipse和其他非版本控制文件
    JDBC加载过程
    JVMTI 中间JNI系列功能,线程安全和故障排除技巧
    【Python】Python与文本处理langid工具包的文本语言检测和歧视
    SQL 存储过程 分页
    Android:仿手机QQ朋友动态ListView
    再说Java EE
    辛星与您解读PHP页面跳转的几种实现方式
    VS2010 使用TeeChart画图控件
  • 原文地址:https://www.cnblogs.com/qingsong/p/13782601.html
Copyright © 2011-2022 走看看