FrankKai / FrankKai.github.io

FE blog
https://frankkai.github.io/
363 stars 39 forks source link

前端cookie总结 #154

Open FrankKai opened 5 years ago

FrankKai commented 5 years ago

看经验比我丰富的老哥的代码,惊觉自己对cookie的掌握程度,还是小学生的水平,所以开这个issue补充一下cookie知识点,以后在开发过程中总结到的好的实践也会记录在这里。

参考资料:https://developer.mozilla.org/en-US/docs/Web/API/Document/cookie

FrankKai commented 5 years ago

cookie基础概念

读cookie

allCookies = document.cookie;

写cookie

;path=path
;domain=domain

path:1.若Path为 / ,那么无论是路径/foo还是子路径/foo/bar,从浏览器发到服务端的请求,在header中都会带上cookie头 2.必须是绝对路径 3.若不指定path,则为当前location的pathname domain:1.指出可以接收cookie的host。默认是location.host 2.若设置了Domain属性,那么它的子域名中也是包含这个cookie的 这两个属性定义了cookie的作用域,也就是说这个cookie是要发给谁的。

衍生面试题:聊一聊cookie的作用域?

;max-age=max-age-in-seconds
;expires=date-in-GMTString-format

这两个属性定义了cookie的过期时间。 expires和max-age都是设置过期时间的,规范定义规则如下:

The max-age directive takes priority over Expires, so if max-age is present in a response, the calculation is simply:

  freshness_lifetime = max_age_value

Otherwise, if Expires is present in the response, the calculation is:

  freshness_lifetime = expires_value - date_value

若真要问有什么区别:1.max-age精确到秒;而expires精确到毫秒 2.前端通过expires设置过期时间,服务端可以通过设置max-age来覆盖前端的过期时间

衍生面试题: 1.聊一聊max-age和expires的异同?见上文。 2.若max-age和expires同时设定了,哪一个会生效?The max-age directive takes priority over Expires

;secure
;samesite

设置secure的cookie仅在https之类的安全协议下可以传输。 samesite的设置,阻止浏览器发送跨站请求,有lax和strict两个值。strict会阻止所有跨站请求;lax仅仅允许在TOP LEVEL的GET请求中带cookie,可以阻止绝大多数CSRF攻击,子frame是不能发的。

衍生面试题: 1.TOP LEVEL是什么? TOP LEVEL指的就是window.top,也就是最顶级的window对象,例如在https://developer.mozilla.org/en-US/docs/Web/API/Document/cookie 这个路径下,打开chrome devtools的控制台,我们看到的top指的就是developer.mozilla.org。

encodeURIComponent()

cookie值不允许包含分号,逗号,空格,但是可以使用encodeURIComponents编码。这个方法仅不编码A-Z a-z 0-9 - _ . ! ~ * ' ( )

__Secure-
__Host-

只能在安全的通道中包含cookie。__Host-则指明cookie仅在由浏览器指定的path下生效。

;httponly
;sameparty

httpOnly为true的cookie,是由服务端写入的,通过document.cookie是获取不到的,可以防御XSS攻击攻击。 sameparty可以将多个站点,看做第一方cookie,从而实现多站点域名共享。需要注意必须是secure并且samesite不为strict。例如.taogao.com,.tmall.com,.1688.com,组内成员彼此都作为第一方cookie。

FrankKai commented 5 years ago

cookie使用实践

  1. 前端cookie如何设置过期时间?
    const d = new Date();
    d.setTime(d.getTime() + 30*60*1000); // 设置过期时间为30分钟
    const cookieKV = 'cookieKey=cookieValue';
    const expires = `expires=${d.toGMTString()}`;// 由于cookie的过期时间类型为 ;expires=date-in-GMTString-format,所以需要用Date.toGMTString()转换成GMT类型
    document.cookie = `${cookieKV};${expires}`; // 30分钟后此cookie失效,从cookie列表中删除
  2. 前端查询某个cookie已过期?
    document.cookie.indexOf(`${name}=`); // 若返回-1则表示已过期

    与第7题很类似。 还有很多其他写法。

  3. 为什么需要设置cookie?

从前端的角度来说,因为有些时候需要从服务端获取一个token,signa之类的凭证或者数字签名,cookie的设定,可以使得在凭证有效期内,不用频繁向服务端发送获取token的请求,直接从浏览器本地获取cookie即可完成之后的请求。 从服务端的角度来说,由于前端设置了cookie过期时间,有效期内不用访问服务端获取凭证,从而减轻服务端服务的压力。

  1. 如何获取一个指定名字的cookie?

    getCookieValueByName(cookieName){
    const cookieValue = document.cookie.replace(/(?:(?:^|.*;\s*)name\s*\=\s*([^;]*).*$)|^.*$/, "$1");
    return cookieValue;
    }
  2. 如何设置一个只用一次的cookie?

    function doOnce() {
    if (document.cookie.replace(/(?:(?:^|.*;\s*)doSomethingOnlyOnce\s*\=\s*([^;]*).*$)|^.*$/, "$1") !== "true") {
    alert("Do something here!");
    document.cookie = "doSomethingOnlyOnce=true; expires=Fri, 31 Dec 9999 23:59:59 GMT"; // Sat Jan 01 10000 07:59:59 GMT+0800 (中国标准时间) 10000年1月1日
    }
    }
  3. 重置一个cookie?

    function resetOnce() { 
    document.cookie = "doSomethingOnlyOnce=; expires=Thu, 01 Jan 1970 00:00:00 GMT";
    }

7.确定一个cookie是否存在或者有效?

checkCookieExsitence(cookieName){
    if (document.cookie.split(';').filter((item) => item.trim().startsWith(`${cookieName}=`)).length) {
        return true;
    }
    return false;
}

与第2题很类似。

8.确定一个cookie的值是否为指定值?

checkCookieExsitence(cookieName, cookieValue){
    if (document.cookie.split(';').filter((item) => item.includes(`${cookieName}=${cookieValue}`)).length) {
        return true;
    }
    return false;
}
FrankKai commented 4 years ago

浏览器如何精确清除cookie

1.网站设置→Cookie→查看所有Cookie和网站数据

找到需要删除的网站并删除Cookie即可。

2.点击浏览器url左边的不安全锁子 image image

FrankKai commented 4 years ago

常见应用场景

cookie是当前tab有效的还是所以tab有效的?

cookie是通过domain指定作用范围的。 若是服务端,可以指定domain,若是跨系统cookie,一般是一级域名;若指定系统,可以指定二级,三级域名。 若是前端,一般是设置在document.cookie上,在当前域名设置。

image

服务端如何既对token做处理又对cookie做处理?

const certificate = token || cookie 优先使用token。

cookie与前端安全

敏感数据的cookie(httpOnly为true)通过服务端写入。

为了避免XSS和CSRF攻击,包含敏感数据的cookie通过服务端写入,此时httpOnly属性为true,浏览器通过document.cookie 这个api获取不到,是一种安全防范措施。