1、TCP/IP 三次握手(为什么3次,能否2次或者4次?),四次挥手(为什么4次,3次可以吗)
首先要会画 三次握手和四次挥手 的图。很重要,画了两次错了
3次握手的示意图如下:
三次握手过程:TCP发起的一方A,由操作系统生成一个序列号 n,以这个n为原点,对自己每个将要发送的数据进行编号,连接的另一方 B 会对A每次发送的数据进行确认,如果A收到B的确认编号2001,则可以认为 n~2000编号已经全部到达B。
为什么三次握手
- 首先,三次握手证明双方收发能力正常
- 其次,如果只需要两次握手,那第二次(从server发到client端)之后server就分配资源了,但是如果第二次丢失了,那就造成资源浪费
- 还有,如果client没有收到确认,就会再次发送握手连接,如果服务端先接到了第二个消息,然后发送返回确认,双方通信完毕,关闭。这时候第一个请求到了服务端,服务端确认,然而客户端已经关闭了,不理睬,这时候服务端只能一直等。
- 还有,握手就确认了双方的序列号规则
可以不握手吗?
tcp实现可靠通信与 报文序号和确认号(ack) 是分不开的,我们知道握手是干的啥,其中就有告知初始序号的功能,所以不能不握手。
4次挥手示意图:
由上图看出,由client端发起挥手,server给client的2次回复中,一次是确认信息ack,一次是数据的传送,那可不可以只要3次挥手呢?答案是可能的,TCP是全双工的,Client在没有数据需要发送给Server后,就发送FIN告知server,然后终止对server发送消息,但这个时候server还以发送数据给client,这时候需要4次;但是如果server收到client的FIN后再也没有数据要发给client了,那么 对client的ack包和server自己的FIN包就能合并成一个包发送过去,四次挥手变成3次。
了解完挥手完成后,可能还想更深入了解 TIME_WAIT,可以查看之前写的这篇。
2、延伸-握手可能有什么安全问题
首先,发起请求时候的序列是随机的,为什么是随机的呢?想想如果是固定的从0开始,那么客户端发送多次握手(重传),那么,当新连接建立之后,如果上一次的请求再过来了,序列还是 0 ,那就乱了。相反,如果序列不固定,那么上一次的过来,我只要和新连接这里对比下 序列号 就知道是否合法了。
- client第一个 SYN 包丢失,这个无所谓,后续触发重传机制,隔5s,24s等
- server 收到 SYN ,但是回复的 SYN,ACK 丢失,也会触发重传,可能依次隔 3s,6s,12s 等
- client 最后依次发送的 ACK 丢了,server 因为没收到 ACK 而实现重传,但是client 已经进入 ESTABLISHED 状态了。因为多数情况下,client 发送完最后的 ACK之后,就认为连接建立,开始发送数据。现实中的情况是,在这种情况下 server 收到 client 的数据会进入 ESTABLISH 状态,并会认为数据有效。
- 如果client 故意不发最后一次 ACK,那么服务端处于半连接状态,如果这种半连接很多的话,server 端很有压力,因为需要一直重传
以上内容参考自知乎上的文章、知乎上的文章1、知乎-泪花的回答
3、延伸-三次握手可以携带数据吗?
第一次、第二次不可以,第三次可以。想想为什么?
- 假如第一次允许带数据,那么攻击者只需要在第一次SYN中放入大量数据,根本不考虑服务器接收能力,这会让server 花费很长时间和很多空间来处理这些报文
- 并且,第一次不知道server 是否有接收能力;如果放第二次,server 也不知道clien 是否有接收能力。
以上内容参考自知乎上的文章、知乎上的文章1、知乎-泪花的回答
4、引申——为什么要等待2MSL?
原因有二:保证TCP协议的全双工连接能够可靠关闭 以及 保证这次连接的重复数据段从网络中消失
第一点:如果主机1直接CLOSED了,那么由于IP协议的不可靠性或者是其它网络原因,导致主机2没有收到主机1最后回复的ACK。那么主机2就会在超时之后继续发送FIN,此时由于主机1已经CLOSED了,就找不到与重发的FIN对应的连接。所以,主机1不是直接进入CLOSED,而是要保持TIME_WAIT,当再次收到FIN的时候,能够保证对方收到ACK,最后正确的关闭连接。
第二点:如果主机1直接CLOSED,然后又再向主机2发起一个新连接,我们不能保证这个新连接与刚关闭的连接的端口号是不同的。也就是说有可能新连接和老连接的端口号是相同的。一般来说不会发生什么问题,但是还是有特殊情况出现:假设新连接和已经关闭的老连接端口号是一样的,如果前一次连接的某些数据仍然滞留在网络中,这些延迟数据在建立新连接之后才到达主机2,由于新连接和老连接的端口号是一样的,TCP协议就认为那个延迟的数据是属于新连接的,这样就和真正的新连接的数据包发生混淆了。所以TCP连接还要在TIME_WAIT状态等待2倍MSL,这样可以保证本次连接的所有数据都从网络中消失。
5、IP地址分类(A/B/C/D类)
IP地址由四段组成,每个字段是一个字节,即4个字节、 每个字节有8位,最大值是255,IP地址 = 网络号+主机号。分为A、B、C三类及特殊地址D、E。全0和全1的都保留不用。
由图可知:
A类:前1个字节(8位)为网络号,后3个字节(24位)为主机号。A类第1位必须是0
B类:前2个字节(16位)为网络号,后2个字节(16位)为主机号。B类前两位固定为10
C类:前3个字节(24位)为网络号,后1个字节(8位)为主机号。C类前3位固定为110
D类: 是多播地址,一般用于多路广播用户。该类IP地址的最前面为1110
E类: 是保留地址。该类IP地址的最前面为1111
6、TCP与UDP区别
- UDP发送数据前无需建立连接,TCP需要握手建立连接。
- UDP尽最大努力交付,不保证可靠交付;TCP提供可靠交付。
- UDP面向报文,对应用程序交下来的报文,在添加首部之后就交付给Ip层,不会对报文拆分;TCP面向字节流,会对应用程序的报文进行拆分。
- UDP支持一对一、一对多、多对一和多对一的通信;TCP全双工通信,并且只能点对点通信,允许通信双方在任何时候均能通信。
- UDP首部开销小,TCP开销大(UDP 8个字节,TCP20个字节)。
- UDP没有拥塞控制,在网络条件差的情况下发送端也不会降低发送速率;TCP有拥塞控制,慢开始避免拥塞,快重传、快恢复。
- TCP 通过滑动窗口实现流量控制,UDP 无。
需要参考知乎上的讲解)重写一下
7、引申-TCP流量控制
如果发送方把数据发送得过快,接收方可能会来不及接收,这就会造成数据的丢失。所谓流量控制就是让发送方的发送速率不要太快,要让接收方来得及接收。
利用滑动窗口机制可以很方便地在TCP连接上实现对发送方的流量控制。
设A向B发送数据。在连接建立时,B告诉了A:“我的接收窗口是 rwnd = 400 ”(这里的 rwnd 表示 receiver window) 。因此,发送方的发送窗口不能超过接收方给出的接收窗口的数值。请注意,TCP的窗口单位是字节,不是报文段。假设每一个报文段为100字节长,而数据报文段序号的初始值设为1。大写ACK表示首部中的确认位ACK,小写ack表示确认字段的值ack。
从图中可以看出,B进行了三次流量控制。第一次把窗口减少到 rwnd = 300 ,第二次又减到了 rwnd = 100 ,最后减到 rwnd = 0 ,即不允许发送方再发送数据了。这种使发送方暂停发送的状态将持续到主机B重新发出一个新的窗口值为止。B向A发送的三个报文段都设置了 ACK = 1 ,只有在ACK=1时确认号字段才有意义。
TCP为每一个连接设有一个持续计时器(persistence timer)。只要TCP连接的一方收到对方的零窗口通知,就启动持续计时器。若持续计时器设置的时间到期,就发送一个零窗口控测报文段(携1字节的数据),那么收到这个报文段的一方就重新设置持续计时器。
8、引申-快重传和快恢复
- 快重传算法首先要求接收方每收到一个失序的报文段后就立即发出重复确认(为的是使发送方及早知道有报文段没有到达对方)而不要等到自己发送数据时才进行捎带确认。
- 快恢复:当发送方连续收到三个重复确认,就开始执行拥塞避免算法,缩小拥塞窗口,随后再使拥塞窗口缓慢地线性增大。
9、Http和Https的区别?
Https是ssl加密传输,Http是明文传输
Https是使用端口443,而Http使用80
HttpsSSL+HTTP协议构建的可进行加密传输、身份认证的网络协议要比Http协议安全
Https协议需要到CA申请证书
10、中间人攻击
带着下列问题去了解Https 安全性:
- 为什么用了https 就是安全的?用了https就一定安全吗?
- https 的底层原理如何?
点击看答案
https的原理
https的整体过程分为证书验证和数据传输阶段,具体交互如下图:
所以证书验证阶段流程就是:
- 客户端发起https 请求
- 服务端返回https 证书
- 客户端验证证书是否合法
数据传输阶段流程就是:
- 证书合法后,在本地生成随机数
- 通过公钥加密随机数,并把加密后的随机数传输给服务端
- 服务端通过私钥对随机数解密
- 服务端通过客户端传入的随机数构造对称加密算法,对返回结果内容进行加密后传输
那我们再引申一下,为什么后来要使用对称加密传输数据。这是因为:
- 非对称加密的效率低
- https 上述场景中,只有服务端保存了私钥,一对公私钥只能单向加解密,而对称加密可以实现双向的加解密
中间人攻击
了解以上原理之后,中间人攻击的具体流程如下:
主要包括以下步骤:
- 本地请求被劫持(如dns劫持等),所有请求均发送到中间人的服务器
- 中间人返回自己自己的证书
- 客户端创建随机数并通过中间人的证书公钥加密,之后凭随机数构造对称加密对传输内容加密
- 中间人用私钥解密随机数,此时中间人拥有客户端的随机数,所以可以通过对称加密算法解密内容
- 中间人再以客户端的请求内容向正规服务器发送请求,此时中间人发起的请求就是正规请求了,数据也是正规数据,所以合法,正规服务器会通过建立的安全通道返回加密数据
- 此后流程都是合法化的了,中间人只是做了个转发而已
以上,就是中间人攻击的流程,我们日常使用的fiddler 代理,其实就很好地模拟了中间人攻击。因为我们使用fiddler 代理https 的时候,需要本地信任fiddler 的证书,其实就是中间人返回自己的证书过程,中间人攻击关键也是这一步。
一般客户端会验证证书的合法性,所以中间人的证书没有这么容易被信任,中间人攻击的难点也在这。
以上内容参考自知乎-Java面试那些事儿
11、TCP/IP 流量控制,拥塞避免,可以结合这篇文章
12、Session 和 Cookie 的区别?
点击看答案
HTTP是一种无状态的协议,为了分辨链接是谁发起的,Session和Cookie就是为解决这个问题而提出来的两个机制。
Cookies是服务器下发,存储到本地机器上的一段文本,并随每一个请求发回服务器,是在客户端保持状态的方案。
浏览器第一次发送请求时,服务器自动生成了一HashTable和一个Session ID来唯一标识这个HashTable,并将其通过响应发送回浏览器。Session的实现方式和Cookie有一定关系,一般会把session id存在Cookie中(也可以依赖于url重写),每次访问的时候将Session id带过去,服务器就根据id查找hashtable就可以识别当前用户状态了。
所以可以总结,cookie存在本地,session存在服务器;父路径不能享用子路径的cookies,而同一个session的窗口可以共享session;cookie没有session可靠。
点击看答案
客户端浏览器通过DNS解析到www.baidu.com的IP地址220.181.27.48,通过这个IP地址找到客户端到服务器的路径。客户端浏览器发起一个HTTP会话到220.161.27.48,然后通过TCP进行封装数据包,输入到网络层。
在客户端的传输层,把HTTP会话请求分成报文段,添加源和目的端口,如服务器使用80端口监听客户端的请求,客户端由系统随机选择一个端口如5000,与服务器进行交换,服务器把相应的请求返回给客户端的5000端口。然后使用IP层的IP地址查找目的端。
客户端的网络层不用关系应用层或者传输层的东西,主要做的是通过查找路由表确定如何到达服务器,期间可能经过多个路由器,这些都是由路由器来完成的工作,我不作过多的描述,无非就是通过查找路由表决定通过那个路径到达服务器。
客户端的链路层,包通过链路层发送到路由器,通过邻居协议查找给定IP地址的MAC地址,然后发送ARP请求查找目的地址,如果得到回应后就可以使用ARP的请求应答交换的IP数据包现在就可以传输了,然后发送IP数据包到达服务器的地址。
14、HTTP中,POST与GET的区别
点击看答案
Get是从服务器上获取数据,Post是向服务器传送数据。
Get是把参数数据队列加到提交表单的Action属性所指向的URL中,值和表单内各个字段一一对应,在URL中科院看到。
Get传送的数据量小,不能大于2KB;post传送的数据量较大,一般被默认为不受限制。
根据HTTP规范,GET用于信息获取,而且应该是安全的和幂等的。
15、http2 与http1 的区别
点击看答案
总结一下:1)、新的二进制格式 2)、多路复用 3)、header 压缩 4)、采用新的压缩算法 5)、server push 6)、更安全的SSL
解释: http1 设计的时候是基于文本,http2 基于二进制格式。http2 的格式定义更接近tcp层的方式,length 定义了整个frame 的开始到结束,type 定义了frame 的类型,stream id 用作流控制。如下图所示:
虽然看上去写一个是和http1完全不同了,实际上并没有改变http1的语义,只是把http1的header 和 body 用frame 重新封装了一层而已。他们的对应关系如下:
上述http1的首部信息会封装到 Header 的 frame,而相应的 body 封装到 Data frame。
解释:多路复用允许同时通过单一的 HTTP/2 连接发起多重的请求-响应消息。一个request对应一个 stream 并分配一个id,这样一个连接上可以有多个stream,每个stream 的frame 可以随机地混杂在一起,接收方可以根据stream id 将各个frame 再归属到不同的request 里面。
http 性能优化的关键并不在于高带宽,而是低延迟,tcp 连接会随着时间进行自我“调谐”,起初会限制最大速度,如果传输成功,会随着时间提高传输的速度,这种调谐称为“慢启动”。http2 通过让所有数据流共用同一个连接,可以更高效地使用TCP。
客户端依据域名来向服务器建立连接,一般pc端浏览器会针对单个域名的server 同时建立 6~8 个连接,连接无法复用会导致请求要经历三次握手和慢启动。在http1中,假如有5个连接同时发出,在第一个请求没有收到回复之前,后续从应用层发出的请求只能排队,请求2,3,4,5只能等请求1的response 回来之后才能逐个发出。网络通畅的时候性能影响不大,一旦请求1的request 因为什么原因没有抵达服务器,影响到后续所有的请求,问题就比较严重了。
解释:http2针对header 采用新的压缩方式,高效地压缩算法可以很大地压缩header。并且,通讯双方各自缓存一份 header fields 表,避免重复header 的传输。
解释:http2在采用gzip之外的新的压缩算法,更加安全。
解释:http2 能通过push的方式将客户端需要的内容预先推送过去。
解释:http2.0 对 tls 的安全性做了进一步加强。
> 以上内容参考自[知乎上的回答](https://www.zhihu.com/question/34074946)
16、网络状态码?以 2、3、4、5 开头的代表什么意思。
点击看答案
1xx-临时响应
100: 继续。请求者应当继续提出请求
101: 切换协议。请求者要求服务器切换协议,服务器确认并准备切换
2xx-成功
200: 成功。服务器成功处理请求
201: 已创建。请求成功并且服务器创建了新的资源
202: 已接受。 服务器接受请求,但是尚未处理
203: 非授权信息。服务器成功处理请求,但返回的信息可能来自另一来源
204: 无内容。服务器成功处理请求,但是没有返回任何内容
205: 重置内容。服务器成功处理请求,但是没有返回任何内容
206: 部分内容。服务器成功处理了部分GET请求
3xx-重定向
300: 多种选择。服务器根据请求者选择一项操作,火提供操作列表供请求者选择
301: 永久移动。请求的资源永久移动到新位置了,返回此响应时会自动转到新位置
302: 临时移动。从不同位置响应请求,但是后续还是以原来位置继续请求
303: 查看其它位置。
304: 未修改。自上次请求后,请求的网页未修改过,此时不会返回网页内容
305: 使用代理。请求者只能使用代理访问请求的网页。
4xx-请求错误
400: 错误请求。服务器不理解请求语法
401: 未授权。请求要求身份验证
403: 进制。服务器拒绝请求
404: 未找到。服务器找不到请求的网页
405: 方法禁用。禁用请求中指定的方法
408: 请求超时。服务器等候请求时发生超时
410: 已删除。请求的资源已永久删除
413: 请求实体过大。请求实体过大,服务器无法响应
414: 请求的URI过长。请求的URI(通常为网址)过长,无法处理
415: 不支持的媒体类型。
5xx-服务器错误
500: 服务器内部错误。服务器遇到错误,无法完成请求
501: 尚未实施。服务器不具备完成请求的功能
502: 错误网关。
503: 服务不可用。暂时地维护或者超载了
504: 网关超时。服务器作为网关或者代理,但是没有及时从上游服务器收到请求
505: HTTP版本不支持。服务器不支持请求中所用的HTTP协议版本
以上内容参考自站长工具
17、HttpDNS
点击看答案
当前 DNS 系统存在的问题
- 域名缓存。运营商的 LocalDNS 会缓存域名解析的结果,而不是向权威域名发起递归。运营商缓存dns就可以实现把dns解析结果指向广告
- 解析转发。运营商自身不进行域名递归解析,而是把它发给其它运营商。一些小运营商就是这样做的。这样,比如说访问的是qq.com,则腾讯的权威dns收到的域名解析请求的来源就变成了其它运营商,最终导致用户流量被导向了错误的IDC,比如明明是广东的用户,被导向去了北京的服务器。
- NAT ,网络地址转换。运营商LocalDNS出口根据权威DNS目标ip进行NAT,导致腾讯权威dns无法正确识别运营商的 LocalDNS 的ip,引发域名解析错误,流量跨网等
解决方案
注意:HttpDNS主要用于客户端
HttpDNS 的使用过程主要有两步:
- 客户端直接访问HttpDNS 接口,获取Host对应的IP。
- 客户端通过IP,向后台发送请求。以Http为例,通过在Header中指定host 字段,向HttpDNS 返回的IP 发送标准的Http请求即可。
以上内容参考自鹅厂网事上的博客
18、https的证书验证
点击看答案
证书是一级一级的验证的,验证当前的证书时,首先拿上一级的证书的公钥,用上一级的公钥来验证当前证书的签名,验证成功就通过,不成功就报错了。然后一级一级上去,顶级。因为本地(浏览器和操作系统)一般存有信任的根证书,顶级证书一般都能通过本地证书验证。
以上内容可以参考知乎上的内容
19、https的攻击方式
点击看答案
1、中间人攻击。类似Fiddler 这种方式,前提是黑客通过某种特殊手段在被攻击者的手机上安装了根证书
2、Https协议降级攻击。比如说client端仅仅支持某个有漏洞的ssl版本(比如SSLv3.0),那么服务端只能接收或者直接拒绝。如果接受的话,攻击者就能攻击(应该是 Padding Oracle 攻击)
3、使用对称加密的时候破解的对称加密
以上内容参考自知乎的博客、中间人攻击
20、到底使用什么时候使用 GET 请求,什么时候使用 POST 请求?
点击看答案
当请求无副作用(如搜索)的时候,可以使用 GET 方法;当请求有副作用(如添加数据)的时候,则使用 POST 。不过有个很实际的问题: GET 方法可能会产生很长的 url ,并且某些浏览器和服务器对 GET 请求的 url 长度是有限制的 !
若符合下列任一情况,用 POST :
- 请求的结果有持续性的副作用
- 使用 GET 方法会使 url 过长
- 要传送的数据不是采用 7 位的 ASCII 编码
若符合下列任一情况,用 GET:
- 请求是为了查找资源
- 请求的结果无持续性副作用
- 收集的数据及 HTML 表单内输入字段名称的总长度不超过 1024 个字符
以上内容参考自 cnblogs 博客
21、TCP相关问题
粘包处理
TCP 两端 A、B 建立了连接后,A 端先发送 100 个字节,再发送 100 个字节。那么 B 端会分别收到两次 100 字节吗? 答案是不一定。
我们常说 TCP 是一种流式连接,这个流字到底怎么理解?它是指 TCP 的数据传输就像一种水流一样,并不区分不同数据包之间的界限。
看过 TCP 协议内容的人就可以发现,TCP 协议允许发送端将几次发送的数据包缓存起来合成一个数据包发送到网络上去,因为这样可以获得更高的效率,这一行为通常是在操作系统提供的 SOCKET 中实现,所以在应用层对此毫无所觉。 所以我们在程序中调用 send 发送超过 MTU 的数据包时,操作系统提供的 SOCKET 的 send 发送了数据后,操作系统有可能缓存了起来,等待后续的数据一起发送,而不是立即发送出去。
分包发送 网络传输的概念中有 MTU 的概念,也即是网络中一个数据包最大的长度。如果要发送超过这个长度的数据包,就需要分包发送。当调用 SOCKET 的 send 发送超过 MTU 的数据包时,操作系统提供的 SOCKET 实现会自动将这个数据包分割成几个不超过 MTU 的数据包发送。 当出现这些上面这些情况的时候,接收端就会发现接收到的数据和发送的数据的次数不一致。这个就是粘包现象。
问题
当我们传输如文件这种数据时,流式的传输非常适合,但是当我们传输指令之类的数据结构时,流式模型就有一个问题:无法知道指令的结束。所以粘包问题是必须要解决的。
粘包问题解决方案
- 短连接。需要发送数据的时候建立 TCP 连接,发送完一个数据包后就断开 TCP 连接,这样接收端自然就知道数据结束了。这种方案多次建立 TCP 连接,性能低下
- 长连接。使用长连接能够获得更好的性能但不可避免的会遇到如何判断数据结构的开始与结束的问题。
- 定长结构。如果发送端发送了一个固定长度的数据结构,接收端必须每次都严格判断接收到额数据的长度,当收到的数据长度不足时,需要再次接收数据,直到满足长度,当收到的数据多于固定长度时,需要截断数据,并将多余的数据缓存起来,视为长度不足需要再次接收处理。 不定长结构
定长的数据结构是一种理想的情况,真正的应用中通常使用的都是不定长的数据结构。
- 不定长结构。目前最通用的做法是在每次发送的数据的固定偏移位置写入数据包的长度。所以对于处理粘包的关键在于提前获取到数据包的长度。
心跳
当 TCP 两端 A、B 建立了连接后,如果一端拔掉网线或者拔掉电源,那么另一端能够收到通知吗?
答案是不会
TCP 的建立连接和断开连接都是通过发送数据实现的,也就是我们常说的三次握手、四次挥手。
但是这就说明了一点,如果不发送数据那么是无法断开连接的。正常情况下当 TCP 的一端A调用了 SOCKET 的 close 或者进程结束,操作系统就会按照 TCP 协议发送FIN 数据报文。B 端收到后就会断开连接。但是当出现了上文所说的异常情况时:被拔掉网线或者断掉电源,总结起来就是没有机会发出断开的 FIN 数据报文。那么和 A 直连的路由设备虽然知道 A 设备已经断开了,但是路由设备并没有保存连接的状态信息,所以路由设备也就不可能去通知 B 端 A 端的断开。而 B 端没有收到断开的数据报文就会依然保持连接。所以 A 端拔掉网线或者断掉电源后 B 端是没办法收到断开连接的通知的。
解决方案
KEEP_ALIVE
TCP 协议本身就提供了一种这样的机制来探测对端的存活。TCP 协议有一个KEEP_LIVE 开关,只要打开这个开关就会定时发送一些数据长度为零的探测心跳包,发送的频率和次数都可以设置
数据校验
TCP 如何保证数据的正确性,保证数据内容不会出错?
大部分人就会开始说丢包重传、接收确认之类的东西,但这些都扯偏了,只要少数人能够正确回答题目要问的问题:首部校验。
对于能答上这个问题的人,我会进一步问,这个校验机制能够确保数据传输不会出错吗?
答案是不能。
TCP 协议中规定,TCP 的首部字段中有一个字段是校验和,发送方将伪首部、TCP 首部、TCP 数据使用累加和校验的方式计算出一个数字,然后存放在首部的校验和字段里,接收者收到 TCP 包后重复这个过程,然后将计算出的校验和和接收到的首部中的校验和比较,如果不一致则说明数据在传输过程中出错。这就是TCP 的数据校验机制。
但是这个机制能够保证检查出一切错误吗?显然不能。因为这种校验方式是累加和,也就是将一系列的数字(TCP 协议规定的是数据中的每 16 个比特位数据作为一个数字)求和后取末位。
但是小学生都知道 A+B=B+A。
解决方案
在应用层添加一层校验
以上内容参考自csdn的博客