前后端分离-跨域-会话机制-cookie-csrf

 

 

1、首先用一张图引出此次学习的起因及过程

前后端分离-跨域-会话机制-cookie-csrf_第1张图片

2、具体探索过程

1、使用的前后端语言:前端H5(http://web.local.com),后端node.js(http://localhost:8080,验证码插件一般bmp24/svg)

2、一般后端接口处理跨域主要加Access-Control-Allow-Origin:'options'

app.use("*", function (req, res, next) {
  res.header('Access-Control-Allow-Origin', 'http://web.local.com');
  // res.header('Access-Control-Allow-Credentials',true);
  res.header("Access-Control-Allow-Headers", "Content-Type,Content-Length, Authorization, Accept,X-Requested-With");
  res.header("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS");
  if (req.method === 'OPTIONS') {
      res.sendStatus(200)
  } else {
      next()
  }
});

3、引入session

// 配置session
app.use(session({
  secret:'dsafsafsf@123',//设置签名秘钥 内容可以任意填写
  name:'sessionId', 
  cookie:{ 
    maxAge:180*1000,
    httpOnly:false,
   }, //设置cookie的过期时间,例:80s后    session和相应的cookie失效过期
  resave:false, //强制保存,如果session没有被修改也要重新保存
  saveUninitialized:false //如果原先没有session那么久设置,否则不设置
}));

4、前端ajax请求,返回头中带有set-cookie,但是浏览器中并没有存储sessionId的值

前后端分离-跨域-会话机制-cookie-csrf_第2张图片

前后端分离-跨域-会话机制-cookie-csrf_第3张图片

5、如果把域名(web.local.com)换成(localhost)就会显示,证明服务端的配置并无问题,但是为什么浏览器不存储cookie的值呢?

前后端分离-跨域-会话机制-cookie-csrf_第4张图片

6、通过观察发现,不但sessionId不被存储,而且请求头中并没有设置cookie,经过查找,有的人说ajax中加入xhrFields: { withCredentials: true},后端加入res.header('Access-Control-Allow-Credentials',true);但是事实上还是不行,经过观察发现如下:将鼠标放在感叹号上会出现一行英文,大致是说sameSite默认为Lax,可以将其设置为none,才可以

前后端分离-跨域-会话机制-cookie-csrf_第5张图片

7、SamaSite是什么?引用阮一峰的网络日志(http://www.ruanyifeng.com/blog/2019/09/cookie-samesite.html)

Chrome 5.1 开始,浏览器的 Cookie 新增加了一个SameSite属性,用来防止 CSRF 攻击和用户追踪。

CSRF 攻击是什么?

Cookie 往往用来存储用户的身份信息,恶意网站可以设法伪造带有正确 Cookie 的 HTTP 请求,这就是 CSRF 攻击。

举例来说,用户登陆了银行网站your-bank.com,银行服务器发来了一个 Cookie。


Set-Cookie:id=a3fWa;

用户后来又访问了恶意网站malicious.com,上面有一个表单。


...

用户一旦被诱骗发送这个表单,银行网站就会收到带有正确 Cookie 的请求。为了防止这种攻击,表单一般都带有一个随机 token,告诉服务器这是真实请求。


...

这种第三方网站引导发出的 Cookie,就称为第三方 Cookie。它除了用于 CSRF 攻击,还可以用于用户追踪。

比如,Facebook 在第三方网站插入一张看不见的图片。



浏览器加载上面代码时,就会向 Facebook 发出带有 Cookie 的请求,从而 Facebook 就会知道你是谁,访问了什么网站。

二、SameSite 属性

Cookie 的SameSite属性用来限制第三方 Cookie,从而减少安全风险。

它可以设置三个值。

  • Strict
  • Lax
  • None

2.1 Strict

Strict最为严格,完全禁止第三方 Cookie,跨站点时,任何情况下都不会发送 Cookie。换言之,只有当前网页的 URL 与请求目标一致,才会带上 Cookie。


Set-Cookie: CookieName=CookieValue; SameSite=Strict;

这个规则过于严格,可能造成非常不好的用户体验。比如,当前网页有一个 GitHub 链接,用户点击跳转就不会带有 GitHub 的 Cookie,跳转过去总是未登陆状态。

2.2 Lax

Lax规则稍稍放宽,大多数情况也是不发送第三方 Cookie,但是导航到目标网址的 Get 请求除外。


Set-Cookie: CookieName=CookieValue; SameSite=Lax;

导航到目标网址的 GET 请求,只包括三种情况:链接,预加载请求,GET 表单。详见下表。

请求类型 示例 正常情况 Lax
链接 发送 Cookie 发送 Cookie
预加载 发送 Cookie 发送 Cookie
GET 表单
发送 Cookie 发送 Cookie
POST 表单 发送 Cookie 不发送
iframe 发送 Cookie 不发送
AJAX $.get("...") 发送 Cookie 不发送
Image 发送 Cookie 不发送

设置了StrictLax以后,基本就杜绝了 CSRF 攻击。当然,前提是用户浏览器支持 SameSite 属性。

2.3 None

Chrome 计划将Lax变为默认设置。这时,网站可以选择显式关闭SameSite属性,将其设为None。不过,前提是必须同时设置Secure属性(Cookie 只能通过 HTTPS 协议发送),否则无效。

下面的设置无效。


Set-Cookie: widget_session=abc123; SameSite=None

下面的设置有效。


Set-Cookie: widget_session=abc123; SameSite=None; Secure

8、如果你能耐心的看到这里,也许你已经明白了,允许跨域传cookie是危险的,是被禁止的。但是我们还是想通过后端来验证数据,那么我们只能曲线救国了,生成sign_id,随验证码一起返回,提交表单时,将sign_id与验证码等参数一同提交,验证redis.get('sign_id')的值与验证码的值,完成全部验证。

//生成验证码 svg方式
    getAuthImg(req, res){
       let option = {
            mathMin:1,
            mathMax:100,
            width: 105,
            height: 33,
            background: "#f4f3f2",//干扰线条数
            noise: 2,
            fontSize: 32,
            ignoreChars: '0o1i',   //验证码字符中排除'0o1i'
            color: true // 验证码的字符是否有颜色,默认没有,如果设定了背景,则默认有           
        };
        // 验证码,有两个属性,text是字符,data是svg代码
        // var code = svgCaptcha.create(option);
        var code = svgCaptcha.createMathExpr(option),
            sign_id = sha1(new Date().getTime().Math.random());
            redis.set(sign_id, code.text, 'EX', 300);
        // 返回数据直接放入页面元素展示即可
        res.send({
            img: code.data,
            sign_id:sign_id
        });
    }

有不对的地方,欢迎指正,谢谢!

 

 

你可能感兴趣的:(web,js,node.js,jquery,vue.js,html,html5)