Cookie写不进去问题深入调查 https Secure Cookie

什么情形下,Cookie 会写不进去?https Secure Cookie
像是语法错误那种显而易见的就不用说了,除此之外你可能会答说:写完全不同domain的Cookie。例如说你的网页在http://a.com却硬要写http://b.com的Cookie,这种情形当然写不进去。

或者,你可能会回答:不在https却想加上Secureflag的Cookie。
没错,像是这种情形也会写不进去。

除了这些,你还能想到什么吗?

如果想不太到,那就听我娓娓道来吧!

悲剧的开始

在一个月前我写了一篇跟CSRF有关的文章(让我们来谈谈CSRF),正是因为工作上需要实作CSRF的防御,所以趁机研究了一下。简单来说,就是要在Cookie设置一个csrftoken。

可是那天我却发现,我怎么写都写不进去。

我的测试网站的网址是:http://test.huli.com,拿来写Cookie的script是:

document.cookie = " csrftoken=11111111; expires=Wed, 29 Mar 2020 10:03:33 GMT; domain=.huli.com; path=/ "
我就只是想对.huli.com写一个名称是csrftoken的Cookie。而我碰到的问题,就是怎么写都写不进去。

这段语法完全没有问题,我检查过好几遍了,但就是不知道为什么写不进去。我们开头讲的那几种case 这边都完全没碰到。这只是一个简单的http 网站,而且是写自己domain 的Cookie,怎么会写不进去?

刚开始碰到这情形,我还想说会不会是我电脑的灵异现象,在其他人的电脑上就好了,就暂时没有管它,直到有一天PM跟我说:「咦,这个页面怎么坏了?」,我仔细检查后才发现是因为他也写不进去这个Cookie,导致server没有收到csrftoken而验证失败。

好了,看来现在已经确认不是我电脑上的问题了,而是大家都会这样。可是,却有其他人是正常的。其他人都可以,但就只有我跟PM 两个人不行。

幸好见过小风小浪的我知道,每次碰到这种诡异的问题,先开无痕模式再说,至少可以知道你的浏览器不会被其他因素给干扰。打开无痕模式之后发现,可以了,可以设定Cookie 了。在一般情况下不行设定,但是开无痕浏览模式却可以。

这就真的很奇怪了,到底为什么不行呢?而且若是我把Cookie换了一个名字,叫做csrftoken2,就可以写入了!就唯独csrftoken这个名称不行,可是Cookie总不可能有保留字这种东西吧!就算真的有,csrftoken也绝对不会是保留字。

这一切都太诡异了,到底csrftoken这个名字有什么问题?到底为什么写不进去?

于是我就去拜了Google大神,用cookie 不能寫、cookie can not set、unable set cookie等等的关键字去搜寻,却都一无所获,找到的答案都跟我的情况完全不一样。

我用Chrome devtool看了,明明http://test.huli.com就没有任何的Cookie,怎么会写不进去呢?

在经历过一阵乱找资料之后,我还稍微去翻了cookie的rfc:HTTP State Management Mechanism,但还是没有找到相关资料。

最后不知道哪来的灵感,我就去Chrome的设定那边检视所有huli.com的Cookie,并且一个一个看过之后删掉。删完之后,就可以正常写入Cookie了。

仔细想想其实还满合理的,毕竟无痕模式可以,就代表是以前做的一些事情会影响到写Cookie这件事,再经由删除Cookie就可以确认问题一定是出在其他有关的Domain身上,推测是其他Domain做了一些事情,才会造成http://test.huli.com没办法写入Cookie。

后来我回想起刚刚删掉的那几个Cookie,发现存在一个也叫做csrftoken的同名cookie。

拨云见日

难得让我找到了一点线索,当然要跟着这条线索继续查下去。

回想了一下,发现是另外一个负责后台管理的网站叫做:https://admin.huli.com写的,因为是用django的关系,所以开启CSRF防护之后预设的Cookie名称就是csrftoken。

仔细再用Chrome devtool看了一下,这个Cookie设置了Secure,Domain是.admin.huli.com。看起来也没什么异状。

然而,在拜访这个网站之后,我再试着去http://test.huli.com,发现又没办法写入Cookie了,甚至原本的Cookie也离奇地消失了。

太棒了!看来我离真相越来越近了!

我把这个.admin.huli.com的同名Cookie删掉之后,去拜访我自己的http://test.huli.com,发现一切都正常。Cookie可以正常写入。

看来答案很明显了,那就是:

只要.admin.huli.com的那个同名Cookie存在,http://test.huli.com就没办法对.huli.com写入同名的Cookie。
解法其实到这边就很明显了,第一个是改一个Cookie 名称,第二个是改一个Domain。

有关于第二个解法,还记得我们在http://test.huli.com是写入.huli.com这个Domain的Cookie吗?只要改成写入.test.huli.com这个Domain,一样可以正常运作。

所以若是讲得更详细一点,这个写不进去Cookie 的问题就发生在:

当有一个Domain为.admin.huli.com并设置成Secure的Cookie已经存在的时候,http://test.huli.com就没办法对.huli.com写入同名的Cookie。
在大概确认问题以后,我就开始调整各个变因,看能不能查出到底是哪一个环节出了问题,最后我发现两个重点:

其实只有Chrome 不能写,Safari, Firefox 都可以
Secure 这个flag 没有设置的话,就可以写
深入追查

既然有了只有Chrome 会发生这种情形的这个有力线索,就可以循着这条线继续追查下去,那怎么追查呢?

没错,就是最简单直接的方法:去找Chromium 的原始码!

以前看过很多文章都是查问题查一查最后查到Source code 去,终于轮到我也有这一天了。可是Chromium 的原始码这么一大包,该如何找起呢?

于是我决定先Google:chromium cookie,在第一笔搜寻结果发现了很有帮助的资料:CookieMonster。这篇文章有详细说明了Chromium的Cookie机制是怎么运作的,并且说明核心就是一个叫做CookieMonster的东西。

再来就可以直接去看Source code了,可以在/net/cookies找到cookie_monster.cc。

还记得刚刚发现的问题重点之一,推测是跟Secure这个flag有关,所以直接用Secure当关键字下去搜寻,可以在中间的部分发现一个DeleteAnyEquivalentCookie的function,以下节录部分原始码,1146行到1173行:

// If the cookie is being set from an insecure scheme, then if a cookie
// already exists with the same name and it is Secure, then the cookie
// should *not* be updated if they domain-match and ignoring the path
// attribute.
//
// See: https://tools.ietf.org/html/draft-ietf-httpbis-cookie-alone
if (cc-> IsSecure () && !source_url.SchemeIsCryptographic() &&
ecc.IsEquivalentForSecureCookieMatching(*cc)) {
skipped_secure_cookie = true ;
histogram_cookie_delete_equivalent_-> Add (
COOKIE_DELETE_EQUIVALENT_SKIPPING_SECURE);
// If the cookie is equivalent to the new cookie and wouldn't have been
// skipped for being HTTP-only, record that it is a skipped secure cookie
// that would have been deleted otherwise.
if (ecc. IsEquivalent (* cc)) {
found_equivalent_cookie = true ;
if (!skip_httponly || !cc-> IsHttpOnly ()) {
histogram_cookie_delete_equivalent_-> Add (
COOKIE_DELETE_EQUIVALENT_WOULD_HAVE_DELETED);
}
}
}
这边很贴心的帮你加上了注释,说是:

如果有个cookie 是来自insecure scheme,并且已经存在一个同名又设置为Secure 又domain-match 的cookie 的话,这个cookie 就不该被设置
虽然不太理解domain-match指的到底是怎样才算match,但看来我们碰到的写不进去Cookie的问题就是在这一段发生的。而且还有贴心附上参考资料:https://tools.ietf.org/html/draft-ietf-httpbis-cookie-alone
标题为:「Deprecate modification of 'secure' cookies from non-secure origins」。

内容不长,很快就可以看完,以下节录其中一小段:

Section 8.5 and Section 8.6 of [RFC6265] spell out some of the
drawbacks of cookies' implementation: due to historical accident,
non-secure origins can set cookies which will be delivered to secure
origins in a manner indistinguishable from cookies set by that origin
itself. This enables a number of attacks, which have been recently
spelled out in some detail in [COOKIE-INTEGRITY].
附注中的参考资料是这个:Cookies Lack Integrity: Real-World Implications,里面有附一段二十几分钟的影片,可以看一看,看完之后就会知道为什么不能写入了。

如果你还没看,这边可以帮大家做一个总结。要知道为什么刚开始那个case 不能写入Cookie,可以先想想看如果可以写入,会发生什么事情。

假如http://test.huli.com成功写入.huli.com的csrftoken这个cookie的话,对http://test.huli.com似乎没什么影响,就多带一个Cookie上去,看起来合情合理。

可是呢,却对https://admin.huli.com有些影响。

原本.admin.huli.com并且设置为Secure的Cookie还是会在,但现在多了个.huli.com又是同名的Cookie。当https://admin.huli.com送request的时候,就会把这两个Cookie一并带上去。所以Server收到的时候可能会是这样:

csrftoken=cookie_from_test_huli_com; csrftoken=cookie_from_admin_huli_com
但碰到同名Cookie的时候,很多人都会只取第一个处理,所以Server side收到的csrftoken就会是cookie_from_test_huli_com。

意思就是说,尽管你在https://admin.huli.com用Secure的方式写了一个Cookie,却被其他不安全的来源(http://test.huli.com)给覆盖过去了!

那盖掉Cookie 可以做什么呢?举几个上面参考资料给的例子(但我不确定有没有理解错误,有错的话请指正),第一个是Gmail 的视窗不是分成两部分吗,一部分是信箱,另外一部分是Hangouts。攻击者可以利用上面讲的手法把原来使用者的cookie 盖掉,换成自己的session cookie,可是因为Hangouts 跟Gmail 本身的domain 不一样,所以Gmail 还是使用者的帐号,Hangouts 却已经变成攻击者的帐号了。

被攻击的人就很有可能在不知情的状况下利用攻击者的帐号来发送讯息,攻击者就可以看到那些讯息了。

第二个例子是某间银行网站,假如在使用者要新增信用卡的时候把session cookie 换成攻击者的,那这张信用卡就新增到攻击者的帐户去了!

大概就是这样,总之都是透过把原本的cookie 遮蔽住,让server side 使用新的cookie 的攻击方法。

总结

我一开始碰到这个问题的时候真的满苦恼的,因为怎么想都想不到为什么一个语法完全没错的指令没办法写入Cookie,而且https://admin.huli.com这个网站我平常也很少用到,根本不会想到是它的问题。

但这次把问题解掉之后重新回来看,其实过程中就有一些蛛丝马迹可循,例如说可以透过「清掉Cookie 就没事」这点得知应该是跟其他Cookie 有干扰,也可以从别的浏览器可以写入这点得知应该是Chrome 的一些机制。

过程中的每个线索都会带你找到新的路,只要坚持走下去,一定能成功闯出迷宫。
转自:高级前端进阶

Cookie写不进去问题深入调查 https Secure Cookie的更多相关文章

  1. A Secure Cookie Protocol 安全cookie协议 配置服务器Cookie

    Title http://www.cse.msu.edu/~alexliu/publications/Cookie/cookie.pdf AbstractCookies are the primary ...

  2. 实体写到redis写不进去--误把类当成实体类

    之前一直都把实体写入redis都没有问题,今天再次这样干,结果却是怎么写都写不进去,redis里的值老是为空 最后才发现把类当成了实体类,当然写不进去了. 把类: /// <summary> ...

  3. FileStream和StreamWriter配合写数据流时,出现数据写不进去的问题

    今天做一个数据导进txt小程序时,发现一个问题,就是没有关闭sw的流,只关闭了fs的,结果写不进去数据,看代码是对的,就是不行,最后就随手填上了sw的关闭后,可以了,反复测试,竟然就是这的问题,有点搞 ...

  4. hbase集群写不进去数据的问题追踪过程

    hbase从集群中有8台regionserver服务器,已稳定运行了5个多月,8月15号,发现集群中4个datanode进程死了,经查原因是内存 outofMemory了(因为这几台机器上部署了spa ...

  5. http、https和Cookie

    http和https http,https 都是网络传输协议 是用于网络相关传输,http走的是明文传输,https走的密文传输(内部采用对称加密以及非对称加密).对应的https安全性要高于http ...

  6. asp.net,cookie,写cookie,取cookie

    Cookie是一段文本信息,在客户端存储 Cookie 是 ASP.NET 的会话状态将请求与会话关联的方法之一.Cookie 也可以直接用于在请求之间保持数据,但数据随后将存储在客户端并随每个请求一 ...

  7. 自己Cookie写的自动登录功能 包含BASE64 和MD5的使用

    sql表 username  password字段 User类 有 id username password等字段 Service有一函数 @Override public User findUser ...

  8. asp.net,cookie,写cookie,取cookie(转载)

    Cookie是一段文本信息,在客户端存储 Cookie 是 ASP.NET 的会话状态将请求与会话关联的方法之一.Cookie 也可以直接用于在请求之间保持数据,但数据随后将存储在客户端并随每个请求一 ...

  9. Android中Http加载如何得到Cookie和 WebView 加载网页如何得到的Cookie

    最近做项目在手机端登录Http请求和 WebView 记载登录获取Cookie信息,可查看Cookie信息. 如图: Http请求获取Cookie信息: public static String re ...

随机推荐

  1. Java当中的IO一

    1.IO操作的目标 什么是IO操作的目标? 输入: 从数据源当中读取数据 输出: 将数据写入到数据目的地当中 有数据进入到程序当中,这个过程就可以被叫做输入 流:即在数据源与程序之间建立的传输通道 2 ...

  2. centos中安装配置nginx完成之后主机无法访问

    原因 VMware中安装centos7,安装配置完成nginx后,主机无法访问.虚拟机没有放行Nginx默认端口80. 解决办法 首先:开启 web 端口 firewall-cmd --permane ...

  3. VS开发入门三:c#的类的修饰符和成员的修饰符

    初学者经常会犯下的错误就是,修饰符一大堆,而且类和其成员很多修饰符是一样的容易混用 这里总结下 C#修饰符之类修饰符(个 助记 PIPA SS ):public.internal. partial(多 ...

  4. PCB布局布线

    1.关键芯片的物理位置,明细信号流向,防止关键信号交叉,高速线布线通畅. 2.可装配,可维修,可测试. 3.模拟电路和数字电路分区摆放. 4.疏密有序. 5.原理图应该明确主芯片周边元件的布局要求. ...

  5. jenkins配置自动发送邮件,抄送

    1.安装插件.系统管理-安装插件:可选插件:搜索Email Extension 2.设置全局变量.系统管理-系统设置:a.Jenkins Location 设置发送方邮件--- b.Extended ...

  6. robot framework + win7 64 上的安装

    1.安装 python 2.7   2.cmd  管理模式 python -m pip install --upgrade pip     pip install robotframework==3. ...

  7. php中数组直接用加号相加array+array

    php中数组功能非常强大,甚至也可以直接通过+相加来合并数组. A数组 $a = ['a', 'b']; B数组 $b = ['c', 'd', 'e']; A+B结果 Array ( [0] =&g ...

  8. Fiddler抓取数据并分析(完整的配置教程)

    一.Fiddler现在的移动应用程序几乎都会和网络打交道,所以在分析一个 app 的时候,如果可以抓取出其发出的数据包,将对分析程序的流程和逻辑有极大的帮助.对于HTTP包来说,已经有很多种分析的方法 ...

  9. jQuery-AutoComplete自动提示简单实现

    注:本次案列实现功能为 用户注册信息,如果数据库对应表中存在部分信息,点击已有的用户的用户名,自动补全其它已有的基本信息 实现思路:通过AutoComplete提示,异步通过用户名查询全表,充当Aut ...

  10. AIX 7.1 RAC 11.2.0.4.0升级至11.2.0.4.6(一个patch跑了3个小时)

    1.环境 DB:两节点RAC 11.2.0.4.0升级至11.2.0.4.6 OS:AIX 7.1(205G内存 16C) 2.节点1.节点2(未建库) 2.1.patch 20420937居然用了3 ...