前几天在业务开发中,在iframe中嵌入打开一个xxx的url链接,在链接的主页中,会跳转到另一个登录的页面,然而登录一直失败,失败原因是xxx的服务端没有收到对应的cookie。但是在浏览器中的顶层搜索打开xxx的url链接,在跳转到另一个登录的页面后,就可以正常的登录。
页面嵌套关系如下所示:

Cookie简介:
HTTP 协议是无状态的,但可以通过 Cookie 来维持客户端与服务端之间的“会话状态”。
简单来说就是:服务端通过 Set-Cookie 响应头设置 Cookie 到客户端,而客户端在下次向服务器发送请求时添加名为 Cookie 的请求头,以携带服务端之前“埋下”的内容,从而使得服务端可以识别客户端的身份。
本地代码示例如下:
配置本地host
127.0.0.1 a.cross.com
127.0.0.1 b.test.com
127.0.0.1 a.test.com
开启serverB:
const http = require("http");
const fs = require("fs");
let server = http.createServer((req, res) => {
const cookie = req.headers.cookie
console.log('cookie', cookie);
res.writeHead(200, [
["Set-Cookie", "name=bbb"], // 设置 cookie
]);
if (!cookie) {
res.end("no cookie");//没有cookie时
return
}
if ("/" == req.url) {
fs.readFile(__dirname + "/index.html", "utf-8", (err, data) => {
if (err) {
throw err;
} else {
res.end(data);
}
});
} else if (req.url == "/favicon.ico") {
res.statusCode = 204;
res.end();
} else {
res.end("404 NOT Found");
}
});
server.listen(3002, () => {
console.log("服务器启动成功");
});
serverB中index.html的body为:
<body>
<div>i am B页面</div>
</body>
在浏览器顶部导航栏输入http://b.test.com:3002时,正常的B页面展示为

在A中使用iframe嵌套B的url,开启serverA:
const http = require("http");
const fs = require("fs");
let server = http.createServer((req, res) => {
console.log(req.url);
if ("/" == req.url) {
fs.readFile(__dirname + "/index.html", "utf-8", (err, data) => {
if (err) {
throw err;
} else {
res.end(data);
}
});
} else if (req.url == "/favicon.ico") {
res.statusCode = 204;
res.end();
} else {
res.end("404 NOT Found");
}
});
server.listen(3001, () => {
console.log("服务器启动成功");
});
serverA中index.html的body为:
<body>
<div>i am A页面</div>
<iframe src="http://b.test.com:3002"></iframe>//iframe嵌套B页面的url
</body>
在chrome中打开http://a.cross.com:3001,页面展示如下:

可以看到在A页面的iframe中嵌套B页面时,在B服务中没有获取到cookie信息,所以没有展示正常的B页面。
那接下来就一块来分析问题吧。
既然在浏览器顶部导航栏输入http://b.test.com:3002时可以正常显示,那看一下此时的网络请求情况:

看一下访问失败时的请求头情况

可以看到请求异常的情况下,请求头中没有携带cookie信息,并且在响应头中会提示SameSite=Lax信息。
查看b站点的Application中的Cookie信息

可以看到本地有b站点的cookie信息。为什么本地有cookie信息,但是请求的时候request header中没有携带此cookie信息呢?
查找资料得知,从 Chrome 80 开始,如果不指定 SameSite 就等效于设置为 Lax。
SameSite 是 HTTP 响应头 Set-Cookie的属性之一。它允许声明该 Cookie 是否仅限于第一方或者同一站点上下文。
SameSite 可以有下面三种值:
之前默认是 None 的,Chrome80 后默认是 Lax。
Lax的情况见下表:
| 请求类型 | 示例 | 正常情况 | Lax |
|---|---|---|---|
| 链接 | <a href="..."></a> |
发送 Cookie | 发送 Cookie |
| 预加载 | <link rel="prerender" href="..."/> |
发送 Cookie | 发送 Cookie |
| GET 表单 | <form method="GET" action="..."> |
发送 Cookie | 发送 Cookie |
| POST 表单 | <form method="POST" action="..."> |
发送 Cookie | 不发送 |
| iframe | <iframe src="..."></iframe> |
发送 Cookie | 不发送 |
| AJAX | $.get("...") |
发送 Cookie | 不发送 |
| Image | <img src="..."> |
发送 Cookie | 不发送 |
当sameSite为Lax时,post、iframe、ajax、image的跨站请求都不会发送cookie。
要理解上面的规则,还需要了解一下跨域和跨站的区别。
首先要理解的一点就是跨站和跨域是不同的。同站(same-site)/跨站(cross-site)和第一方(first-party)/第三方(third-party)是等价的。但是与浏览器同源策略(SOP)中的同源(same-origin)/跨域(cross-origin)是完全不同的概念。
同源策略的同源是指两个 URL 的协议/主机名/端口一致。例如,https://www.baidu.com,它的协议是 https,主机名是 www.baidu.com,端口是 443。
同源策略作为浏览器的安全基石,其同源判断是比较严格的。相对而言,Cookie中的同站判断就比较宽松:只要两个 URL 的 eTLD+1 相同即可,不需要考虑协议和端口。其中,eTLD 表示有效顶级域名,注册于 Mozilla 维护的公共后缀列表(Public Suffix List)中,例如,.com、.co.uk、.github.io 等。eTLD+1 则表示,有效顶级域名+二级域名,例如 baidu.com 等。
举几个例子,www.taobao.com 和 www.baidu.com 是跨站,a.baidu.com 和 b.baidu.com是同站,a.github.io 和 b.github.io 是跨站(注意是跨站)。
在上面的模拟示例中我使用的chrome浏览器的版本是107版本,虽然本地是有cookie信息,但是SameSite为空,也就是没有设置,所以默认SameSite=Lax,导致在A页面访问iframe中的B站点时,是跨站的方式,不会发送B站点的cookie信息。
这种问题的解决方案有以下几种
1、服务器在set-cookie时,设置SameSite=None; Secure。但是这里需要注意:
2、使用Nginx或其他网关工具进行Proxy操作,使跨站请求变为同站请求
将这个被调用接口的应用和发起请求的应用放在同一个站下面,使他们是同站请求,这样就不存在跨站问题了。
比如上面模拟示例所示,在host配置中,将A站点127.0.0.1使用a.test.com映射,这样在a.test.com中访问b.test.com就是同站访问了。
或者使用nginx代理请求,将a.test.com代理到a.cross.com,这样在浏览器中顶部导航栏中输入a.test.com就可以被nginx代理访问到a.cross.com,而这时浏览器会认为在a.test.com页面中访问b.test.com,浏览器会当作同站处理cookie。同理可以使用nginx代理b站点的url,使与A站点同站。
3、使用http auth也就是header auth方式进行,将令牌通过header的形式传输,不使用Cookie,那当然也就不存在Cookie中奇奇怪怪的问题了。
4、使用指定版本的浏览器,使用chrome内核低于80的浏览器,或者在safari中关闭防止跨站追踪选项。
以上列出了4种解决此类问题的方法,具体还需要结合自己的业务场景选择合适的解决方案。
参考:
https://github.com/mqyqingfeng/Blog/issues/157
我希望我的UserPrice模型的属性在它们为空或不验证数值时默认为0。这些属性是tax_rate、shipping_cost和price。classCreateUserPrices8,:scale=>2t.decimal:tax_rate,:precision=>8,:scale=>2t.decimal:shipping_cost,:precision=>8,:scale=>2endendend起初,我将所有3列的:default=>0放在表格中,但我不想要这样,因为它已经填充了字段,我想使用占位符。这是我的UserPrice模型:classUserPrice回答before_val
我有一个包含模块的模型。我想在模块中覆盖模型的访问器方法。例如:classBlah这显然行不通。有什么想法可以实现吗? 最佳答案 您的代码看起来是正确的。我们正在毫无困难地使用这个确切的模式。如果我没记错的话,Rails使用#method_missing作为属性setter,因此您的模块将优先,阻止ActiveRecord的setter。如果您正在使用ActiveSupport::Concern(参见thisblogpost),那么您的实例方法需要进入一个特殊的模块:classBlah
我有一个具有一些属性的模型:attr1、attr2和attr3。我需要在不执行回调和验证的情况下更新此属性。我找到了update_column方法,但我想同时更新三个属性。我需要这样的东西:update_columns({attr1:val1,attr2:val2,attr3:val3})代替update_column(attr1,val1)update_column(attr2,val2)update_column(attr3,val3) 最佳答案 您可以使用update_columns(attr1:val1,attr2:val2
我有这个html标记:我想得到这个:我如何使用Nokogiri做到这一点? 最佳答案 require'nokogiri'doc=Nokogiri::HTML('')您可以通过xpath删除所有属性:doc.xpath('//@*').remove或者,如果您需要做一些更复杂的事情,有时使用以下方法遍历所有元素会更容易:doc.traversedo|node|node.keys.eachdo|attribute|node.deleteattributeendend 关于ruby-Nokog
对于Rails模型,是否可以/建议让一个类的成员不持久保存到数据库中?我想将用户最后选择的类型存储在session变量中。由于我无法从我的模型中设置session变量,我想将值存储在一个“虚拟”类成员中,该成员只是将值传递回Controller。你能有这样的类(class)成员吗? 最佳答案 将非持久属性添加到Rails模型就像任何其他Ruby类一样:classUser扩展解释:在Ruby中,所有实例变量都是私有(private)的,不需要在赋值前定义。attr_accessor创建一个setter和getter方法:classUs
所以这可能有点令人困惑,但请耐心等待。简而言之,我想遍历具有特定键值的所有属性,然后如果值不为空,则将它们插入到模板中。这是我的代码:属性:#===DefaultfileConfigurations#default['elasticsearch']['default']['ES_USER']=''default['elasticsearch']['default']['ES_GROUP']=''default['elasticsearch']['default']['ES_HEAP_SIZE']=''default['elasticsearch']['default']['MAX_OP
假设我有以下类(class):classPersondefinitialize(name,age)@name=name@age=ageenddefget_agereturn@ageendend我有一组Person对象。是否有一种简洁的、类似于Ruby的方法来获取最小(或最大)年龄的人?如何根据它对它们进行排序? 最佳答案 这样做会:people_array.min_by(&:get_age)people_array.max_by(&:get_age)people_array.sort_by(&:get_age)
我在rubyonrails应用程序中有以下新方法:defnewifcookies[:owner].empty?cookies[:owner]=SecureRandom.hexend@movie=Movie.new@movie.owner=cookies[:owner]end基本上,每个新用户都应该获得一个代码来识别他们(尽管只是通过cookie)。因此,当用户创建电影时,创建的cookie将存储在owner字段中。所以有两个问题:使用.empty?方法,当我从浏览器中删除cookie时,返回一个undefinedmethodempty?'对于nil:NilClass`当我确实已经在
我想为我的Task模型创建一个status属性,该属性将按以下顺序指示它在三部分进度中的位置:打开=>进行中=>完成。它的工作方式类似于亚马逊包裹的交付方式:已订购=>已发货=>已交付。我想知道设置此属性的最佳方法是什么。我可能是错的,但创建三个独立的bool属性似乎有点多余。实现此目标的最佳方法是什么? 最佳答案 Rails4有一个内置的enummacro.它使用单个整数列并映射到键列表。classOrderenumstatus:[:ordered,:shipped,:delivered]end状态映射如下:{ordered:0,
我正在尝试将一个资源属性的默认值设置为另一个属性的值。我正在为我正在构建的tomcat说明书定义一个资源,其中包含以下定义。我想要可以独立设置的“名称”和“服务名称”属性。当未设置服务名称时,我希望它默认为为“名称”提供的任何内容。以下不符合我的预期:attribute:name,:kind_of=>String,:required=>true,:name_attribute=>trueattribute:service_name,:kind_of=>String,:default=>:name注意第二行末尾的“:default=>:name”。当我在Recipe的新block中引用我