【PHP/杂谈】一些关于软件层面校验客户端安全的小方法

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/o0DarkNessYY0o/article/details/80773928

一、前言

        时隔一年!一年啊!我又回来啦!!!

        这一年生活节奏也是过得贼快贼快的,面试、转正、职称评定、接二连三的项目等等,都不是我停更的理由,其实呢,主要是。。。。我。。。换手机+忘记密码了[汗]。

        经过这教训以后,很好!神马东西都绑定了,下次忘密码就容易找回来点吧~哈哈

        是不是又碰到久违的话痨了~行行行!我马上写正文!好久不回来了,总得让我唠嗑两句吧~

二、正文!前的唠嗑X2

        由于都是边学边做的,因此这块我都会定期更新续集,还有一个就是这种安全理念不管啥语言都是通用的,我最近做PHP,就用PHP来做栗子了,以后用Java啊,Py啊神马的时候再写,那就是内个语言的源码了,希望大伙儿看了思路以后能够跨一下语言,移植一下,相信都是不难哒~

三、思路!PHP校验客户端安全性的——小方法

0、节约大神时间请看

        咱先说个思路吧,也不耽误大神的时间,这篇文讲的是web应用开发这块的两个软件层面的客户端安全校验,一个是请求类型的锁定,另一个是严格访问来源校验。

1、请求类型锁定

        顾名思义啊,就是检验GET和POST,再加一个Ajax。

        为什么要检验呢!?

        这个其实是一个软件层面比较基本的安全校验,咱打个比方吧,比如下面写到的一个Ajax:

    $.ajax({
        url: baseURL + "AjaxGetSomeParams",
        type: "POST",
        data: param,
        async: false,
        headers: {
            "content-type": "application/x-www-form-urlencoded Access-Control-Allow-Origin"
        },
        success: function (data, status) {//如果调用php成功
            var result = eval("(" + data + ")");

            // do something X1 ...

        },
        error: function (data) {

            // do something X2 ...

        },
        complete: function (XMLHttpRequest, status) {

            // do something X3 ...

         }
    });

        我们需要Ajax从服务器获取数据,之后调整页面内的一些布局,然而这点就会被爬虫er看上了,拼命的在URL上进行访问AjaxGetSomeParams页面,哦豁,糟了,神马数据都被爬完了,这时候如果咱的软件能够检测出AjaxGetSomeParams页面是否是通过Ajax来访问的,就可以暂且规避一些诸如上所述的情况了。

        下面放这个请求类型锁定的源码,有部分内容需要关联上下文的,我在文末放上整个文章的工具类出来就可以啦~忘了说明一下,是CI框架的,其实都是通用的,无碍~无碍哈~

    /**
     * 描述:
     *      检查是否是对应的访问类型,若不是,则跳转警告页面
     *      该是GET的就GET,该POST的就POST,Ajax的就Ajax,检查的是混淆安全
     * 参数:
     *      $True_Type:正确的访问方式:0 -> GET访问,1 -> POST访问,2 -> Ajax访问
     * 返回:
     *      访问方式正确->true,访问方式错误->false
     * 用法:
     *      // [$True_Type]访问类型安全检查
     *      $this -> load -> library('safety');
     *      if(!$this -> safety -> NotSafetyVisitCheck([$True_Type])) return;
     */
    public function NotSafetyVisitCheck($True_Type){
        if($True_Type == 0) {

            // 非GET的异常请求处理
            if(!IS_GET) {
                $CI = &get_instance();
                $CI->load->helper('captcha');
                $ip = $CI->input->ip_address();

                $data['title'] = "嘿!干嘛呢";
                $data['content'] = $ip."童鞋,你咋想的通过这个方式来看这个页面哦~<br/>这链接只能GET请求的哦!";
                $CI->load->vars($data);

                // 绑定显示的视图
                $CI->load->view('phone\templates\header');
                $CI->load->view('phone\email_check_finish');
                $CI->load->view('phone\templates\footer');
                return false;
            }
        } else if ($True_Type == 1) {

            // 非POST的异常请求处理
            if(!IS_POST) {
                $CI = &get_instance();
                $CI->load->helper('captcha');
                $ip = $CI->input->ip_address();

                $data['title'] = "嘿!干嘛呢";
                $data['content'] = $ip."童鞋,你咋想的通过这个方式来看这个页面哦~<br/>这链接只能POST请求的哦!";
                $CI->load->vars($data);

                // 绑定显示的视图
                $CI->load->view('phone\templates\header');
                $CI->load->view('phone\email_check_finish');
                $CI->load->view('phone\templates\footer');
                return false;
            }
        } else if ($True_Type == 2) {

            // 非Ajax或POST的异常请求处理
            if(!IS_AJAX || !IS_POST) {
                $CI = &get_instance();
                $CI->load->helper('captcha');
                $ip = $CI->input->ip_address();

                echo $ip."童鞋,你咋想的通过这个方式来看这个页面哦~<br/>这链接只能Ajax请求的哦!";
                return false;
            }
        } else {

            $CI = &get_instance();
            $CI->load->helper('captcha');
            $ip = $CI->input->ip_address();

            $data['title'] = "嘿!干嘛呢";
            $data['content'] = $ip."童鞋,你你你这想法很危险呀~快联系我,咱来相互学习呀~";
            $CI->load->vars($data);

            // 绑定显示的视图
            $CI->load->view('phone\templates\header');
            $CI->load->view('phone\email_check_finish');
            $CI->load->view('phone\templates\footer');
            return false;
        }
        return true;
    }

2、严格访问来源校验

        聪明的童鞋估计看了上面这个就有点不下去了,这很明显有个BUG嘛,比如爬虫er写个页面,页面里面加个Ajax,然后通过Ajax的success回调把获取到的内容再显示出来不就照样拿得到嘛,嘿嘿~接下来的这个方法就是解决这个问题的啦~

        其实呢,我感觉这个也可以叫做防跨域,只不过跨域好多地方都用得上,已经搞不清楚定义了,我们先理解下这个方法的思路!

        这个方法通过校验当前访问来源的URL地址,如果是Ajax的话还要加上Ajax上一级访问来源,即Ajax请求所在页面的URL地址,通过字符串比对,把理论上访问URL和实际访问URL进行比对,进而达到防止这类型的爬虫~

        同样是CI的源码,理解思路了都是可以通用的

    /**
     *描述:
     *      检查是否是跨域请求,若是,则跳转警告页面
     *      该是我这个域名的接口就是只能我这个域名来访问,外来域名的全都是想来坑我数据的
     * 参数:
     *      $True_Uper:正确的上一页URL地址(若非Ajax则可以为空)
     *      $True_Thiser:正确当前页URL地址
     *      $Is_Ajax:是(true)否(false)应是Ajax访问
     * 返回:
     *      合法请求->true,非法跨域请求->false
     * 用法:
     *      $this -> load -> library('safety');
     *      if(!$this -> safety -> NoCrossDomainAccess([$True_Uper], [$True_Thiser], [$Is_Ajax])) return;
     */
    public function NoCrossDomainAccess($True_Uper, $True_Thiser, $Is_Ajax){

        // 访问源是Ajax,则肯定有发起页和Ajax请求URL
        if($Is_Ajax) {

            // 当前访问的URL地址
            $thisUrl = $this::curPageURL();

            // stripos(a, b); 查找字符串b在字符串a中第一次出现的位置
            // 若当前URL和真实URL不符,或当前页面的上一页URL和真实上一页URL不符,则判断是跨域请求
            if(!isset($_SERVER['HTTP_REFERER']) || stripos($_SERVER['HTTP_REFERER'], $True_Uper) === false || !isset($thisUrl) || stripos($thisUrl, $True_Thiser) === false) {

                $CI = &get_instance();
                $CI->load->helper('captcha');
                $ip = $CI->input->ip_address();

                echo $ip."童鞋,干嘛这么认真冲动呢!?<br/>为何要跨Ajax来请求呢?";

                return false;
            }
        } else { // 访问源不是Ajax,则只有发起页的POST或GET

            // 当前访问的URL地址
            $thisUrl = $this::curPageURL();

            // stripos(a, b); 查找字符串b在字符串a中第一次出现的位置
            // 若当前URL和真实URL不符,或当前页面的上一页URL和真实上一页URL不符,则判断是跨域请求
            if(stristr($thisUrl, $True_Thiser) === false) {

                $CI = &get_instance();
                $CI->load->helper('captcha');
                $ip = $CI->input->ip_address();

                $data['title'] = "嘿!友仔!";
                $data['content'] = $ip."童鞋,干嘛这么认真冲动呢!?<br/>为何要跨POST/GET来请求呢?";
                $CI->load->vars($data);

                // 绑定显示的视图
                $CI->load->view('phone\templates\header');
                $CI->load->view('phone\email_check_finish');
                $CI->load->view('phone\templates\footer');

                return false;
            }
        }

        return true;
    }

四、工具类源码

        哎~其实讲这么多还不如撸源码,工具类源码奉上!注释管饱!

<?php
    defined('BASEPATH') OR exit('No direct script access allowed');

    /**
     * 用以区分AJax还是POST的导入
     * if(IS_AJAX) { ... }
     * if(IS_POST) { ... }
     * 或者
     * if(IS_AJAX) { ... }
     * else { ... }
     */
    define('IS_AJAX', isset($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest');
    define('IS_POST', strtolower($_SERVER['REQUEST_METHOD']) == 'post');
    define('IS_GET', strtolower($_SERVER['REQUEST_METHOD']) == 'get');

    /**
     * Created by DNYY
     * User: DarkNessYY
     * Content: 这是专门用来封装检查客户端安全方法的一个校验工具类
     */
    class Safety {

        /**
         * 描述:
         *      检查是否是对应的访问类型,若不是,则跳转警告页面
         *      该是GET的就GET,该POST的就POST,Ajax的就Ajax,检查的是混淆安全
         * 参数:
         *      $True_Type:正确的访问方式:0 -> GET访问,1 -> POST访问,2 -> Ajax访问
         * 返回:
         *      访问方式正确->true,访问方式错误->false
         * 用法:
         *      // [$True_Type]访问类型安全检查
         *      $this -> load -> library('safety');
         *      if(!$this -> safety -> NotSafetyVisitCheck([$True_Type])) return;
         */
        public function NotSafetyVisitCheck($True_Type){
            if($True_Type == 0) {

                // 非GET的异常请求处理
                if(!IS_GET) {
                    $CI = &get_instance();
                    $CI->load->helper('captcha');
                    $ip = $CI->input->ip_address();

                    $data['title'] = "嘿!干嘛呢";
                    $data['content'] = $ip."童鞋,你咋想的通过这个方式来看这个页面哦~<br/>这链接只能GET请求的哦!";
                    $CI->load->vars($data);

                    // 绑定显示的视图
                    $CI->load->view('phone\templates\header');
                    $CI->load->view('phone\email_check_finish');
                    $CI->load->view('phone\templates\footer');
                    return false;
                }
            } else if ($True_Type == 1) {

                // 非POST的异常请求处理
                if(!IS_POST) {
                    $CI = &get_instance();
                    $CI->load->helper('captcha');
                    $ip = $CI->input->ip_address();

                    $data['title'] = "嘿!干嘛呢";
                    $data['content'] = $ip."童鞋,你咋想的通过这个方式来看这个页面哦~<br/>这链接只能POST请求的哦!";
                    $CI->load->vars($data);

                    // 绑定显示的视图
                    $CI->load->view('phone\templates\header');
                    $CI->load->view('phone\email_check_finish');
                    $CI->load->view('phone\templates\footer');
                    return false;
                }
            } else if ($True_Type == 2) {

                // 非Ajax或POST的异常请求处理
                if(!IS_AJAX || !IS_POST) {
                    $CI = &get_instance();
                    $CI->load->helper('captcha');
                    $ip = $CI->input->ip_address();

                    echo $ip."童鞋,你咋想的通过这个方式来看这个页面哦~<br/>这链接只能Ajax请求的哦!";
                    return false;
                }
            } else {

                $CI = &get_instance();
                $CI->load->helper('captcha');
                $ip = $CI->input->ip_address();

                $data['title'] = "嘿!干嘛呢";
                $data['content'] = $ip."童鞋,你你你这想法很危险呀~,来相互学习呀~";
                $CI->load->vars($data);

                // 绑定显示的视图
                $CI->load->view('phone\templates\header');
                $CI->load->view('phone\email_check_finish');
                $CI->load->view('phone\templates\footer');
                return false;
            }
            return true;
        }

        /**
         * 描述:
         *      检查是否是跨域请求,若是,则跳转警告页面
         *      该是我这个域名的接口就是只能我这个域名来访问,外来域名的全都是想来坑我数据的
         * 参数:
         *      $True_Uper:正确的上一页URL地址(若非Ajax则可以为空)
         *      $True_Thiser:正确当前页URL地址
         *      $Is_Ajax:是(true)否(false)应是Ajax访问
         * 返回:
         *      合法请求->true,非法跨域请求->false
         * 用法:
         *      $this -> load -> library('safety');
         *      if(!$this -> safety -> NoCrossDomainAccess([$True_Uper], [$True_Thiser], [$Is_Ajax])) return;
         */
        public function NoCrossDomainAccess($True_Uper, $True_Thiser, $Is_Ajax){

            // 访问源是Ajax,则肯定有发起页和Ajax请求URL
            if($Is_Ajax) {

                // 当前访问的URL地址
                $thisUrl = $this::curPageURL();

                // stripos(a, b); 查找字符串b在字符串a中第一次出现的位置
                // 若当前URL和真实URL不符,或当前页面的上一页URL和真实上一页URL不符,则判断是跨域请求
                if(!isset($_SERVER['HTTP_REFERER']) || stripos($_SERVER['HTTP_REFERER'], $True_Uper) === false || !isset($thisUrl) || stripos($thisUrl, $True_Thiser) === false) {

                    $CI = &get_instance();
                    $CI->load->helper('captcha');
                    $ip = $CI->input->ip_address();

                    echo $ip."童鞋,干嘛这么认真冲动呢!?<br/>为何要跨Ajax来请求呢?";

                    return false;
                }
            } else { // 访问源不是Ajax,则只有发起页的POST或GET

                // 当前访问的URL地址
                $thisUrl = $this::curPageURL();

                // stripos(a, b); 查找字符串b在字符串a中第一次出现的位置
                // 若当前URL和真实URL不符,或当前页面的上一页URL和真实上一页URL不符,则判断是跨域请求
                if(stristr($thisUrl, $True_Thiser) === false) {

                    $CI = &get_instance();
                    $CI->load->helper('captcha');
                    $ip = $CI->input->ip_address();

                    $data['title'] = "嘿!友仔!";
                    $data['content'] = $ip."童鞋,干嘛这么认真冲动呢!?<br/>为何要跨POST/GET来请求呢?";
                    $CI->load->vars($data);

                    // 绑定显示的视图
                    $CI->load->view('phone\templates\header');
                    $CI->load->view('phone\email_check_finish');
                    $CI->load->view('phone\templates\footer');

                    return false;
                }
            }

            return true;

            // $_SERVER['HTTP_REFERER']当前页面的前一个页面地址,$this::curPageURL()是当前页面的地址
            // echo $_SERVER['HTTP_REFERER']."|".$this::curPageURL();

        }

        /**
         * 描述:
         *      获取当前页面的完整URL路径
         * 参数:
         *      无
         * 返回:
         *      当前页面的完整URL,带HTTP头、参数等
         * 用法:
         *      直接调用获取返回值即可
         */
        function curPageURL() {

            $pageURL = 'http';

            if (isset( $_SERVER["HTTPS"] ) && strtolower( $_SERVER["HTTPS"] ) == "on") {
                $pageURL .= "s";
            }
            $pageURL .= "://";

            if ($_SERVER["SERVER_PORT"] != "80") {
                $pageURL .= $_SERVER["SERVER_NAME"] . ":" . $_SERVER["SERVER_PORT"] . $_SERVER["REQUEST_URI"];
            } else {
                $pageURL .= $_SERVER["SERVER_NAME"] . $_SERVER["REQUEST_URI"];
            }
            return $pageURL;
        }

    }

?>

五、后话

        写完收工!久不发文,甚是想念,希望大扎多多支持,三口再三口!

猜你喜欢

转载自blog.csdn.net/o0DarkNessYY0o/article/details/80773928
今日推荐