diff --git a/config-templates/config.php b/config-templates/config.php index b573f432d8ce2bea2a3961d5ed173342b91caac6..50e03fdcc02401a32c49e0be25d52ce0190e10d2 100644 --- a/config-templates/config.php +++ b/config-templates/config.php @@ -564,7 +564,7 @@ $config = [ * Example: * 'session.cookie.samesite' => 'None', */ - 'session.cookie.samesite' => null, + 'session.cookie.samesite' => \SimpleSAML\Utils\HTTP::canSetSameSiteNone() ? 'None' : null, /* * Options to override the default settings for php sessions. @@ -792,7 +792,7 @@ $config = [ 'language.cookie.secure' => false, 'language.cookie.httponly' => false, 'language.cookie.lifetime' => (60 * 60 * 24 * 900), - 'language.cookie.samesite' => null, + 'language.cookie.samesite' => \SimpleSAML\Utils\HTTP::canSetSameSiteNone() ? 'None' : null, /** * Custom getLanguage function called from SimpleSAML\Locale\Language::getLanguage(). diff --git a/lib/SimpleSAML/Utils/HTTP.php b/lib/SimpleSAML/Utils/HTTP.php index 23c7bdf84d0f627e24c1d0abd8a7977b3beb63fa..d74031ef02e56d166cc2dc26c38c1b651752b886 100644 --- a/lib/SimpleSAML/Utils/HTTP.php +++ b/lib/SimpleSAML/Utils/HTTP.php @@ -18,6 +18,51 @@ use SimpleSAML\XHTML\Template; */ class HTTP { + /** + * Determine if the user agent can support cookies being sent with SameSite equal to "None". + * Browsers with out support may drop the cookie and or treat is a stricter setting + * Browsers with support may have additional requirements on setting it on non-secure websites. + * + * Based on the Azure teams experience rolling out support and Chromium's advice + * https://devblogs.microsoft.com/aspnet/upcoming-samesite-cookie-changes-in-asp-net-and-asp-net-core/ + * https://www.chromium.org/updates/same-site/incompatible-clients + * @return bool true if user agent supports a None value for SameSite. + */ + public static function canSetSameSiteNone(): bool + { + $useragent = $_SERVER['HTTP_USER_AGENT'] ?? null; + if (!$useragent) { + return true; + } + // All iOS 12 based browsers have no support + if (strpos($useragent, "CPU iPhone OS 12") !== false || strpos($useragent, "iPad; CPU OS 12") !== false) { + return false; + } + + // Safari Mac OS X 10.14 has no support + // - Safari on Mac OS X. + if (strpos($useragent, "Macintosh; Intel Mac OS X 10_14") !== false) { + // regular safari + if (strpos($useragent, "Version/") !== false && strpos($useragent, "Safari") !== false) { + return false; + } elseif (preg_match('|AppleWebKit/[\.\d]+ \(KHTML, like Gecko\)$|', $useragent)) { + return false; + } + } + + // Chrome based UCBrowser may have support (>= 12.13.2) even though its chrome version is old + $matches = []; + if (preg_match('|UCBrowser/(\d+\.\d+\.\d+)[\.\d]*|', $useragent, $matches)) { + return version_compare($matches[1], '12.13.2', '>='); + } + + // Chrome 50-69 may have broken SameSite=None and don't require it to be set + if (strpos($useragent, "Chrome/5") !== false || strpos($useragent, "Chrome/6") !== false) { + return false; + } + return true; + } + /** * Obtain a URL where we can redirect to securely post a form with the given data to a specific destination. * diff --git a/tests/lib/SimpleSAML/Utils/HTTPTest.php b/tests/lib/SimpleSAML/Utils/HTTPTest.php index e60dae5c8d9df57cb059166b946fbde836ed9d24..f6f90fd64b31ee8e3d158540ac4d2c4ecc82db65 100644 --- a/tests/lib/SimpleSAML/Utils/HTTPTest.php +++ b/tests/lib/SimpleSAML/Utils/HTTPTest.php @@ -526,4 +526,57 @@ class HTTPTest extends ClearStateTestCase $this->assertMatchesRegularExpression('/\b[Ss]ame[Ss]ite=Lax(;|$)/', $headers[2]); $this->assertMatchesRegularExpression('/\b[Ss]ame[Ss]ite=Strict(;|$)/', $headers[3]); } + + /** + * Test detecting if user agent supports None + * @dataProvider detectSameSiteProvider + * @param null|string $userAgent The user agent. Null means not set, like with CLI + * @param bool $supportsNone None can be set as a SameSite flag + */ + public function testDetectSameSiteNoneBehavior(?string $userAgent, bool $supportsNone): void + { + if ($userAgent) { + $_SERVER['HTTP_USER_AGENT'] = $userAgent; + } + $this->assertEquals($supportsNone, HTTP::canSetSameSiteNone(), $userAgent ?? 'No user agent set'); + } + + public function detectSameSiteProvider(): array + { + // @codingStandardsIgnoreStart + return [ + [null, true], + ['some-new-browser', true], + //Browsers that can handle 'None' + // Chrome + ['Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.70 Safari/537.36', true], + // Chome on windows + ['Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36', true], + // Chrome linux + ['Mozilla/5.0 (X11; HasCodingOs 1.0; Linux x64) AppleWebKit/637.36 (KHTML, like Gecko) Chrome/70.0.3112.101 Safari/637.36 HasBrowser/5.0', true], + // Safari iOS 13 + ['Mozilla/5.0 (iPhone; CPU iPhone OS 13_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/11.2 Mobile/15E148 Safari/604.1', true], + // Mac OS X with support + ['Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.1 Safari/605.1.15', true], + // UC Browser with support + ['Mozilla/5.0 (Linux; U; Android 9; en-US; SM-A705FN Build/PPR1.180610.011) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 UCBrowser/12.13.2.1208 Mobile Safari/537.36', true], + ['Mozilla/5.0 (Linux; U; Android 10; en-US; RMX2020 Build/QP1A.190711.020) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 UCBrowser/12.13.5.1209 Mobile Safari/537.36', true], + // Embedded Mac with support + ['Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/605.1.15 (KHTML, like Gecko)', true], + // Browser without support + // Old Safari on mac + ['Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.1.1 Safari/605.1.15', false], + // Old Safari on iOS 12 (phone and ipad + ['Mozilla/5.0 (iPhone; CPU iPhone OS 12_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.1 Mobile/15E148 Safari/604.1', false], + ['Mozilla/5.0 (iPad; CPU OS 12_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.0 Mobile/16A5288q Safari/605.1.15', false], + // Chromium without support + ['Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/65.0.3325.181 Chrome/65.0.3325.181 Safari/537.36', false], + // UC Browser without support + ['Mozilla/5.0 (Linux; U; Android 8.1.0; zh-CN; EML-AL00 Build/HUAWEIEML-AL00) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 baidu.sogo.uc.UCBrowser/11.9.4.974 UWS/2.13.1.48 Mobile Safari/537.36 AliApp(DingTalk/4.5.11) com.alibaba.android.rimet/10487439 Channel/227200 language/zh-CN', false], + ['Mozilla/5.0 (Linux; U; Android 7.1.1; en-US; CPH1723 Build/N6F26Q) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 UCBrowser/12.13.0.1207 Mobile Safari/537.36', false], + // old embedded browser + ['Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/605.1.15 (KHTML, like Gecko)', false] + ]; + // @codingStandardsIgnoreEnd + } }