麻豆小视频在线观看_中文黄色一级片_久久久成人精品_成片免费观看视频大全_午夜精品久久久久久久99热浪潮_成人一区二区三区四区

首頁 > 編程 > PHP > 正文

yii2 csrf驗證理分析

2020-03-22 20:12:51
字體:
來源:轉載
供稿:網友
  • 知識補充

    因為yii2 csrf的驗證的加解密 涉及到異或運算

    所以需要先補充php里字符串異或運算的相關知識,不需要的可以跳過

    ^異或運算
    不一樣返回1 否者返回 0
    在PHP語言中,經常用來做加密的運算,解密也直接用^就行
    字符串運算時 利用字符的ascii碼轉換為2進制來運算
    單個字符運算
    舉例的ascii見下表

    字符

    二進制

    ASCII

    a

    1100001

    97

    b

    1100010

    98

    c

    1100011

    99

    d

    1100100

    100

    計算結果

    運算

    二進制

    ASCII

    a^b

    0000 0011

    3

    a^c

    0000 0010

    2

    b^d

    0000 0110

    6

    ab^cd

    0000 0010

    2

    a^cd

    0000 0010

    2

    ab^c

    0000 0010

    2

    1.對于單個字符和單個字符的
    直接計算其結果即可 比如表里的a^b

    2.對于長度一樣的多個字符串 如表里的ab^cd
    計算a^c對應的結果和和b^d對應的結果 對應的字符連接起來

    <?php$str1='ab';$str2='cd';$r= $str1^$str2;var_dump($r);echo '<hr>';for($i=0;$i<strlen($r) ;$i++){    echo ord($r[$i]).'<br>';}?>

    對于不等的
    以短的字符串長度位進行計算

    Yii2的csrf token驗證
    在yii2的接收post請求時
    在如果開啟
    enableCsrfValidation為true
    在/vendor/yiisoft/yii2/web/Controller.php

    <?php   html' target='_blank'>public function beforeAction($action)    {        if (parent::beforeAction($action)) {            if ($this->enableCsrfValidation && Yii::$app->getErrorHandler()->exception === null && !Yii::$app->getRequest()->validateCsrfToken()) {                throw new BadRequestHttpException(Yii::t('yii', 'Unable to verify your data submission.'));            }            return true;        }                return false;    }?>

    會進行validateCsrfToken驗證
    在/vendor/yiisoft/yii2/web/Request.php

    <?phppublic function validateCsrfToken($token = null)    {        $method = $this->getMethod();        // only validate CSRF token on non-'safe' methods http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.1.1        if (!$this->enableCsrfValidation || in_array($method, ['GET', 'HEAD', 'OPTIONS'], true)) {            return true;        }        $trueToken = $this->loadCsrfToken();        if ($token !== null) {            return $this->validateCsrfTokenInternal($token, $trueToken);        } else {            return $this->validateCsrfTokenInternal($this->getBodyParam($this->csrfParam), $trueToken)                || $this->validateCsrfTokenInternal($this->getCsrfTokenFromHeader(), $trueToken);        }    }?>

    說明在 GET, HEAD, OPTIONS 均不驗證,除了這幾種主要用的也就post了

    說明在我們發送post請求時必須發送相關驗證的字段和值
    下面看CsrfToken產生過程
    在/vendor/yiisoft/yii2/web/Request.php里

    <?phppublic function getCsrfToken($regenerate = false)    {        if ($this->_csrfToken === null || $regenerate) {            if ($regenerate || ($token = $this->loadCsrfToken()) === null) {                $token = $this->generateCsrfToken();            }            // the mask doesn't need to be very random            $chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-.';            $mask = substr(str_shuffle(str_repeat($chars, 5)), 0, static::CSRF_MASK_LENGTH);            // The + sign may be decoded as blank space later, which will fail the validation            $this->_csrfToken = str_replace('+', '.', base64_encode($mask . $this->xorTokens($token, $mask)));        }        return $this->_csrfToken;    }?>

    會發現
    _csrfToken的產生大致如下
    如果開啟了enableCsrfCookie,
    CsrfToken就從cookie里取,否者從session里取(更安全)
    可在
    /vendor/yiisoft/yii2/web/Request.php的下面部位看到

    <?php protected function loadCsrfToken()    {        if ($this->enableCsrfCookie) {            return $this->getCookies()->getValue($this->csrfParam);        } else {            return Yii::$app->getSession()->get($this->csrfParam);        }    }?>

    從loadCsrfToken()里取出的值這里稱token

    在post里發送的也就是Yii::$app->getRequest()->csrfParam 這里稱csrfToken現在根據代碼大致說下生成和驗證的主要思路,當然自己看代碼更能細致的了解1.從cookie或者session里取出token ,當然cookie或者session里如果沒有就是初始化操作的過程了,這里初始化不是重點2.隨機產生CSRF_MASK_LENGTH(Yii2里默認是8位)長度的字符串 mask3.對mask和token進行如下運算str_replace('+', '.', base64_encode($mask . $this->xorTokens($token, $mask)));$this->xorTokens($arg1,$arg2) 是一個先補位異或運算

    傳入$arg1,$arg2
    長度短的要用自身補到長度長的字符串的位置
    見代碼部分
    在/vendor/yiisoft/yii2/web/Request.php 的如下部分

     <?php  private function xorTokens($token1, $token2)    {        $n1 = StringHelper::byteLength($token1);        $n2 = StringHelper::byteLength($token2);        if ($n1 > $n2) {            $token2 = str_pad($token2, $n1, $token2);        } elseif ($n1 < $n2) {            $token1 = str_pad($token1, $n2, $n1 === 0 ? ' ' : $token1);        }        return $token1 ^ $token2;    } ?>

    就是說如果 $arg1比$arg2短,$arg1要用自身補齊 補到和和$arg2一樣的長度
    這里為什么要這樣做?
    因為在php里
    'a'^'bc' 會只算 a^b 而不考慮c了,這里采用了向長度更長的來補
    如果用
    xorTokens來處理 'a'和'bc'
    會先把a用自己填充到和bc一樣的長度后再進行異或運算
    異或運算詳見上文補充

    str_replace('+', '.', base64_encode($mask . $this->xorTokens($token, $mask)));


    計算后即會得出在post請求時要發送的值 csrfToken

    下面是驗證過程
    1.根據 表單字段名
    Yii::$app->getRequest()->csrfParam;
    從post里拿到
    csrfToken的值
    從方法 validateCsrfToken里可以看到
    代碼
    在/vendor/yiisoft/yii2/web/Request.php 的如下部分

    <?php public function validateCsrfToken($token = null)    {        $method = $this->getMethod();        // only validate CSRF token on non-'safe' methods http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.1.1        if (!$this->enableCsrfValidation || in_array($method, ['GET', 'HEAD', 'OPTIONS'], true)) {            return true;        }        $trueToken = $this->loadCsrfToken();        if ($token !== null) {            return $this->validateCsrfTokenInternal($token, $trueToken);        } else {            return $this->validateCsrfTokenInternal($this->getBodyParam($this->csrfParam), $trueToken)                || $this->validateCsrfTokenInternal($this->getCsrfTokenFromHeader(), $trueToken);        }    }?>

    $this->getBodyParam($this->csrfParam)
    可以看出
    解密的目的就是要從
    csrfToken里取出token 然后和會話里的token比較
    見/vendor/yiisoft/yii2/web/Request.php 的如下部分

    <?php private function validateCsrfTokenInternal($token, $trueToken)    {        $token = base64_decode(str_replace('.', '+', $token));        $n = StringHelper::byteLength($token);        if ($n <= static::CSRF_MASK_LENGTH) {            return false;        }        $mask = StringHelper::byteSubstr($token, 0, static::CSRF_MASK_LENGTH);        $token = StringHelper::byteSubstr($token, static::CSRF_MASK_LENGTH, $n - static::CSRF_MASK_LENGTH);        /*          注意此時的$token在加密過程中是xorTokens($trueToken,$mask)的結果        */        $token = $this->xorTokens($mask, $token);        return $token === $trueToken;    }?>

    加密時用的是
    str_replace('+', '.', base64_encode($mask . $this->xorTokens($token, $mask)));
    解密
    1.首先要把.替換成+
    2.然后base64_decode
    再 根據長度分別取出$mask和$this->xorTokens($token, $mask) ;
    為了說明方便 $this->xorTokens($token, $mask) 這里稱作 token1
    然后
    進行mask和token1的異或運算,即得token
    注意在加密時
    token1=token^mask
    所以
    解密時
    token=mask^token1=mask^(token^mask)

    yii2
    中的核心思路
    token是從會話中取得的
    用隨機串和token進行運算處理 得到一個加密串
    驗證的時候通過這個加密串解密出來這個token和會話里的值進行比較

    PHP編程

    鄭重聲明:本文版權歸原作者所有,轉載文章僅為傳播更多信息之目的,如作者信息標記有誤,請第一時間聯系我們修改或刪除,多謝。

  • 發表評論 共有條評論
    用戶名: 密碼:
    驗證碼: 匿名發表
    主站蜘蛛池模板: 日韩不卡一区二区 | 国产一区二区在线免费 | 最新中文字幕免费视频 | 国产精品一区免费在线观看 | 日韩视频一 | 黄wwww | 国产精品视频在线观看免费 | 久久久久久久.comav | 日韩视频在线视频 | av电影在线网 | 国产成人精品网站 | 今井夏帆av一区二区 | 古装三级在线观看 | 精品久久久久久久久中文字幕 | 91美女视频在线观看 | 国产一级桃视频播放 | 羞羞视频免费网站含羞草 | av在线免费电影 | 色猫av| 第一区免费在线观看 | 欧美日韩亚洲另类 | 天天透天天狠天天爱综合97 | 青青国产在线视频 | 国产91丝袜在线播放 | www.99久久久| 黄色特级片黄色特级片 | 欧美一区二区三区久久精品视 | 国产精品国产三级国产在线观看 | 久久久久久久久国产精品 | 欧美精品久久久久久久久久 | 欧美一级美国一级 | 亚洲成人涩涩 | 欧美精品一区二区三区在线 | 99综合视频| 99在线热播精品免费 | 亚洲国产精品一区二区三区 | 亚洲日色 | 视频二区国产 | 免费试看av| 久久777国产线看观看精品 | 日韩视频高清 |