\n
As @shrimpwagon said in a comment below, session.cookie_secure
must be true
for this to work. PHP doesn't require it, but browsers do.
Reputation: 1759
According to the article here https://php.watch/articles/PHP-Samesite-cookies and PHP documenation at https://www.php.net/manual/en/session.security.ini.php, There are only 2 possible config options for this new feature, added in PHP 7.3:
Yet, according to the Chrome console, this needs to be set to "None":
A cookie associated with a cross-site resource at URL was set without the
SameSite
attribute. It has been blocked, as Chrome now only delivers cookies with cross-site requests if they are set withSameSite=None
andSecure
. You can review cookies in developer tools under Application>Storage>Cookies and see more details at URL and URL.
Because of this, I can no longer set cross-site cookies. What is the workaround?
Upvotes: 29
Views: 57976
Reputation: 6152
Mission: let JS Ajax request be done from another domain (e,g: localhost)
steps:
A. add withCredentials
to your ajax request
B. set Access-Control-Allow-Credentials: true
among the rest of the Access-Control-Allow-...
headers
C. add "samesite" => "none"
to your session cookie params.
finally my code look like this:
Server:
$currentCookieParams = session_get_cookie_params();
session_set_cookie_params([
"lifetime" => $currentCookieParams["lifetime"],
"path" => $currentCookieParams["path"],
"domain" => $_SERVER["HTTP_HOST"],
"secure" => true,
"samesite" => "none",
"httponly" => $currentCookieParams["httponly"]
]);
header("Access-Control-Allow-Origin: " . $_SERVER["HTTP_ORIGIN"]);
header("Access-Control-Allow-Headers: " . $_SERVER["HTTP_ACCESS_CONTROL_REQUEST_HEADERS"]);
header("Access-Control-Allow-Methods: " . $_SERVER["HTTP_ACCESS_CONTROL_REQUEST_METHOD"]);
header('Access-Control-Max-Age: 1000');
header('Access-Control-Allow-Credentials: true');
js - client:
fetch(`https://example.com/login.php`, {
method: 'POST',
withCredentials: true,
body: `username=${user}&password=${pass}`
}).then(res => {
if (res.status === 200) {
//here session cookie exists and sent to server, so i can access the data
fetch(`https://example.com/secret.php`, {
method: 'GET',
withCredentials: true,
}).then(res => {
if (res.status === 200) {
console.log(res.body);
} else {
console.error("error")
}
}).catch(err => {
console.log(err)
})
} else {
console.error("error")
}
}).catch(err => {
console.log(err)
})
tested with FF 112 and Chromium 113 on ubuntu
Upvotes: 0
Reputation: 101
ini_set('session.cookie_secure', "1"); ini_set('session.cookie_httponly', "1"); ini_set('session.cookie_samesite','None'); session_start();
php 7.4 samesite in phpinfo
php 7.2 samesite does not exist in phpinfo
$currentCookieParams = session_get_cookie_params();
$cookie_domain= 'your domain';
if (PHP_VERSION_ID >= 70300) {
session_set_cookie_params([
'lifetime' => $currentCookieParams["lifetime"],
'path' => '/',
'domain' => $cookie_domain,
'secure' => "1",
'httponly' => "1",
'samesite' => 'None',
]);
} else {
session_set_cookie_params(
$currentCookieParams["lifetime"],
'/; samesite=None',
$cookie_domain,
"1",
"1"
);
}
session_start();
Upvotes: 10
Reputation: 1
If you use nginx, you can also modify the cookie using lua. It is a bit hacky, but I found it to be working well for legacy sites:
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php5.6-fpm.sock;
# This is the relevant part:
header_filter_by_lua '
local cookies = ngx.header.set_cookie
if cookies then
if type(cookies) ~= "table" then
cookies = {cookies}
end
local gsub = string.gsub
local changed
for i, cookie in ipairs(cookies) do
local new_cookie = gsub(cookie, "^PHPSESSION=(.*)", "PHPSESSION=%1; Samesite=strict", 1)
if new_cookie ~= cookie then
cookies[i] = new_cookie
changed = true
end
end
if changed then
ngx.header.set_cookie = cookies
end
end
';
# End Lua
}
You might need to adapt the regex (gsub), but I found it works well.
Upvotes: 0
Reputation: 715
For PHP 5.6.40, there exists a workaround (the hack on path parameter) which does not involve rebuilding PHP.
If you have no problem rebuilding the PHP binary, I managed to port this feature from PHP 7.3 to PHP 5.6.40, and there is now a pull request. I needed it for our projects that aren't migrated yet. I know 5.6 branch is deprecated, I am just sharing.
Pull request: https://github.com/php/php-src/pull/6446
Our repo with the changes: https://github.com/Inducido/php-src/tree/PHP-5.6.40
Build tested on Debian 8.11
Session: . Added support for the SameSite cookie directive for setcookie(), setrawcookie() and session_set_cookie_params(). Port from PHP 7.x branch they all have an "samesite" additionnal parameter at the very end (string)
prototypes:
bool setcookie(string name [, string value [, int expires [, string path [, string domain [, bool secure[, bool httponly[, string samesite]]]]]]])
bool setrawcookie(string name [, string value [, int expires [, string path [, string domain [, bool secure[, bool httponly[, string samesite]]]]]]])
void session_set_cookie_params(int lifetime [, string path [, string domain [, bool secure[, bool httponly[, string samesite]]]]])
(session_get_cookie_params updated too)
none
is interpreted
like false
in ini files.This solves the issue "This Set-Cookie was blocked due to user preferences" in Chrome.
Upvotes: 0
Reputation: 12027
You can set the value to "None" using ini_set
. There's no check that the value is supported when that function is used:
ini_set('session.cookie_samesite', 'None');
session_start();
session_set_cookie_params
can also set it:
session_set_cookie_params(['samesite' => 'None']);
session_start();
The bug report for this to be supported in php.ini is here.
As @shrimpwagon said in a comment below, session.cookie_secure
must be true
for this to work. PHP doesn't require it, but browsers do.
Upvotes: 45
Reputation: 834
Bad:
session.cookie_samesite=None
Correct:
session.cookie_samesite="None"
Explanation here
Upvotes: 5
Reputation: 1
This method can be helpful for u
Add header's attributes on nginx
below Secure
+ SameSite=None
location / {
proxy_cookie_path / "/; secure; SameSite=none";
}
It's working on me!
Upvotes: 0