cari
Rumahpembangunan bahagian belakangtutorial phpYii2 中CSRF的疑问(完结)

  1. 描述你的问题
    在开启Csrf防御的时候,默认csrf的值只能使用一次,第二次提交就是验证不通过,因为已经使用过了,那么如何做下面这种效果呢?

Yii2 中CSRF的疑问(完结)

如图,该页面是Ajax提交请求,那么第一个按钮点击后csrf值失效了,第二次提交失败返回400错误,求解!
怎么让csrf的值可以刷新后用于第二次请求。

不要让我关闭csrf,csrf本来就是为了防御这种请求的。

经过楼下兄弟的指点,现分析如下,
在使用他自带的表单的时候,\yii\helpers\BaseHtml::beginForm 方法中有判断,如果在一次页面展示中多次调用表单创建,则每次获取的csrf都是一样的,也就是说,同一页面多个表单,都可用的。
我们知道csrf验证是在\yii\web\Request类中,但是该类在初始化的时候我并没有看到他有检查csrf,所以我们需要知道他是在哪里进行检查的,通过全文搜索,发现在\yii\web\Controller类的beforeAction方法中有检查,原型如下:

<code>/**
     * @inheritdoc
     */
    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;
    }</code>

通过该代码我们知道,在检查csrf是直接使用的\yii\web\Request::validateCsrfToken方法,在该方法中先通过loadCsrfToken方法获取csrf,

<code>/**
     * Loads the CSRF token from cookie or session.
     * @return string the CSRF token loaded from cookie or session. Null is returned if the cookie or session
     * does not have CSRF token.
     */
    protected function loadCsrfToken()
    {
        if ($this->enableCsrfCookie) {
            return $this->getCookies()->getValue($this->csrfParam);
        } else {
            return Yii::$app->getSession()->get($this->csrfParam);
        }
    }</code>

这个代码很好理解,就是cookie取,没开的话就在session取,然后返回。
然后通过validateCsrfTokenInternal方法验证csrf token,通过跟踪代码发现,在验证完csrf后并没有删除该csrf,换句话说就是该csrf还是可以用的,只要你页面不刷新,因为页面刷新时在 你布局文件的头部会有个 = Html::csrfMetaTags() ?>用来输出csrf,这时候上一个csrf就会失效的。所以说一个页面不停地AJAX请求,只要不刷新是没问题的。
结论:
在yii中一共有如下几个地方会刷新csrf
\yii\helpers\BaseHtml::beginFormHtml::csrfMetaTags()\yii\web\Request::getCsrfToken,关键点在\yii\web\Request::getCsrfToken方法里如楼下兄弟所言,$regenerate 参数也可以控制强制重新生成csrf token.

<code>private $_csrfToken;

    /**
     * Returns the token used to perform CSRF validation.
     *
     * This token is a masked version of [[rawCsrfToken]] to prevent [BREACH attacks](http://breachattack.com/).
     * This token may be passed along via a hidden field of an HTML form or an HTTP header value
     * to support CSRF validation.
     * @param boolean $regenerate whether to regenerate CSRF token. When this parameter is true, each time
     * this method is called, a new CSRF token will be generated and persisted (in session or cookie).
     * @return string the token used to perform CSRF validation.
     */
    public 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;
    }</code>

该方法在获取csrftoken的时候判断 $this->_csrfToken是否是空的,按照页面正常加载来说程序一启动肯定是空的,这个值不是存客户端的,这个也不是从服务端获取的,是页面启动后就是空的,只有执行该方法后生成的csrf token才会放入cookiesession,也就是说在同一个请求中多次执行该方法,获取的csrf token都是一样的,如果一个新页面请求到该方法就会重新生成,这也是不同页面刷新为何csrf token一直变的原因,所以,csrf token值可多次使用,但是只限当前页面的ajax请求。

我的系统问题是由于我使用的是IIS 10作为Web,又开了Url重写,默认不存在的文件或文件夹都会重写给Yii处理,然而我没有在web目录下放置传说中的favicon.ico文件,导致有个404,这个是浏览器在后台自动请求的,导致yii输出了一个404,而我不知道,404页面又调用了布局,导致csrf token 被刷新了。很二是吧。。。。。。

回复内容:

  1. 描述你的问题
    在开启Csrf防御的时候,默认csrf的值只能使用一次,第二次提交就是验证不通过,因为已经使用过了,那么如何做下面这种效果呢?

Yii2 中CSRF的疑问(完结)

如图,该页面是Ajax提交请求,那么第一个按钮点击后csrf值失效了,第二次提交失败返回400错误,求解!
怎么让csrf的值可以刷新后用于第二次请求。

不要让我关闭csrf,csrf本来就是为了防御这种请求的。

经过楼下兄弟的指点,现分析如下,
在使用他自带的表单的时候,\yii\helpers\BaseHtml::beginForm 方法中有判断,如果在一次页面展示中多次调用表单创建,则每次获取的csrf都是一样的,也就是说,同一页面多个表单,都可用的。
我们知道csrf验证是在\yii\web\Request类中,但是该类在初始化的时候我并没有看到他有检查csrf,所以我们需要知道他是在哪里进行检查的,通过全文搜索,发现在\yii\web\Controller类的beforeAction方法中有检查,原型如下:

<code>/**
     * @inheritdoc
     */
    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;
    }</code>

通过该代码我们知道,在检查csrf是直接使用的\yii\web\Request::validateCsrfToken方法,在该方法中先通过loadCsrfToken方法获取csrf,

<code>/**
     * Loads the CSRF token from cookie or session.
     * @return string the CSRF token loaded from cookie or session. Null is returned if the cookie or session
     * does not have CSRF token.
     */
    protected function loadCsrfToken()
    {
        if ($this->enableCsrfCookie) {
            return $this->getCookies()->getValue($this->csrfParam);
        } else {
            return Yii::$app->getSession()->get($this->csrfParam);
        }
    }</code>

这个代码很好理解,就是cookie取,没开的话就在session取,然后返回。
然后通过validateCsrfTokenInternal方法验证csrf token,通过跟踪代码发现,在验证完csrf后并没有删除该csrf,换句话说就是该csrf还是可以用的,只要你页面不刷新,因为页面刷新时在 你布局文件的头部会有个 = Html::csrfMetaTags() ?>用来输出csrf,这时候上一个csrf就会失效的。所以说一个页面不停地AJAX请求,只要不刷新是没问题的。
结论:
在yii中一共有如下几个地方会刷新csrf
\yii\helpers\BaseHtml::beginFormHtml::csrfMetaTags()\yii\web\Request::getCsrfToken,关键点在\yii\web\Request::getCsrfToken方法里如楼下兄弟所言,$regenerate 参数也可以控制强制重新生成csrf token.

<code>private $_csrfToken;

    /**
     * Returns the token used to perform CSRF validation.
     *
     * This token is a masked version of [[rawCsrfToken]] to prevent [BREACH attacks](http://breachattack.com/).
     * This token may be passed along via a hidden field of an HTML form or an HTTP header value
     * to support CSRF validation.
     * @param boolean $regenerate whether to regenerate CSRF token. When this parameter is true, each time
     * this method is called, a new CSRF token will be generated and persisted (in session or cookie).
     * @return string the token used to perform CSRF validation.
     */
    public 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;
    }</code>

该方法在获取csrftoken的时候判断 $this->_csrfToken是否是空的,按照页面正常加载来说程序一启动肯定是空的,这个值不是存客户端的,这个也不是从服务端获取的,是页面启动后就是空的,只有执行该方法后生成的csrf token才会放入cookiesession,也就是说在同一个请求中多次执行该方法,获取的csrf token都是一样的,如果一个新页面请求到该方法就会重新生成,这也是不同页面刷新为何csrf token一直变的原因,所以,csrf token值可多次使用,但是只限当前页面的ajax请求。

我的系统问题是由于我使用的是IIS 10作为Web,又开了Url重写,默认不存在的文件或文件夹都会重写给Yii处理,然而我没有在web目录下放置传说中的favicon.ico文件,导致有个404,这个是浏览器在后台自动请求的,导致yii输出了一个404,而我不知道,404页面又调用了布局,导致csrf token 被刷新了。很二是吧。。。。。。

如果你在进行完一次请求没有手动去调用Yii::$app->request->getCsrfToken(true)的话是不会存在你说的验证不通过的问题的

Kenyataan
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
Apakah beberapa masalah biasa yang boleh menyebabkan sesi PHP gagal?Apakah beberapa masalah biasa yang boleh menyebabkan sesi PHP gagal?Apr 25, 2025 am 12:16 AM

Sebab -sebab kegagalan phpsession termasuk kesilapan konfigurasi, isu cookie, dan tamat tempoh sesi. 1. Ralat Konfigurasi: Semak dan tetapkan session.save_path yang betul. Masalah 2.Cookie: Pastikan kuki ditetapkan dengan betul. 3.Session Expires: Laraskan Nilai Sesi.GC_MAXLifetime untuk melanjutkan masa sesi.

Bagaimanakah anda menyebarkan isu berkaitan sesi dalam PHP?Bagaimanakah anda menyebarkan isu berkaitan sesi dalam PHP?Apr 25, 2025 am 12:12 AM

Kaedah untuk masalah sesi debug dalam PHP termasuk: 1. Periksa sama ada sesi dimulakan dengan betul; 2. Sahkan penghantaran ID sesi; 3. Semak penyimpanan dan bacaan data sesi; 4. Semak konfigurasi pelayan. Dengan mengeluarkan ID dan data sesi, melihat kandungan fail sesi, dan lain-lain, anda boleh mendiagnosis dan menyelesaikan masalah yang berkaitan dengan sesi.

Apa yang berlaku jika session_start () dipanggil beberapa kali?Apa yang berlaku jika session_start () dipanggil beberapa kali?Apr 25, 2025 am 12:06 AM

Pelbagai panggilan ke session_start () akan menghasilkan mesej amaran dan kemungkinan penggantian data. 1) PHP akan mengeluarkan amaran, menyebabkan sesi telah dimulakan. 2) Ia boleh menyebabkan penggantian data sesi yang tidak dijangka. 3) Gunakan session_status () untuk memeriksa status sesi untuk mengelakkan panggilan berulang.

Bagaimana anda mengkonfigurasi seumur hidup sesi di PHP?Bagaimana anda mengkonfigurasi seumur hidup sesi di PHP?Apr 25, 2025 am 12:05 AM

Mengkonfigurasi kitaran hayat sesi dalam PHP boleh dicapai dengan menetapkan sesi.gc_maxlifetime dan session.cookie_lifetime. 1) session.gc_maxlifetime mengawal masa survival data sesi pelayan, 2) session.cookie_lifetime mengawal kitaran hayat kuki klien. Apabila ditetapkan ke 0, kuki tamat apabila penyemak imbas ditutup.

Apakah kelebihan menggunakan pangkalan data untuk menyimpan sesi?Apakah kelebihan menggunakan pangkalan data untuk menyimpan sesi?Apr 24, 2025 am 12:16 AM

Kelebihan utama menggunakan sesi penyimpanan pangkalan data termasuk kegigihan, skalabilitas, dan keselamatan. 1. Kegigihan: Walaupun pelayan dimulakan semula, data sesi tidak dapat berubah. 2. Skalabiliti: Berkenaan dengan sistem yang diedarkan, memastikan data sesi disegerakkan di antara pelbagai pelayan. 3. Keselamatan: Pangkalan data menyediakan storan yang disulitkan untuk melindungi maklumat sensitif.

Bagaimana anda melaksanakan pengendalian sesi tersuai di PHP?Bagaimana anda melaksanakan pengendalian sesi tersuai di PHP?Apr 24, 2025 am 12:16 AM

Melaksanakan pemprosesan sesi tersuai dalam PHP boleh dilakukan dengan melaksanakan antara muka sessionHandlerInterface. Langkah -langkah khusus termasuk: 1) mewujudkan kelas yang melaksanakan sessionHandlerInterface, seperti CustomSessionHandler; 2) kaedah penulisan semula dalam antara muka (seperti terbuka, rapat, membaca, menulis, memusnahkan, gc) untuk menentukan kitaran hayat dan kaedah penyimpanan data sesi; 3) Daftar pemproses sesi tersuai dalam skrip PHP dan mulakan sesi. Ini membolehkan data disimpan dalam media seperti MySQL dan REDIS untuk meningkatkan prestasi, keselamatan dan skalabiliti.

Apakah ID Sesi?Apakah ID Sesi?Apr 24, 2025 am 12:13 AM

SesionID adalah mekanisme yang digunakan dalam aplikasi web untuk mengesan status sesi pengguna. 1. Ia adalah rentetan yang dijana secara rawak yang digunakan untuk mengekalkan maklumat identiti pengguna semasa pelbagai interaksi antara pengguna dan pelayan. 2. Pelayan menjana dan menghantarnya kepada klien melalui kuki atau parameter URL untuk membantu mengenal pasti dan mengaitkan permintaan ini dalam pelbagai permintaan pengguna. 3. Generasi biasanya menggunakan algoritma rawak untuk memastikan keunikan dan ketidakpastian. 4. Dalam pembangunan sebenar, pangkalan data dalam memori seperti REDIS boleh digunakan untuk menyimpan data sesi untuk meningkatkan prestasi dan keselamatan.

Bagaimanakah anda mengendalikan sesi dalam persekitaran tanpa kerakyatan (mis., API)?Bagaimanakah anda mengendalikan sesi dalam persekitaran tanpa kerakyatan (mis., API)?Apr 24, 2025 am 12:12 AM

Menguruskan sesi dalam persekitaran tanpa kerakyatan seperti API boleh dicapai dengan menggunakan JWT atau cookies. 1. JWT sesuai untuk ketiadaan dan skalabilitas, tetapi ia adalah saiz yang besar ketika datang ke data besar. 2.Cookies lebih tradisional dan mudah dilaksanakan, tetapi mereka perlu dikonfigurasikan dengan berhati -hati untuk memastikan keselamatan.

See all articles

Alat AI Hot

Undresser.AI Undress

Undresser.AI Undress

Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover

AI Clothes Remover

Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Undress AI Tool

Undress AI Tool

Gambar buka pakaian secara percuma

Clothoff.io

Clothoff.io

Penyingkiran pakaian AI

Video Face Swap

Video Face Swap

Tukar muka dalam mana-mana video dengan mudah menggunakan alat tukar muka AI percuma kami!

Alat panas

PhpStorm versi Mac

PhpStorm versi Mac

Alat pembangunan bersepadu PHP profesional terkini (2018.2.1).

Muat turun versi mac editor Atom

Muat turun versi mac editor Atom

Editor sumber terbuka yang paling popular

Versi Mac WebStorm

Versi Mac WebStorm

Alat pembangunan JavaScript yang berguna

SecLists

SecLists

SecLists ialah rakan penguji keselamatan muktamad. Ia ialah koleksi pelbagai jenis senarai yang kerap digunakan semasa penilaian keselamatan, semuanya di satu tempat. SecLists membantu menjadikan ujian keselamatan lebih cekap dan produktif dengan menyediakan semua senarai yang mungkin diperlukan oleh penguji keselamatan dengan mudah. Jenis senarai termasuk nama pengguna, kata laluan, URL, muatan kabur, corak data sensitif, cangkerang web dan banyak lagi. Penguji hanya boleh menarik repositori ini ke mesin ujian baharu dan dia akan mempunyai akses kepada setiap jenis senarai yang dia perlukan.

EditPlus versi Cina retak

EditPlus versi Cina retak

Saiz kecil, penyerlahan sintaks, tidak menyokong fungsi gesaan kod