PHP笔记-随机生成cookie、后台检索、通过session获取ID增强安全性

x33g5p2x  于2022-03-07 转载在 其他  
字(4.5k)|赞(0)|评价(0)|浏览(345)

PHP笔记-用户登录&权限拦截说明

这篇博文中设置Cookie时用的是数据库的用户id。这样有问题,用户可以随意改动ID,从而获取不同的用户权限。

这里我们更新下,增加点安全性。构造safe包

内容如下:

CookieAndSession.php

<?php

namespace safe;

class CookieAndSession{

    public $cookie;
    public $userId;
    public $browser;
    public $os;
    public $timeToLive;
}

CookieTool.php

<?php

namespace safe;

class CookieTool{

    protected function generateKey(): string{

        $length = 32;
        $retKey = "";
        for ($i = 0; $i < $length; $i++)
        {
            $retKey .= chr(mt_rand(33, 126));
        }
        return $retKey;
    }

    protected function getIPAddress(): string{

        $ipaddress = "";

        if (isset($_SERVER['HTTP_CLIENT_IP']))
            $ipaddress = $_SERVER['HTTP_CLIENT_IP'];
        else if(isset($_SERVER['HTTP_X_FORWARDED_FOR']))
            $ipaddress = $_SERVER['HTTP_X_FORWARDED_FOR'];
        else if(isset($_SERVER['HTTP_X_FORWARDED']))
            $ipaddress = $_SERVER['HTTP_X_FORWARDED'];
        else if(isset($_SERVER['HTTP_FORWARDED_FOR']))
            $ipaddress = $_SERVER['HTTP_FORWARDED_FOR'];
        else if(isset($_SERVER['HTTP_FORWARDED']))
            $ipaddress = $_SERVER['HTTP_FORWARDED'];
        else if(isset($_SERVER['REMOTE_ADDR']))
            $ipaddress = $_SERVER['REMOTE_ADDR'];
        else
            $ipaddress = 'UNKNOWN';

        return $ipaddress;
    }

    protected function getBrowser($agent): string{

        $browserAgent = "";
        if(strstr($agent, 'MSIE')) {

            $browserAgent="Internet Explorer";
        }
        else if(strstr($agent, 'Opera')) {

            $browserAgent="Opera";
        }
        else if(strstr($agent, 'Firefox')) {

            $browserAgent="Firefox";
        }
        else if(strstr($agent, 'Chrome')) {

            $browserAgent = "Chrome";
        }
        else if(strstr($agent, 'Safari')) {

            $browserAgent = "Safari";
        }
        else{

            $browserAgent = "unknown";
        }

        return $browserAgent;
    }

    protected function getPlatform($agent): string{

        $agent = strtolower($agent);
        $platform = "";
        if(strstr($agent, 'win')) {

            $platform="windows";
        }
        else if(strstr($agent, 'linux')) {

            $platform = "linux";
        }
        else{

            $platform = "unknown";
        }

        return $platform;
    }

    protected function getMacAddress(): string{

        $MAC = exec('getmac');
        print_r($MAC);
        $MAC = strtok($MAC, ' ');
        return $MAC;
    }

    public function printCookieArray(){

        global $cookieAndSessionArray;
        print_r($cookieAndSessionArray);
    }

    public function setCookieByUserId($userId){

        $userToken = $this->generateKey();

        $browserAgent = $this->getBrowser($_SERVER['HTTP_USER_AGENT']);
        $platform = $this->getPlatform($_SERVER['HTTP_USER_AGENT']);

        $cookieAndSession = new CookieAndSession();
        $cookieAndSession->cookie = $userToken;
        $cookieAndSession->userId = $userId;
        $cookieAndSession->browser = $browserAgent;
        $cookieAndSession->os = $platform;
        $cookieAndSession->timeToLive = 24 * 60 * 60;

        @session_start();
        $_SESSION["user"] = serialize($cookieAndSession);
        setcookie('userToken',$userToken ,time() + 1 * 24 * 3600);
    }
}

因为这里我用的是自定义MVC框架,在每次加载的时候,会调用如下start函数:

public static function start(){

        self::setPath();
        self::setConfig();
        self::setSafe();
        self::setUrl();
        self::setAutoLoad();
        self::setDispatch();
    }

其中setSafe()就是新加的,作用是加载对应的php文件

private static function setSafe(){

        $files = self::getAllFile(SAFE_PATH);
        foreach($files as $file){

            if(file_exists($file)){

                include $file;
            }
        }
    }

其中getAllfile是获取当前目录下的所有文件,如下:

private static function getAllFile($dir): array{

        $retArray = array();

        if(!is_dir($dir))
            return $retArray;

        $files = scandir($dir);
        foreach ($files as $file){

            $tmpFile = $dir . "/" . $file;
            if(!is_dir($tmpFile)){

                array_push($retArray, $dir . "/" . $file);
            }
        }

        return $retArray;
    }

其中SAFE_PATH如下:

ROOT_PATH在index.php中定义的,如下:

index.php

<?php

    define("ROOT_PATH", str_replace("\\", "/", dirname(__DIR__)) . "/");
    include ROOT_PATH . "core/App.php";

    \core\App::start();

当用户点击登录后:

其userToken就为随机数了

后台登录校验是这样的:

public function check(){

        $useName = trim($_POST["userName"]);
        $password = trim($_POST["password"]);
        $captcha = trim($_POST["captcha"]);

		......
		......
		......

        $cookieTool = new CookieTool();
        $cookieTool->setCookieByUserId($user['user_id']);

        $this->success("登录成功", '', 'dashboard', "index");
    }

权限拦截如下:

public function __construct(){

        include VENDOR_PATH . "smarty/Smarty.class.php";
        $this->smarty = new \Smarty();
        $this->smarty->template_dir = APP_PATH . P . "/view/";
        $this->smarty->compile_dir = RESOURCES_PATH . "views";

        if(strtolower(C) != "privilege"){

            if(isset($_COOKIE['userToken'])){

                @session_start();
                $obj = unserialize($_SESSION["user"]);
                if(strcmp($_COOKIE['userToken'], $obj->cookie) != 0){

                    $this->error("未登录,请先登录", "user", "privilege", "login");
                }

                $userModel = new UserModel();
                $user = $userModel->getById((int)$obj->userId);
                if($user){

                    return;
                }
            }

            $this->error("未登录,请先登录", "user", "privilege", "login");
        }
    }

相关文章