页面做静态化后,csrf值如何获取?

公司网站使用了Laravel 6.0框架,前端页没有做任何静态化处理,完全由Laravel输出。为了加速网站运行,公司想把网站页面做静态化。为了节省改动代码成本,我们打算用扩展插件生成静态页,或在负载中缓存网站源服务器的页面。页面如何静态化虽然解决了,但有个最大问题就是,不少页面在使用表单提交(或ajax的post提交),都一直在使用csrf保护验证。一旦页面静态化了,csrf token值就会因为页面静态化,所有网站访客都使用同一个csrf值。
为了安全,我们不可能关掉csrf保护。所以我们考虑的方案:csrf值只能在页面加载的时候,通过js脚本ajax请求来获取,再由js重新赋值给表单的_token隐藏元素。

根据这个方案,我们在所有网页blade模板的共同header头部加入以下脚本来获取token值:

获取token值解决了,但却出现新的问题,有些页面的脚本在没等待上图的ajax返回token值,就已经提交post了,结果返回419;有些页面的表单在加载时网速稍有变化没加载完,就没有被上图脚本赋值到隐藏token元素中,可是上图的代码已经在jq的ready加载完后执行啊。。。。于是我们就进入了脚本执行顺序的坑了,估计每个改动过的表单页都可能存在这些问题。。。

问下有经验的各位,你们的页面在做静态化时,这个csrf是怎么处理的?有没什么办法可以很好地解决?

《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。
《L04 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
讨论数量: 23

等待中,显示未 loading 状态,不让用户提交表单

1年前
window.isLoadedCsrfToken = false;
function initCsrfToken(callback){
      if(isLoadedCsrfToken){
         return callback();
      }
         $.ajax({
             url:'',
             success:function(res){
                 isLoadedCsrfToken  = true;
                  callback();
             }
       })
}

initCsrfToken(()=>{
      // 页面逻辑1

});

initCsrfToken(()=>{
      // 页面逻辑2

});
1年前 评论
xiwang6428 (楼主) 1年前

ajax获取的token。。能防御啥?

1年前 评论
minororange 1年前
bestlang 1年前

查看 laravel 的路由,会有一条这样一个路由:sanctum/csrf-cookie

说下我的想法吧,csrf 不是万能的

  • 所有页面维护一个 csrf,可以存到 cookie,也可以存储到 localstorage
  • 每次提交后刷新 csrf 值
  • 新打开的页面获取新的 csrf ,即不存在即刷新

csrf 自动识别的位置

  • cookie 中的 XSRF-TOKEN
  • header 中的 X-CSRF-TOKEN
  • form 表单中的 _token input 文本框

详见中间件 \App\Http\Middleware\VerifyCsrfToken::class 代码

1年前 评论
xiwang6428 (楼主) 1年前

1.csrf 检查 去掉,用其他方法替代 2.form表单页面,不静态化,采用服务端渲染csrf_token

1年前 评论
xiwang6428 (楼主) 1年前

如果是apache的话可以这样,将form表单的这部分代码 使用请求php的方式,例如 <!--#include virtual="/index.php"--> 不必局限于框架

1年前 评论
xiwang6428 (楼主) 1年前

AJAX 请求事实上你页面不刷新 csrf 一直可用的,不用每次都获取,你可以放cookie

1年前

因为页面静态化了,所以解析的工作就不是php-fpm了,而是nginx直接按照文件返回,所以只能用js来处理,
当然也可以更换静态化规则,有php-fpm预处理一遍,替换掉csrf,不过这样有点本末倒置了

或者使用nginx脚本来替换文件内容再返回

1年前
$.ajaxSetup({
    headers: {
        'X-CSRF-TOKEN': GetCookie("XSRF-TOKEN")
    }
});

  function GetCookie(name) {
    let arr = document.cookie.match(new RegExp("(^| )" + name + "=([^;]*)(;|$)"));
    if (arr != null) return unescape(arr[2]);
    return null;
}

 由于同源原理,所有页面里面都有一个XSRF-TOKEN 提取出来放到ajax中,9.0是这么做的,6.0不清楚是否自动化了:

文档里面的:

file

1年前 评论
xiwang6428 (楼主) 1年前
xini2603 (作者) 1年前
xiwang6428 (楼主) 1年前

我感觉你的瓶颈根本不是页面的问题 页面静态化的提升我感觉没多大 还不如 redis加上

1年前

你都静态化了就应该搞纯前后端分离的架构了啊, 不要用cookie做权限校验, token放header里, 就不用搞csrf了呀

1年前 评论
markyanggang 1年前
luke_wu (作者) 1年前
xiwang6428 (楼主) 1年前

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!