✍个人博客:Pandaconda-CSDN博客
📣专栏地址:http://t.csdnimg.cn/fYaBd
📚专栏简介:在这个专栏中,我将会分享 C++ 面试中常见的面试题给大家~
❤️如果有收获的话,欢迎点赞👍收藏📁,您的支持就是我创作的最大动力💪
📝推荐参考地址:https://www.xiaolincoding.com/(这个大佬的专栏非常有用!)
16. Cookies、Session、Token 的区别是什么?
- session
在服务器端记录,每一个会话会产生一个 session id。当用户打开某个 web 应用时,便与 web 服务器产生一次 session。服务器使用 session id 把用户的信息临时保存在了服务器上,用户离开网站后 session 会被销毁。这样服务器就会根据每个人 session id 的不同,区别开谁是谁了,从而返回给用户不同的请求结果。
缺点:
如果使用单个服务器的话,用户过多的话,会造成服务器开销太大。如果我们系统采用分布式的话,我们登录时,响应我们的那台机器会记录我们登录信息,万一下一个请求,响应我们的不是原来那台机器的话,它并没有存储我们之前会话信息,就会认为我们并没有登录。session 粘连或者 session 复制都不是特别好的方案。
那既然服务端存储这些 session id 这么麻烦,人类又想出一招,那就是把这些 session id 都存储在客户端。这个时候,cookie 运用而生
- cookie
cookie 是服务端保存在客户端的临时的少量的数据。cookie 由服务器生成,发送给浏览器,浏览器把 cookie 以 kv 形式保存到某个目录下的文本文件内,下一次请求同一网站时会把该 cookie 发送给服务器。由于 cookie 是存在客户端上的,所以浏览器加入了一些限制确保 cookie 不会被恶意使用,同时不会占据太多磁盘空间,所以每个域的 cookie 数量是有限的。
但是,cookie 这种方式很容易被恶意攻击者入侵,那么又怎么验证客户端发给我的 session id 的确是我生成的呢?如果不去验证,服务器都不知道他们是不是合法登录的用户,那些不怀好意的家伙们就可以伪造 session id,为所欲为了。
这就需要我们用一种加密的方法或者可以说暗号,来验证这个 id 是否由我自己的服务器之前生成而非恶意攻击者篡改的。
- token
但是这里会有个问题,服务器要保存所有用户的 session 信息,开销会很大,如果在分布式的架构下,就需要考虑 session 共享的问题,需要做额外的设计和开发,例如把 session 中的信息保存到 Redis 中进行共享;所以因为这个原因,有人考虑这些信息是否可以让客户端保存,可以保存到任何地方,并且保证其安全性,于是就有了 token。
token 是服务端生成的一串字符串,可以看做客户端进行请求的一个令牌。
当客户端第一次访问服务端,服务端会根据传过来的唯一标识 userId,运用一些加密算法,生成一个 token,客户端下次请求时,只需要带上 token,服务器收到请求后,会验证这个 token。
有些公司会建设统一登录系统(单点登录),客户端先去这个系统获取 Token,验证通过再拿着这些 token 去访问其他系统;API Gateway 也可以提供类似的功能,我们公司就是这样,客户端接入的时候,先向网关获取 token,验证通过了才能访问被授权的接口,并且一段时间后要重新获取 token。
session 的原理
(1)服务器在处理客户端请求过程中会创建 session,并且为该 session 生存唯一的 session id。(这个 session id 在随后的请求中会被用来重新获得已经创建的 session。在 session 被创建后,就可以调用 session 相关的方法向 session 中新增内容,这些内容只会保存在服务器中)。
(2)服务器将 session id 发送到客户端。
(3)当客户端再次请求时,就会带上这个 session id。
(4)服务器接收到请求之后就会一句 session id 找到相应的 session,完成请求。
注意:
1、虽然 session 保存在服务器,但它还是需要客户端浏览器的支持,因为 session 需要使用 cookie 作为识别标志。服务器会向客户端发送一个名为 JSEDDIONID 的 cookie,它的值为 session id。
2、当 cookie 被禁用时,可以使用 url 重写的方法:将 session 写在 URL 中,服务器再进行解析。
cookie 的生命周期
cookie 的生存时间是整个会话期间:浏览器会将 cookie 保存在内存中,浏览器关闭时自动删除这个 cookie。
cookie 的生存时间是长久有效的:手动将 cookie 保存在客户端的硬盘中,浏览器关闭的话,cookie 页不会清除;下次在打开浏览器访问对应网站内容,这个 cookie 就会自动再次发送到服务器。
token 认证流程
token 的认证流程与 cookie 很相似:
- 客户端使用用户名、密码做身份验证;
- 服务端收到请求后进行身份验证;(也可能是统一登录平台、网关)
- 验证成功后,服务端会签发一个 token 返回给客户端;
- 客户端收到 token 以后可以把它存储起来(可以放在);每次向服务端发送请求的时候,都要带着 token;
- token 会有过期时间,过期后需要重新进行验证;
- 服务端收到请求,会验证客户端请求里面的 token,验证成功,才会响应客户端的请求;
应用场景
总结下来就是: session 是空间换时间,token 是时间换空间。
分布式 session 解决方案
方案 1:session 复制(session 同步)
原理:就是让这两个服务器之间互相同步 session,比如左边服务器之前保存了一个 1,右边服务器之前保存了一个 2,他们两个一同步,那么左边服务器保存了 1,2,右边服务器也保存了 1,2。这样做的话,我们无论去哪个服务器,都相当于能拿到全量的 session 数据,这样就不用担心负载均衡到哪个服务器了。
优点:tomcat 原生支持,只需要修改一下配置文件,好多 tomcat 之间就能复制 session。
缺点:
- session 同步需要通过网络进行数据传输,就有延迟问题,同时会占用大量带宽,这样会压缩我们整个业务的带宽,会降低我们的处理能力。
- 假如我们这里有 100 台 tomcat,每一个 tomcat 里面 session 都只存了 1G 的数据,我们想要用同步方案来做的话,那相当于其他 tomcat 都要保存剩下 99 个人的所有全量数据,那相当于每个 tomcat 都至少需要 100G 的内存才能将 session 整个全量保存下来。因此,这个解决方案受到内存限制,我们服务器无法水平扩展,不能复制上好多个 tomcat 来进行使用。
总结:如果是大型分布式集群环境,由于所有的 web-server 都全量保存数据,所以这种方案我们不使用。而如果是小型系统里面,就 3/5 个 tomcat,我们想使用的话,就简单配置一下也还可以。
方案 2:客户端存储
原理:我们让客户端自己来存储 session,我们服务器想用哪些数据,读取浏览器带过来的 cookie 即可。这样可以节省服务器资源。
缺点:都是缺点。
- 每次 http 请求,携带用户在 cookie 中的完整信息,浪费网络带宽。
- session 数据放在浏览器的 cookie 中,有些浏览器遵循的标准不一样,它的长度限制不一样,比如长度限制 4k,因此不能保存大量信息。
- session 数据放在 cookie 中,存在泄露、篡改、窃取等安全隐患。
总结:上面的缺点都很致命,因此我们实际绝对不会使用这种方案。
方案 3:HASH 一致性(推荐)
原理:
利用了我们负载均衡机制,我们可以利用 ip 的哈希一致性,只要来自于同一个 ip 的,那我们就永远给它定位到同一个服务器,我们也不给它跑到第二个服务器了,这样比如标绿色的浏览器去的标绿色的服务器里面存的东西,无论多少次请求过来,都会落到标绿色服务器的身上,我们就能取得到。
我们 hash 一致性还可以结合业务字段,如下面的图,凡是 456 号用户他的请求都落在绿色服务器,凡是 123 号这个用户他的请求都落在橙色服务器。
优点:
- 只需要改负载均衡 nginx 的配置,让它做一个 ip hash,而不需要修改应用代码。
- 负载是均衡的:只要 hash 属性的值分布是均匀的,多台 web-server 的负载就是均衡的。
- 支持 web-server 水平扩展(而 session 复制方案是不行的,受内存限制)。
缺点:
- session 还是存在 web-server 中,因此 web-server 突然闪断或者重启了,可能会导致部分 session 丢失,这部分用户只要下次再过来,所有的数据都没了,他需要重新登录一遍,所有东西都得重新做一遍。
- 如果我们服务器要水平扩展,如果我们固定了也好,但是如果原来是 2 台服务器,现在加到了 4 台服务器,现在想要做哈希的话,相当于重新得计算一下,假设我们以前计算哈希最简单的方式,按照 ip 地址得到一个整数型的哈希,如果只有 2 台服务器,那么就可以对 2 求余操作,求到余数,如果余数是 1,就落到第一台服务器,如果没有余数,就落到第二台服务器。但如果变成了 4 台服务器,我们相当于就要对 4 进行求余操作,如果余 1,落到第一台服务器,余 2 落到第二台服务器,余 3 落到第三台服务器,没有余数我们落到第四台服务器。(即水平扩展后,rehash 后 session 重新分布,会有一部分用户路由不到正确的服务器)
总结:以上缺点问题不大,而且后来呢,我们 ip 哈希的这种也用的比较多,因为基于 session 本来就是具有有效期的,就算这次因为水平扩展原因或者服务器闪断原因没有了,那就相当于浏览器关掉了呗,那我们让用户重新再做一次登录即可。
方案 4:统一存储(推荐)
原理:
我们之前出现的所有问题是,因为浏览器访问我们服务的时候,由于负载均衡机制会跳到不同的服务器,而又由于 session 是每个服务器各自存储在各自内存空间的,所以这导致我们跳到下一个服务器以后,我们上一个服务器 session 里面的数据它就用不到了,那怎么办呢?
那我们就可以让 session 统一存储,无论是你哪个服务器,哪个 tomcat,你的 session 都不要存储到你的内存里面了,全部呢,大家都可以存到数据库,或者 redis 之类的速度更快的 nosql 中间件等等。所以,我们可以使用这种方案。
优点:
- 没有安全隐患,没有让浏览器自己存储到 cookie 里,所有的数据都是我们后台统一存储,浏览器肯定是没办法访问到的,只要我们保障了我们后台的 redis 的安全,就没有人能去篡改里面相关的数据。
- 水平扩展也很容易,无论我们 web 服务器有多少个,10 个,100 个,1000 个,反正大家都去 redis 中做存取,即使 redis 不够用了,我们做 redis 集群,每个里面存一点,每个里面存一点。
- 括我们服务器即使重启、宕机,下次再启动了,我们 session 也不会丢失,因为 session 都是 redis 里面存着,跟我们业务服务器宕机与否没有任何关系。
缺点:
- 从内存中取数据是非常快的,也不需要网络交互,而如果我们存储到了 redis 里面,我们想要从 session 里面取数据,我们还得连接 redis,再来一次网络交互。
- 我们需要修改应用代码:如将所有的 getSession 方法替换为从 redis 查数据的方式。
总结:好的一点是,spring 早就意识到了这个问题,专门编写了一个框架叫 SpringSession,它就可以完美的解决我们 session 统一存储问题。
17. HTTP keep-alive 和 TCP keepalive 的区别
二者是完全不同的东西:
- HTTP keep-alive:是应用层(用户态)实现,称为 HTTP 长连接。
- TCP keepalive,是传输层 TCP(内核态)实现,称为 TCP 保活机制。
HTTP 的 keep-alive 也叫 HTTP 长连接,该功能是由「应用程序」实现的,可以使得用同一个 TCP 连接来发送和接收多个 HTTP 请求/应答,减少了 HTTP 短连接带来的多次 TCP 连接建立和释放的开销。
HTTP 协议的长连接和短连接,实质上是 TCP 协议的长连接和短连接。
TCP 的 Keepalive 也叫 TCP 保活机制,该功能是由「内核」实现的,当客户端和服务端长达一定时间没有进行数据交互时,内核为了确保该连接是否还有效,就会发送探测报文,来检测对方是否还在线,然后来决定是否要关闭该连接。
18. 什么是 Dos 攻击和 DDos 攻击?
DOS 攻击指的是攻击者通过向目标服务器发送大量的合法请求或利用安全漏洞,让服务器无法正常处理合法用户请求而导致服务不可用。攻击者的目的是消耗服务器的资源或使其崩溃,从而使正常用户无法访问服务。
DDOS 攻击是分布式的 DOS 攻击,攻击者利用多个恶意控制机器(也称为 “僵尸网络”)发起攻击。这些控制机器被远程控制,协同向目标服务器发送大量的请求,使其超出负载极限,导致服务不可用。
DOS 和 DDOS 攻击可以通过不同的方式实施,如:
- SYN Flood 攻击:攻击者发送大量伪造的 TCP 连接请求(SYN 包),而不真正建立连接,消耗服务器资源。
- UDP Flood 攻击:攻击者向目标服务器发送大量的 UDP 数据包,占用服务器带宽和处理能力。
- ICMP Flood 攻击:攻击者发送大量的 ICMP Echo 请求到目标服务器,占用服务器的网络带宽。
为了对抗 DOS 和 DDOS 攻击,通常采取以下措施:
- 过滤网络流量:通过配置防火墙、负载均衡器或入侵防御系统来过滤和丢弃恶意流量。
- 增加带宽和资源:增加服务器的处理能力和网络带宽,使其能够更好地抵御攻击。
- 流量清洗:使用专门的 DDOS 防护服务,识别和拦截恶意流量,只将合法流量转发到目标服务器。
- 分布式流量分析:通过分析流量模式,检测和阻止来自僵尸网络的恶意请求。