cookie介绍
为什么存在cookie?
(1)cookie存在的原因
因为http请求是无状态的,同一个用户从浏览器向A服务器发送两次请求,A服务器无法判断这两次请求是否是同一个用户。所以,浏览器提供了客户端携带cookie技术,让每次请求有状态。
(2)后端使用cookie进行登录状态记录流程
开发中我们经常使用cookie作为登录验证的手段,如图:
cookie有哪些属性?
一般cookie具有7个属性,包括:
Name:就是cookieName,一般用字母或数字,不能包含特殊字符,没什么好说的。
value:cookieName对应的值。
Domain:域,表示当前cookie所属于哪个域或子域下面,例如.baidu.com就表示在.baidu.com下可以访问。对于服务器返回的Set-Cookie中,如果没有指定Domain的值,那么其Domain的值是默认为当前所提交的http的请求所对应的主域名的。比如访问 http://www.example.com,返回一个cookie,没有指名domain值,那么其为值为默认的www.example.com。(xt是指定了domain=.xtransfer.com,所以需要重写为domain=.xtransfer.sg)
Path:表示cookie的所属路径,一般设为“/”,表示同一个站点的所有页面都可以访问这个cookie。
Expires/Max-age:表示了cookie的有效期。expires的值,是一个GMT格式的时间,过了这个时间,该cookie就失效了。或者是用max-age指定当前cookie是在多长时间之后而失效。如果服务器返回的一个cookie,没有指定其expire time,那么表明此cookie有效期只是当前的session,即是session cookie,当前session会话结束后,就过期了。对应的,当关闭(浏览器中)该页面的时候,此cookie就应该被浏览器所删除了。
secure:表示该cookie只能用https传输。一般用于包含认证信息的cookie,要求传输此cookie的时候,必须用https传输。
httponly:表示此cookie必须用于http或https传输。这意味着,浏览器脚本,比如javascript中,是不允许访问操作此cookie的。设置 HTTPOnly 属性可以防止客户端脚本通过 document.cookie 等方式访问 Cookie,有助于避免 XSS 攻击。
SameSite :是最近非常值得一提的内容,因为 2 月份发布的 Chrome80 版本中默认屏蔽了第三方的 Cookie,这会导致阿里系的很多应用都产生问题,为此还专门成立了问题小组,推动各 BU 进行改造。
我们先来看看这个属性的作用:
SameSite 属性可以让 Cookie 在跨站请求时不会被发送,从而可以阻止跨站请求伪造攻击(CSRF)。
SameSite 可以有下面三种值:
- Strict 仅允许一方请求携带 Cookie,即浏览器将只发送相同站点请求的 Cookie,即当前网页 URL 与请求目标 URL 完全一致。
- Lax 允许部分第三方请求携带 Cookie
- None 无论是否跨站都会发送 Cookie。如果samesit=none,那么要求secure必须是true。
之前默认是 None 的,Chrome80 后默认是 Lax。
浏览器系列之 Cookie 和 SameSite 属性 · Issue #157 · mqyqingfeng/Blog
cookie存储在什么地方?
我们必须再次强调一点:cookie是浏览器提供的手段,cookie相关的管理也是由浏览器来提供。用户每次都是通过浏览器来访问各个网站,每次访问是否携带cookie都是由浏览器决定。
我们不妨把浏览器抽象成一个应用服务器,它帮助我们管理cookie的生命周期:新增cookie、查询cookie、修改cookie、删除cookie。
当我们引入‘cookie数据库’的概念后,用户访问A网站的流程可以细化如下图。
cookie生命周期
(1)cookie生命周期描述
1、增。新增cookie的场景:
- 服务器新增。由应用服务器设置特定的http响应头来新增cookie,通常是通过在HTTP响应头中添加Set-Cookie头来实现。
- 客户端新增。客户端可以使用JavaScript来新增Cookie。通过在客户端的JavaScript代码中设置document.cookie,从而新增Cookie。document.cookie = "cookie_name=cookie_value; max-age=3600;";。
2、删。删除cookie的手段:
- 服务器删除。应用服务器可以通过 Expires/Max-age属性设置cookie的有效期,有效期到了之后,浏览器帮助我们删除cookie。
- 客户端删除。
-
- 浏览器工具删除:开发人员为了测试cookie的相关场景,手动在浏览器开发工具上面删除cookie。步骤:F12->应用->cookie->右击清除。
- 代码删除:document.cookie = "cookie_name=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;";。
3、改。修改cookie的方式:
- 服务器修改。应用服务器可以获取本次请求的cookie,然后手动修改cookie后,通过http响应的方式再返回给浏览器。
- 客户端修改。
-
- 浏览器工具修改:开发人员可以在浏览器工具上手动修改cookie。这种方式不会持久会到硬盘,仅当前会话生效。
- 代码修改:document.cookie = "cookie_name=new_value; max-age=3600;";。
4、查。
- 服务器查询。
- 客户端查询。
-
- 浏览器工具查询:F12->应用->cookie。
- 代码查询: cookie_value = request.cookies.get('cookie_name') # 获取名为'cookie_name'的Cookie值
(2)cookie生命周期存在的隐患
客户端通过脚本可以任意的对cookie进行操作。这种客户端行为的操作cookie,会对整个网站的安全性产生巨大的影响。因为cookie就是身份,如果cookie被泄露出去,网站就无安全性可言了。
(3)cookie有效期与登录状态的关系
cookie被删除后,登录状态会立即失效吗?
当Cookie被删除后,登录状态通常会立即失效,但实际行为取决于服务器端的实现方式和会话管理机制。
在一般情况下,登录状态是通过在客户端(浏览器)存储一个包含用户登录信息的Cookie来实现的。当用户登录成功后,服务器会设置一个持久化的Cookie,该Cookie包含用户的登录凭证或会话标识。每次用户访问网站时,浏览器都会发送该Cookie到服务器,从而维持登录状态。
如果该Cookie被删除或过期,浏览器不再发送该Cookie到服务器,服务器会认为用户没有登录或登录状态已过期,因此登录状态会立即失效。用户需要重新登录来获取新的有效Cookie,恢复登录状态。
但是,需要注意的是,有些网站可能采用其他更复杂的会话管理机制,如在服务器端存储会话信息而不依赖于Cookie。在这种情况下,删除Cookie可能不会立即使登录状态失效,因为登录状态的管理是由服务器控制的,而不是完全依赖于Cookie的存在。
总的来说,大多数网站的登录状态是依赖于Cookie的存在的,因此删除Cookie会导致登录状态立即失效。但对于特定的网站,特别是那些使用更复杂会话管理方式的网站,删除Cookie可能不会立即导致登录状态失效,需要视具体实现而定。
cookie安全问题
http请求因为携带cookie而具备了「有状态」的特性,应用服务器通过识别cookie来判断当前登录的到底是哪个用户。那么,如果cookie不慎泄露,被不法分子恶意使用(伪造真实用户身份),将带来不可预估的影响。
cookie泄露的方式
cookie泄露的方式通常有下面几种:
- 客户端泄露。
-
- 被动泄露 - 跨站脚本攻击(XSS):恶意攻击者通过在网站上注入恶意脚本,使得用户在访问受感染页面时,浏览器会执行这些恶意脚本。这些脚本可以窃取用户的Cookie信息(document.getCookie(cookieName)),并将其发送给攻击者,从而导致Cookie泄露。XSS攻击不仅仅可以用来窃取cookie,还可以用来发送恶意请求(2012年发生的微博事件沸沸腾腾)。
- 前端代码漏洞:前端代码存在漏洞,使得攻击者通过某些技巧获取cookie。
- 恶意浏览器插件:一些恶意的浏览器插件或扩展程序可能会窃取用户的Cookie信息,然后传送给攻击者。
- 网络泄露。
-
- 不安全的网络:在不安全的网络环境中,如公共Wi-Fi热点,黑客可以使用网络监听技术截取用户的传输数据,包括Cookie信息,从而导致Cookie泄露。
cookie泄露带来的危害
cookie泄露带来最大的危害就是不法分子模拟真实用户身份,向官方网站发起恶意请求,这个过程叫做CSRF攻击。那么在这个过程中,不法分子是如何一步步诱导用户发起请求的呢?
CSRF攻击流程
我们先来看一张流程图:
图中表示内容如下:
(1)用户 通过浏览器 在A网站界面 正常访问A网站,且浏览器已经存储了A网站的cookie;
(2)浏览器中的信息是丰富多彩的,用户又去浏览了B网站界面。至于为什么用户会突然访问B网站界面,通常原因有以下几种:
- 基于A网站界面「内部」进行网站跳转
-
- A网站界面被埋点,当用户点击A网站某个链接或者图片时,会跳转到B网站。JavaScript跳转页面是最常用的方法之一,比如使用URL链接、使用location.href、使用window.location.replace等等。其中URL链接的方式示例:<a href="http://www.baidu.com">百度一下</a>。
-
-
- 主动埋点。业务方需要从A网站跳转到B网站。
- 被迫埋点。A网站被JS脚本攻击,黑客将一段JS脚本嵌入A网站界面。这个过程叫XSS攻击。
-
- 基于A网站「外部」解析网站跳转
-
- 用户自己在互联网遨游时浏览到了B网站。
- 点击A网站界面左右两侧类似广告的链接进行跳转。
(3)原来B网站是 黑客网站,用户来到‘B网站界面’后,在不知情的情况下,向‘A服务器应用’发起请求。这个过程叫做CSRF跨站请求伪造攻击。当然,跨站请求也不是那么容易就成功了,需要解决两个问题。
- 跨域问题-同源策略。受浏览器同源策略影响,B网站访问A服务器属于跨域请求。
-
- 如果A服务器配置的Access-Control-Allow-Origin允许域不包括B网站域。则该请求由于跨域而失败。
- 如果A服务器配置的Access-Control-Allow-Origin允许B网站域(A网站与B网站属于同一个公司或合作伙伴关系),则该请求成功,且响应成功。
- cookie携带问题-samesit。以上图为例就是:用户基于B网站界面,向A网站服务器发送请求时,该请求是否携带A网站的cookie。请求跨域问题解决之后,只是说该次请求具备了可携带cookie的条件。这和A应用服务器返回cookie的samesit属性有关:
-
- Strict 仅允许一方请求携带 Cookie,即浏览器将只发送相同站点请求的 Cookie,即当前网页 URL 与请求目标 URL 完全一致。
- Lax 允许部分第三方请求携带 Cookie
- None 无论是否跨站都会发送 Cookie。如果samesit=none,那么要求secure必须是true。
B网站界面向A应用服务器发起请求的手段
基于B网站界面 触发 A应用服务器请求 属于跨域,且用户服务器肯定不会配置允许黑客网站域名跨域。因此,黑客需要通过其他手段绕过浏览器同源策略,也就是通过其他手段解决跨域问题。一般的 CSRF 攻击 其常用方式有三种。《以下三种方式的请求允许跨域,且可携带第三方 cookie》
1. 自动发起 Get 请求
黑客最容易实施的攻击方式是自动发起 Get 请求,具体攻击方式你可以参考下面这段代码:
这是黑客页面的 HTML 代码,在这段代码中,黑客将转账的请求接口隐藏在 img 标签内,欺骗浏览器这是一张图片资源。当该页面被加载时,浏览器会自动发起 img 的资源请求,如果服务器没有对该请求做判断的话,那么服务器就会认为该请求是一个转账请求,于是用户账户上的 100 极客币就被转移到黑客的账户上去了。
2. 自动发起 POST 请求
除了自动发送 Get 请求之外,有些服务器的接口是使用 POST 方法的,所以黑客还需要在他的站点上伪造 POST 请求,当用户打开黑客的站点时,是自动提交 POST 请求,具体的方式你可以参考下面示例代码:
在这段代码中,我们可以看到黑客在他的页面中构建了一个隐藏的表单,该表单的内容就是极客时间的转账接口。当用户打开该站点之后,这个表单会被自动执行提交;当表单被提交之后,服务器就会执行转账操作。因此使用构建自动提交表单这种方式,就可以自动实现跨站点 POST 数据提交。
3. 引诱用户点击链接
除了自动发起 Get 和 Post 请求之外,还有一种方式是诱惑用户点击黑客站点上的链接,这种方式通常出现在论坛或者恶意邮件上。黑客会采用很多方式去诱惑用户点击链接,示例代码如下所示:
这段黑客站点代码,页面上放了一张美女图片,下面放了图片下载地址,而这个下载地址实际上是黑客用来转账的接口,一旦用户点击了这个链接,那么他的极客币就被转到黑客账户上了。
以上三种就是黑客经常采用的攻击方式。如果当用户登录了极客时间,以上三种 CSRF 攻击方式中的任何一种发生时,那么服务器都会将一定金额的极客币发送到黑客账户。
防御CSRF攻击的手段
CSRF本质上是根据cookie来进行攻击,那么我们的防御手段也应该围绕cookie是否泄露进行分析。
1、避免cookie泄露
- 同源策略。跨域时 cookie 无法携带,但是有多种方式可以绕过同源策略正常携带第三方 cookie 发起请求「如上面讲述的 get,post 和 link」。 由于介绍同源策略的篇幅会比较多,我会在下一节单独重点讲解。
- 防御XSS脚本攻击。一般而言,黑客是通过XSS脚本先获取cookie信息,然后发起伪造请求。
- 使用HttpOnly属性。设置Cookie的HttpOnly=true,这样JavaScript无法通过document.cookie获取或修改Cookie,从而减少XSS攻击的威胁。
- 使用Secure属性。对于包含敏感信息的Cookie,应该设置Secure=true,只有在通过HTTPS安全连接时才发送该Cookie。
- 使用SamesSit属性。有strict、lax和none三个值,其作用请见「cookie介绍-cookie有哪些属性」节。
2、补偿措施
即使我们再怎么防护cookie,cookie最终还是会由于各种各样的原因遭到泄露。那么我们的防御手段就应该考虑:假设cookie泄露了,应该如何保护网站。
- 使用CSRF令牌:在Web应用中使用CSRF令牌,也称为同步令牌,用于验证每个重要操作的合法性。在每个表单提交或重要的请求中,服务器会生成一个CSRF令牌,并将其嵌入表单或请求参数中。然后,在提交请求时,服务器会验证这个令牌,确保它与用户会话中的令牌匹配,从而防止CSRF攻击。
- 使用HTTP请求头:可以在HTTP请求头中自定义一些字段来携带CSRF令牌。这样,在发送重要请求时,服务器可以检查请求头中的令牌,并进行验证。
- 第三种方式使用双重 Cookie 验证的办法,服务器在用户访问网站页面时,向请求域名注入一个Cookie,内容为随机字符串,然后当用户再次向服务器发送请求的时候,从 cookie 中取出这个字符串,添加到 URL 参数中,然后服务器通过对 cookie 中的数据和参数中的数据进行比较,来进行验证。使用这种方式是利用了攻击者只能利用 cookie,但是不能访问获取 cookie 的特点。并且这种方法比 CSRF Token 的方法更加方便,并且不涉及到分布式访问的问题。这种方法的缺点是如果网站存在 XSS 漏洞的,那么这种方式会失效。同时这种方式不能做到子域名的隔离。
浏览器同源策略
什么是同源策略
1995年,同源政策由 Netscape 公司引入浏览器。目前,所有浏览器都实行这个政策。同源策略是防止CSRF攻击的重要手段。
最初,它的含义是指,A 网页设置的 Cookie,B 网页不能使用A的cookie,除非这两个网页“同源”。所谓“同源”指的是“三个相同”:
- 协议相同
- 域名相同
- 端口相同
同源策略与跨域
什么是跨域?
非同源即是跨域。如果基于B网站访问A网站,由于两个网站非同源,因此受同源策略影响,则该请求属于跨域请求,浏览器会对该请求做拦截,导致该请求发送失败。因为请求跨域,因此cookie也不会被携带。
跨域请求到底发出去了吗?
答案是发出去了,跨域请求发出后,是被浏览器拦截。
跨域请求被谁拦截了?
跨域请求发出后,是被浏览器拦截的,而不是被服务器拦截的。这是因为跨域请求涉及到浏览器的安全策略,即同源策略(Same-Origin Policy)。
同源策略是浏览器的一项安全特性,它要求网页资源(例如JavaScript、CSS和Cookie)只能与来自同一源(协议、域名和端口)的网页进行交互。如果一个请求违反了同源策略,浏览器会拦截该请求,阻止它的执行,并阻止携带Cookie等敏感信息,即请求跨域时无法携带cookie。
浏览器跨域请求流程
当浏览器发现一个跨域请求时(比较当前网站域名和请求域名是否一致):
- 它会先发送一个预检请求(Preflight Request,该请求不是真的访问后端服务器,所以该请求没有响应结果),以检查服务器是否允许跨域请求。这个预检请求是一种OPTIONS请求,用于向服务器询问是否允许实际的跨域请求。
- 只有在服务器返回明确的允许跨域的响应头时,浏览器才会发送实际的跨域请求。通常,我们都是使用CORS手段解决跨域问题,则‘明确的允许跨域的响应头’指的是CORS响应头。
下面以CORS方式解决跨域为例,CORS 跨域的判定流程如下:
- 浏览器先根据同源策略对前端页面和后台交互地址做匹配,若同源,则直接发送数据请求;若不同源,则发送跨域请求。
- 预检请求(跨域请求)。
-
- 服务器收到浏览器跨域请求后,根据自身配置返回对应文件头。若未配置过任何允许跨域,则文件头里不包含 Access-Control-Allow-origin 字段,若配置过域名,则返回 Access-Control-Allow-origin + 对应配置规则里的域名的方式。
- 浏览器根据接受到的 响应头里的 Access-Control-Allow-origin 字段做匹配,若无该字段,说明不允许跨域,从而抛出一个错误;若有该字段,则对字段内容和当前域名做比对,如果同源,则说明可以跨域,浏览器接受该响应;若不同源,则说明该域名不可跨域,浏览器不接受该响应,并抛出一个错误。
- 真正的跨域请求。当预检通过后,浏览器会发送真正的跨域请求。
上面说到的两种类型的报错,控制台输出是不一样的:
- 服务器允许跨域请求,但是 Origin 指定的源,不在许可范围内,服务器会返回一个正常的HTTP回应。浏览器发现,这个回应的头信息没有包含 Access-Control-Allow-Origin 字段,就知道出错了,从而抛出一个错误,被 XMLHttpRequest的onerror 回调函数捕获。注意,这种错误无法通过状态码识别,因为 HTTP 回应的状态码有可能是200。
<!--控制台返回结果-->
XMLHttpRequest cannot load http://localhost/city.json.
The 'Access-Control-Allow-Origin' header has a value 'http://segmentfault.com' that is not equal to the supplied origin.
Origin 'http://www.zhihu.com' is therefore notallowed access.
- 服务器不允许任何跨域请求
<!--控制台返回结果-->
XMLHttpRequest cannot load http://localhost/city.json.
No 'Access-Control-Allow-Origin' header is present on the requested resource.
Origin 'http://www.zhihu.com' is therefore not allowed access.
下面列举当使用CORS手段解决跨域时,CORS相关的请求头和响应头:
请求头(跨域请求时可能增加的字段):
- Origin:指示请求的来源,即发起请求的页面所在的域。
- Access-Control-Request-Method:在预检请求(OPTIONS 请求)中指示实际请求所使用的方法。
- Access-Control-Request-Headers:在预检请求(OPTIONS 请求)中指示实际请求中包含的额外请求头信息。
响应头(跨域请求时可能增加的字段):
- Access-Control-Allow-Origin:指示允许访问该资源的域(或者使用通配符 * 表示允许任意域访问)。
- Access-Control-Allow-Methods:指示允许使用的请求方法。
- Access-Control-Allow-Headers:指示允许的额外请求头字段。
- Access-Control-Allow-Credentials:指示是否允许发送跨域请求时携带凭据(如 Cookie、HTTP 认证等)。
- Access-Control-Expose-Headers:指示哪些响应头字段可以被客户端访问。
这些字段主要用于实现 CORS(跨域资源共享)机制,通过在请求头和响应头中进行交互,确保跨域请求的安全性和授权机制。
请注意,实际使用时,具体的请求头和响应头字段可能因跨域请求的需求、服务器的配置以及浏览器的支持而有所不同。
浏览器跨域请求流程案例
场景描述:
用户基于www.xtransfer.cn界面,向www.xtransfer.sg服务器发送跨域请求。
解决方案:
采用CORS手段解决跨域问题。由于www.xtransfer.cn和www.xtransfer.sg是同一个公司名下的域名,因此是允许用户基于www.xtransfer.cn界面,向www.xtransfer.sg服务器发送跨域请求的。
流程如下:
1、浏览器发送预检请求。
2、浏览器接收预检请求的响应。
3、浏览器分析预检响应头。
- Access-Control-Allow-Origin=http://www.xtransfer.cn。该跨域请求的发起域必须是http://www.xtransfer.cn((或者使用通配符 * 表示允许任意域访问))。
- Access-Control-Allow-Credentials=true。该跨域请求允许携带凭证(cookie或者http认证)。
- Access-Control-Allow-Methods=GET, PUT, POST, DELETE, PATCH, OPTIONS。指示允许使用的请求方法。
- Access-Control-Allow-Headers=DNT,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization,x-xsrf-token,x-b3-traceid,x-user-agent-context,x-b3-spanid,fp。指示允许的额外请求头字段。
- Access-Control-Expose-Headers=Content-Type, X-TenantID, X-Track-Id, X-B3-TraceId, X-Request-Id, X-No-Conversion。指示哪些响应头字段可以被客户端访问。
4、浏览器发现预检响应头的条件都满足,在发送真正的后端请求。
同源策略与cookie的关系
请求一旦跨域,cookie将无法携带。基于B网站访问A网站属于跨域请求,如果A网站没有配置允许B网站跨域,那么该请求不仅请求失败更不会携带cookie。
同源策略如何防止CSRF攻击的
CSRF的本质是靠cookie进行攻击的,同源策略规定跨域时请求失败且cookie也无法携带。
我们先来看下跨站请求过程图:
1、当用户访问B网站界面时,由于同源策略,访问B网站的所有请求 肯定不会 携带A网站的cookie。
- 假设可以携带A网站的cookie,那么B网站完全可以把cookie存储起来,再通过postman等其他手段模拟真实用户向A应用服务器发送伪造请求。
2、黑客当然知道同源策略的这个特点,因此他故意在B网站界面埋下一个访问A服务器的请求,让用户基于B网站主动触发请求访问A网站。
- 跨域问题。
因为是基于B网站向A网站发送请求,A和B网站使用的不是同一个域名,受同源策略影响,该请求跨域且跨站。
a. 如果A应用服务器想要处理这次请求,那么A服务器就需要做跨域处理,通常采用CORS手段解决跨域。
b. 如果A应用服务器不允许该请求跨域,服务器会报跨域异常错误通知给浏览器。
- cookie携带问题。
即使A应用服务器允许跨域,并不代表该请求就可以被正常处理了,通常服务器内部还需要验证用户的身份。由于我们采用的是cookie验证策略,因此A应用服务器需要验证cookie的有效性。
-
- cookie存在:验证cookie是否有效。如果有效则该请求被 正常处理,否则验证失败。
- cookie不存在:身份校验失败。cookie不存在,说明用户基于B网站向A应用服务器发送请求时候,没有携带A网站的cookie(samesit=strict时。最新版谷歌浏览器设置samesit的默认值就是strict)。
跨域
什么是跨域?
为什么有跨域?
浏览器同源策略,非同源即跨域。
浏览器的同源策略目的是为了保护用户的信息安全,为了防止恶意网站窃取用户在浏览器上的数据,如果不是同源的站点,将不能进行如下操作 :
- Cookie、LocalStorage 和 IndexDB 无法读写
- DOM 和 Js对象无法获得
- AJAX请求不能发送
解决跨域的手段
在浏览器中, <script> 、<img>、<iframe>、<link>等标签都可以跨域加载,而不受浏览器的同源策略的限制。
同源策略(same origin policy)_要不要买菜啊的博客-CSDN博客