IOS同名Cookie覆盖失败问题分析

1.  问题现象

在测试APP中的H5页面时,有时会出现无法根据Cookie内容获取Session的情况。现象如下:

l  查看APP中H5页面的调试窗口,同名的Cookie存在两个;

l  同名的Cookie存在两个的问题,仅在IOS出现,未在Android出现;

l  出现问题的请求,目前使用GET方式;以前使用POST方式时,未出现过该问题;

l  对于设置了过期时间的Cookie,会出现该问题;未设置过期时间的Cookie,未出现该问题。

使用Tomcat作为Web应用服务器,在设置Cookie时,使用的参数包括Cookie名称、Cookie值、超时时间(部分Cookie设置)、Path等。

2.  问题分析

2.1  通信数据分析

2.1.1  IOS覆盖失败通信数据分析

以下通信数据,通过HTTP请求头的User-Agent可以看到操作系统为IOS。

从下图可以看到,第一次请求中,服务器对客户端设置了名称为“q..._cookie_key”的Cookie,值为“7454d62524e827acd9ff5901a7afa282”,Path为“/w...a”。

从下图可以看到,第二次请求中,客户端包含名称为“q..._cookie_key”的Cookie,值为“7454d62524e827acd9ff5901a7afa282”; 服务器对客户端设置了名称为“q..._cookie_key”的Cookie,值为“cabfea9857194e32cd881d3207cb2c50”,Path为“/w...a”。

从下图可以看到,第三次请求中,客户端包含两个名称为“q..._cookie_key”的Cookie,值分别为“7454d62524e827acd9ff5901a7afa282”与“cabfea9857194e32cd881d3207cb2c50”。

由上可知,上述通信过程中,服务器对IOS客户端的名称相同的Cookie设置了两次,但后一次设置的Cookie值未将前一次设置的Cookie值覆盖,两个不同的Cookie值均存在。

2.1.2  Android覆盖成功通信数据分析

以下通信数据,通过HTTP请求头的User-Agent可以看到操作系统为Android。

从下图可以看到,第一次请求中,服务器对客户端设置了名称为“q..._cookie_key”的Cookie,值为“2b0cac5df973d05648b6eb05738e1c6e”,Path为“/w...a”。

从下图可以看到,第二次请求中,客户端包含名称为“q..._cookie_key”的Cookie,值为“2b0cac5df973d05648b6eb05738e1c6e”; 服务器对客户端设置了名称为“q..._cookie_key”的Cookie,值为“2d3e61a275680ed5e241f5148e08c39e”,Path为“/w...a”。

从下图可以看到,第三次请求中,客户端包含一个名称为“q..._cookie_key”的Cookie,值为“2d3e61a275680ed5e241f5148e08c39e”。

由上可知,上述通信过程中,服务器对Android客户端的名称相同的Cookie设置了两次,后一次设置的Cookie值将前一次设置的Cookie值覆盖。

2.2  未设置过期时间的Cookie覆盖成功分析

对于未设置过期时间的Cookie,未出现覆盖失败的现象,只有存在过期时间的Cookie,出现了覆盖失败的现象。

查看javax.servlet-api-4.0.0.jar中的javax.servlet.http.Cookie类的setMaxAge方法的注释如下:

Sets the maximum age in seconds for this Cookie. 

 

A positive value indicates that the cookie will expire after that many seconds have passed. Note that the value is the maximum age when the cookie will expire, not the cookie's current age.

 

A negative value means that the cookie is not stored persistently and will be deleted when the Web browser exits. A zero value causes the cookie to be deleted.

即Cookie.setMaxAge方法用于设置Cookie的过期时间(以秒为单位),当参数值为正时,表明当前Cookie会在指定秒后过期;当参数值为负时,代表当前Cookie不会被持久化存储,会在浏览器退出后删除。

当设置存在过期时间的Cookie时,调用Cookie.setMaxAge方法时传入的参数值为正;当设置不存在过期时间的Cookie时,调用Cookie.setMaxAge方法时传入的参数值为负。

由于不存在过期时间的Cookie在浏览器退出后会被删除,因此当客户端页面关闭后,不会出现不能覆盖的问题。

2.3  IOS分析

2.3.1  IOS文档说明

在IOS中可使用cookiesWithResponseHeaderFields方法,创建HTTP Cookie数组。

查看https://developer.apple.com/documentation/foundation/nshttpcookie/1393011-cookieswithresponseheaderfields?language=objc,有如下内容:

If headerFields doesn’t specify a domain for a given cookie, the cookie is created with a default domain value of URL.

即使用以上方法创建Cookie时,若未指定Cookie的domain属性,则默认使用URL作为domain。

2.3.2  IOS使用POST方法覆盖成功分析

IOS使用POST方法进行请求时,使用访问的URL是固定的,即每次设置的domain是不变的,因此同名Cookie可以覆盖成功。

2.3.3  IOS使用GET方法覆盖失败分析

使用GET方法进行请求时,使用访问的URL是不同的,即每次设置的domain是不同的,因此同名Cookie会覆盖失败。

(查看前文截图,每次请求的URL不相同)

2.4  Android分析

2.4.1  Android文档说明

查看https://developer.android.com/reference/java/net/HttpCookie,有如下内容:

By default, cookies are created according to the RFC 2965 cookie specification.

创建cookies时,默认根据RFC 2965。

2.4.2  JDK文档说明

查看JDK 1.8的java.net.CookieManager类,包含以下内容:

                        // As per RFC 2965, section 3.3.1:

                        // Domain  Defaults to the effective request-host.  (Note that because

                        // there is no dot at the beginning of effective request-host,

                        // the default Domain can only domain-match itself.)

                        if (cookie.getDomain() == null) {

                            String host = uri.getHost();

                            if (host != null && !host.contains("."))

                                host += ".local";

                            cookie.setDomain(host);

                        }

根据注释及代码可以看到,JDK根据RFC 2965,默认使用请求host作为domain(当domain为空时,则使用请求host作为domain)。

2.5  RFC说明

2.5.1  RFC 2965关于Cookie domain参数默认值说明

查看https://tools.ietf.org/html/rfc2965#section-3.3,有如下内容:

Domain  Defaults to the effective request-host.  (Note that because there is no dot at the beginning of effective request-host, the default Domain can only domain-match itself.)

2.5.2  Cookie domain参数是否需要以.开头的说明

l  RFC 6265

RFC 6265(https://tools.ietf.org/html/rfc6265#section-4.1.2.3,2011年4月)中相关说明如下:

The Domain attribute specifies those hosts to which the cookie will be sent.  For example, if the value of the Domain attribute is "example.com", the user agent will include the cookie in the Cookie header when making HTTP requests to example.com, www.example.com, and www.corp.example.com.  (Note that a leading %x2E ("."), if present, is ignored even though that character is not permitted, but a trailing %x2E ("."), if present, will cause the user agent to ignore the attribute.)  If the server omits the Domain attribute, the user agent will return the cookie only to the origin server.

The user agent will reject cookies unless the Domain attribute specifies a scope for the cookie that would include the origin server.  For example, the user agent will accept a cookie with a Domain attribute of "example.com" or of "foo.example.com" from foo.example.com, but the user agent will not accept a cookie with a Domain attribute of "bar.example.com" or of "baz.foo.example.com".

domain属性指定cookie将会被发送到的主机。例如,如果domain属性的值为“example.com”,则在向example.com,www.example.com和www.corp.example.com发出HTTP请求时,用户代理将在Cookie头中包含对应的cookie。(请注意,前导%x2E(".")(如果存在)将被忽略,即使该字符不被允许,但尾随的%x2E(".")(如果存在)将导致用户代理忽略该属性。)如果服务器忽略了domain属性,则用户代理将仅将cookie发送到原始服务器。

除非domain属性指定包含原始服务器的cookie的范围,否则用户代理将拒绝cookie。例如,用户代理将接受来自foo.example.com的domain属性为“example.com”或“foo.example.com”的cookie,但用户代理不会接受domain属性为“bar.example.com”或“baz.foo.example.com”的cookie。

在RFC 6265中,若domain属性不以“.”开头,也能匹配子域名。

l  RFC 2965

RFC 2965(https://tools.ietf.org/html/rfc2965#section-3.3,2000年10月)中相关说明如下:

Domain  Defaults to the effective request-host.  (Note that because there is no dot at the beginning of effective request-host, the default Domain can only domain-match itself.)

*  A Set-Cookie2 from request-host x.foo.com for Domain=.foo.com would be accepted.

domain默认为有效的请求主机。(请注意,由于在有效请求主机的开头没有点,因此默认域只能与自身进行域匹配。)

在RFC 2965中,domain属性需要以“.”开头,才能匹配子域名。

l  RFC 2109

RFC 2109(https://tools.ietf.org/html/rfc2109#section-4.2.2,1997年2月)中相关说明如下:

Domain=domain Optional.  The Domain attribute specifies the domain for which the cookie is valid.  An explicitly specified domain must always start with a dot.

* A Set-Cookie from request-host x.foo.com for Domain=.foo.com would be accepted.

domain属性是可选的。domain属性指定cookie有效的域。明确指定的域必须始终以点开头。

在RFC 2965中,domain属性需要以“.”开头,才能匹配子域名。

可以看到,在RFC 6265中,domain属性可以不以“.”开头,即可匹配子域名;在之前的版本中,domain属性需要以“.”开头,才能匹配子域名。

为了兼容旧版本的实现,在设置Cookie的domain属性时,最好以“.”开头。

3.  问题解决

3.1  解决方法

在设置Cookie时,设置domain属性(domain属性值设置为“.”加当前域名),可以解决IOS同名Cookie覆盖失败问题。

3.2  IOS覆盖成功通信数据分析

以下通信数据,通过HTTP请求头的User-Agent可以看到操作系统为IOS。

从下图可以看到,第一次请求中,服务器对客户端设置了名称为“q..._cookie_key”的Cookie,值为“2edb3aef87277e79c44e099d62910e05”,Path为“/w...a”。

从下图可以看到,第二次请求中,客户端包含名称为“q..._cookie_key”的Cookie,值为“2edb3aef87277e79c44e099d62910e05”; 服务器对客户端设置了名称为“q..._cookie_key”的Cookie,值为“a25c0b4fb350981672e5c17d17fc7e95”,Path为“/w...a”。

从下图可以看到,第三次请求中,客户端包含一个名称为“q..._cookie_key”的Cookie,值为“a25c0b4fb350981672e5c17d17fc7e95”。

由上可知,上述通信过程中,服务器对IOS客户端的名称相同的Cookie设置了两次,后一次设置的Cookie值将前一次设置的Cookie值覆盖。

IOS同名Cookie覆盖失败的问题解决。

发布了37 篇原创文章 · 获赞 0 · 访问量 2321

猜你喜欢

转载自blog.csdn.net/a82514921/article/details/104609862