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

一、前言

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

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

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

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

二、正文!前的唠嗑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."童鞋,你咋想的通过这个方式来看这个页面哦~
这链接只能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."童鞋,你咋想的通过这个方式来看这个页面哦~
这链接只能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."童鞋,你咋想的通过这个方式来看这个页面哦~
这链接只能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."童鞋,干嘛这么认真冲动呢!?
为何要跨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."童鞋,干嘛这么认真冲动呢!?
为何要跨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; }

四、工具类源码

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


    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."童鞋,你咋想的通过这个方式来看这个页面哦~
这链接只能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."童鞋,你咋想的通过这个方式来看这个页面哦~
这链接只能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."童鞋,你咋想的通过这个方式来看这个页面哦~
这链接只能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."童鞋,干嘛这么认真冲动呢!?
为何要跨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."童鞋,干嘛这么认真冲动呢!?
为何要跨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; } } ?>

五、后话

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

你可能感兴趣的:(PHP,杂谈)