PHP setcookie“SameSite = Strict”?

Posted

技术标签:

【中文标题】PHP setcookie“SameSite = Strict”?【英文标题】:PHP setcookie "SameSite=Strict"? 【发布时间】:2017-02-06 15:13:48 【问题描述】:

我最近阅读了关于“Same Site”属性的“RFC 6265”,我看了一些文章,在 2016 年 4 月谈到,Chrome 51 和 Opera 39 已经实现了“same-site”属性......

不知道现在的php是否支持用这个属性创建cookie?

参考:

Feature documentation on Chrome’s chromestatus.com HTTPbis draft first adopted by Chrome Latest HTTPbis draft

【问题讨论】:

即使 setcookie 函数没有,您也可以始终只输出您自己的自定义 header('Set-Cookie: ...') @MarcB:没错,别忘了对名称和值进行 URL 编码。 here 是一个公开请求,您可以投票和关注。 这个库可以让你使用 cookie 的属性:github.com/delight-im/PHP-Cookie 最重要的是,它还支持 PHP 的内置会话的这个属性,它会自动设置和使用 cookie。或者,等待 PHP 本地发布该功能。 @caw 使用这个库生成 cookie 并将其写入写入客户端的输出缓冲区,然后类才会获取 cookie 并覆盖它,不管这个过程有多快,它确实不保证不能拦截。对于一个处理类似问题的问题...github.com/delight-im/PHP-Cookie/issues/15 虽然这个问题质疑一个草案到 php 会话指向相同的范例。 【参考方案1】:

1。对于 PHP >= v7.3

您可以使用$options数组来设置samesite的值,例如:

setcookie($name, $value, [
    'expires' => time() + 86400,
    'path' => '/',
    'domain' => 'domain.com',
    'secure' => true,
    'httponly' => true,
    'samesite' => 'None',
]);

samesite 元素的值应该是NoneLaxStrict

在manual page 中了解更多信息。

2。对于 PHP

您可以根据您的代码库/需求使用以下解决方案/解决方法之一

2.1 使用 Apache 配置设置 SameSite cookie

您可以将以下行添加到您的 Apache 配置中

Header always edit Set-Cookie (.*) "$1; SameSite=Lax"

这将使用SameSite=Lax 标志更新您的所有cookie

在此处查看更多信息:https://blog.giantgeek.com/?p=1872

2.2 使用 nginx 配置设置 SameSite cookie

location / 
    # your usual config ...
    # hack, set all cookies to secure, httponly and samesite (strict or lax)
    proxy_cookie_path / "/; secure; HttpOnly; SameSite=strict";

这里也一样,这也会用SameSite=Lax 标志更新你的所有cookie

在此处查看更多信息:https://serverfault.com/questions/849888/add-samesite-to-cookies-using-nginx-as-reverse-proxy

2.3 使用header方法设置SameSite cookie

众所周知,cookie 只是 HTTP 请求中的一个标头,具有以下结构

Set-Cookie: key=value; path=/; domain=example.org; HttpOnly; SameSite=Lax

所以我们可以使用 header 方法设置 cookie

header("Set-Cookie: key=value; path=/; domain=example.org; HttpOnly; SameSite=Lax");

事实上,Symfony 并没有等待 PHP 7.3,而是已经在后台做了,see here

?你也可以在 Laravel 中使用它,因为 Laravel 在底层使用 Symfony 的 Symfony\Component\HttpFoundation\Cookie

2.4 使用 setcookie 方法中的错误设置 SameSite cookie

setcookie('cookie-name', '1', 0, '/; samesite=strict');

小心这个,这是 PHP setcookie 方法中的一个已知错误,已经在 PHP7.3 版本中解决,请参见此处 - https://github.com/php/php-src/commit/5cb825df7251aeb28b297f071c35b227a3949f01

【讨论】:

看起来这不是 PHP 7.3+ 中setcookie(和setrawcookie)的正确方法签名,一组选项作为第三个参数传递,其中一个被调用samesite。见github.com/php/php-src/blob/PHP-7.3/UPGRADING#L350 PHP 手册指出 samesite 作为数组的一部分在 setcookie 第三个参数中传递,如下所示:php.net/manual/en/function.setcookie.php @Jarom 实际上,答复者发布的关于setcookie 的 RFC 链接在底部 勘误表 下说:“实际实现的函数替代签名已从原始 RFC。有关详细信息,请参阅 PHP 手册中的文档。查看手册没有提到相同的论点。相反,手册仅将其作为 $options 数组的值提及。有人可以确认 samesite 论点是否真的有效吗? PHP session_set_cookie_params() 是否也允许将相同站点注入 $path? @marcovtwout 是的,session_set_cookie_params() 中的注入在 PHP 7.2.24 中也以同样的方式为我工作,我在 PHP 更改日志中没有找到解决此问题的方法,这对我:)【参考方案2】:

[重要更新:正如@caw 在下面指出的,这个黑客WILL BREAK in PHP 7.3。现在停止使用它来避免令人不快的惊喜!或者至少将其包装在 PHP 版本检查中,例如 if (PHP_VERSION_ID < 70300) ... else ... 。]

您似乎可以滥用 PHP 的“setcookie”函数的“路径”或“域”参数来潜入 SameSite 属性,因为 PHP 不会转义分号:

setcookie('samesite-test', '1', 0, '/; samesite=strict');

然后 PHP 发送以下 HTTP 标头:

设置 Cookie:samesite-test=1;路径=/;同站点=严格

我在几分钟前才发现这一点,所以请自己进行测试!我正在使用 PHP 7.1.11。

【讨论】:

我发现这个答案很有趣,我承认我从未尝试过这个,因为规范没有说明(据我所知)这种可能性......我将对此进行测试以查看它的行为 我已经在phptester 在 PHP 7.0 上进行了测试,这个测试是成功的...非常感谢您的回复! 在 Chrome 63(桌面)62 (android)、原生 Android (v62) 和 Opera (48) 上工作... Firefox (57) 不支持,但下一个版本 (58) 承诺支持。跨度> 优秀的 hack - 只要它不破坏,希望它不会破坏。但是您必须关注未来的 PHP 版本,以了解对此函数的更改。在最好的情况下,这一直有效,直到 PHP 发布了直接支持该功能的更新的 setcookie 方法,这可能是 PHP 7.3,可以在另一个答案中阅读。 看起来这可能很快就会停止工作(可能在 PHP 7.3 中):github.com/php/php-src/commit/…【参考方案3】:

基于Steffen's answer above,这是我用来支持 php = 7.3 的方法:

/**
 * Support samesite cookie flag in both php 7.2 (current production) and php >= 7.3 (when we get there)
 * From: https://github.com/GoogleChromeLabs/samesite-examples/blob/master/php.md and https://***.com/a/46971326/2308553 
 *
 * @see https://www.php.net/manual/en/function.setcookie.php
 *
 * @param string $name
 * @param string $value
 * @param int $expire
 * @param string $path
 * @param string $domain
 * @param bool $secure
 * @param bool $httponly
 * @param string $samesite
 * @return void
 */
function setCookieSameSite(
    string $name, string $value,
    int $expire, string $path, string $domain,
    bool $secure, bool $httponly, string $samesite = 'None'
): void 
    if (PHP_VERSION_ID < 70300) 
        setcookie($name, $value, $expire, $path . '; samesite=' . $samesite, $domain, $secure, $httponly);
        return;
    
    setcookie($name, $value, [
        'expires' => $expire,
        'path' => $path,
        'domain' => $domain,
        'samesite' => $samesite,
        'secure' => $secure,
        'httponly' => $httponly,
    ]);

【讨论】:

感谢您的回答,您能否指出在 Drupal 7 (PHP 7.2.2) 中实现此功能的位置。 替代语法:if (version_compare(phpversion(), '7.3', '&lt;')) ... .【参考方案4】:

我写了一个类来设置samesite cookie。

https://github.com/ovunctukenmez/SameSiteCookieSetter

它适用于所有 PHP 版本。 它还会检查浏览器是否正确支持 samesite 参数。

这里是用法:

//set samesite strict php cookie
SameSiteCookieSetter::setcookie('samesite_test','testvalue', array('samesite' => 'Strict'));

【讨论】:

我测试了你的代码。对于 PHP 我正在使用你的课程 SameSiteCookieSetter 老版本php有bug,去掉boolval函数才能正常工作【参考方案5】:

根据this site,似乎是PHP 7.3 的问题。从投票结果来看,cookie 相关功能的更通用扩展正在实施中 + php.ini 文件中可能还会有一个新键。

但是正如 Marc B 已经写的那样,您可以使用 header() 函数调用来代替,我会在一些用于包含其他初始内容的文件中执行此操作。

【讨论】:

【参考方案6】:

添加 Marty Aghajanyan 的答案(因为显然我可以回答,但尚未发表评论)

在 Apache 2.4.29 (Ubuntu) 中,通过 mod_headers 和 PHP 在 Apache 中执行此操作对我不起作用。在查看文档 (http://www.balkangreenfoundation.org/manual/en/mod/mod_headers.html) 时,我注意到“始终”条件在某些情况下无法从同一个响应标头池中工作。因此,以下内容对我有用,可以设置 SameSite 参数。 (就我而言,我为最近的 Chrome 80 更新设置了 None)

Header edit Set-Cookie ^(.*)$ "$1; Secure; SameSite=None"

文档还建议,如果您想涵盖所有基础,您可以添加带有和不带有“always”的指令,但我没有测试过。

【讨论】:

【参考方案7】:

值得一提的是,macOS 和 ios 上的 Safari 12 将无法识别 SameSite 属性的 None 值,默认值为 Strict。

版本 13 将接受“None”,但没有明确设置值,它默认为“Lax”。

这里有一个很好的解释:

https://www.thinktecture.com/en/identity/samesite/samesite-in-a-nutshell/

【讨论】:

【参考方案8】:

这也可能对仍在苦苦挣扎、使用 PHP >= 7.3.x 和使用 CI 3.1.11 的人有所帮助

在根目录下找到的index.php中,在下面添加一行

if(isset($_COOKIE["PHPSESSID"]))
    header('Set-Cookie: PHPSESSID='.$_COOKIE["PHPSESSID"].'; SameSite=None');

它对我有用,在尝试了所有之后(徒劳)

【讨论】:

也为我工作。只需在开始会话时放置它即可。【参考方案9】:

有很多例子展示了如何设置这个属性,但没有太多解释为什么。

https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies#SameSite_attribute

如果需要跨域发送 cookie,请使用 None 指令选择退出 SameSite 限制。 None 指令要求也使用 Secure 属性。

SameSite 设置为NoneLax 的示例仅适用于跨域场景。如果您的代码不是跨域的,请使用Strict

【讨论】:

以上是关于PHP setcookie“SameSite = Strict”?的主要内容,如果未能解决你的问题,请参考以下文章

PHP:setcookie() 和 unset() 不删除 cookie

unset($_COOKIE['name']) 与 PHP$_ 中的 setcookie

PHP 中内置函数 setcookie() 和 setrawcookie() 的实际实际差异是啥?

php setcookie 没有设置 cookie [重复]

php setcookie 显式到本地主机

php setcookie中path和domain怎么设置