记一次 .NET Framework 不兼容 HTTP COOKIE 协议标准的问题跟踪

我们在后端系统实现了 HTTP 请求的代理类,用于请求其他第三方系统。大致的请求流程是这样的:

消费系统不能直接请求业务系统的 HTTP 接口,需要由中间的 HttpHelper 代理请求。其中 HttpHelper 接受消费系统传入的各种参数,包括要请求的 URL、METHOD、HEAD、BODY 等,在实际生产中一直运行得很好,直到如下异常的出现:

System.Net.CookieException: Cookie format error.
at System.Net.CookieContainer.CookieCutter(Uri uri, String headerName, String setCookieHeader, Boolean isThrow)

跟进异常信息,很容易知道是设置 Cookie 时发生的异常。根据请求端传入的 HEAD 信息排查,我们很容易还原故障现场:传入 HTTP 头信息 Cookie: expires=Fri, 15 Jun 2018 15:19:14 GMT

这里是在设置 Cookie 的过期时间,并且这个时间看起来也正常,并没有格式错误或者时间不存在的错误。看起来问题不出在时间本身上。上网查查 HTTP 规范,根据 HTTP Cookie 协议,也是允许如下形式的字符串的,看起来也没有什么问题:

Set-Cookie: sessionToken=abc123; Expires=Wed, 09 Jun 2021 10:18:14 GMT

既然异常是微软代码抛出来的,也给了具体抛出异常的方法的地方,那么我们就来翻翻微软代码吧。终于,在微软代码 System.Net.Cookie.VerifySetDefaults:L382 发现了问题所在。在这里,微软在校验 Cookie 值时,如果发现指定的值字符串中有保留字符(“,”、";"),则要求该值必须使用双引号引起来,否则就会抛出异常。查看我们请求的头,在 expires 的值“Fri, 15 Jun 2018 15:19:14 GMT”中,的确有“,”存在,并且值也并未使用双引号引起来。于是我尝试修改传入的 HTTP 头参数:

Cookie: expires=“Fri, 15 Jun 2018 15:19:14 GMT”

很自然,异常不再存在了,目前看起来的确是微软的这段代码导致了抛出异常。

你们我们来看看,这个值到底是不是可以去加双引号吧。继续上网翻文档,在 rfc2965#section-3.1 和 rfc6265#section-4.1.1 中提到,值可以是字符串或引号引起来的字符串(quoted-string),这是 在 HTTP State Management Mechanism 中有所规定的。那么我们可以很放心地做这个兼容性处理了,即,当传入的 Cookie 值包含保留字符,并且未被双引号引起来时(一定会产生异常),我们自动地追加双引号,把值引起来,这样既可避免微软对值进行严格校验时抛出异常了。

但是,此事还没有到此为止,我们实际来试试,加了双引号之后,业务系统是否能够正确收到消费系统传入的头呢?收到的头,是否为消费系统的正确意图呢?

值得注意的是,在业务系统里获取到的 Cookie 值,是添加了引号的值,并不是严格地与消费系统里传入的文本一致。

到此为止,应对这个异常便有两个方案了:

  1. 传入的 Cookie 值包含保留字符,并且未被双引号引起来时(一定会产生异常),我们自动地追加双引号。
  2. 什么都不做,按原意抛出异常,提醒调用者更正 HTTP 头信息的格式。

在我们的项目中,由于情况特殊(使用场景为后端服务之间的通信交互),一般不涉及到 Cookie 的设置,并且消费服务可能由很多个不同的团队实现,而业务服务可以统一处理添加的双引号,因此我们采用了方案 1。至于其他场景,实际上个人偏向于采用方案 2,不掩盖任何问题——特别是因为加了双引号之后,请求接受端接收到的值,不能完全原样表达请求发起端设置的值。

参考:

[1] https://en.wikipedia.org/wiki/HTTP_cookie [2] https://referencesource.microsoft.com/#System/net/System/Net/cookie.cs,67f8e4d3cb862668 [3] https://referencesource.microsoft.com/#System/net/System/Net/cookie.cs,dca3e494aed8e006 [4] https://tools.ietf.org/html/rfc6265#section-4.1.1 [5] https://tools.ietf.org/html/rfc2965#section-3.1 [6] https://tools.ietf.org/html/rfc2616

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏C#

DotNet加密方式解析--非对称加密

    新年新气象,也希望新年可以挣大钱。不管今年年底会不会跟去年一样,满怀抱负却又壮志未酬。(不过没事,我已为各位卜上一卦,卦象显示各位都能挣钱...)...

4798
来自专栏张善友的专栏

Mix 10 上的asp.net mvc 2的相关Session

Beyond File | New Company: From Cheesy Sample to Social Platform Scott Hansel...

2517
来自专栏转载gongluck的CSDN博客

cocos2dx 打灰机

#include "GamePlane.h" #include "PlaneSprite.h" #include "BulletNode.h" #include...

5286
来自专栏跟着阿笨一起玩NET

c#实现打印功能

2612
来自专栏闻道于事

js登录滑动验证,不滑动无法登陆

js的判断这里是根据滑块的位置进行判断,应该是用一个flag判断 <%@ page language="java" contentType="text/html...

6588
来自专栏Golang语言社区

【Golang语言社区】GO1.9 map并发安全测试

var m sync.Map //全局 func maintest() { // 第一个 YongHuomap := make(map[st...

4658
来自专栏杨龙飞前端

scrollto 到指定位置

2494
来自专栏张善友的专栏

LINQ via C# 系列文章

LINQ via C# Recently I am giving a series of talk on LINQ. the name “LINQ via C...

2605
来自专栏Ceph对象存储方案

Luminous版本PG 分布调优

Luminous版本开始新增的balancer模块在PG分布优化方面效果非常明显,操作也非常简便,强烈推荐各位在集群上线之前进行这一操作,能够极大的提升整个集群...

3035
来自专栏大内老A

The .NET of Tomorrow

Ed Charbeneau(http://developer.telerik.com/featured/the-net-of-tomorrow/) Exciti...

30810

扫码关注云+社区