SameSiteCookieMiddleware.php 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. <?php
  2. /**
  3. * @copyright 2017, Roeland Jago Douma <roeland@famdouma.nl>
  4. *
  5. * @author Christoph Wurst <christoph@winzerhof-wurst.at>
  6. * @author Roeland Jago Douma <roeland@famdouma.nl>
  7. *
  8. * @license GNU AGPL version 3 or any later version
  9. *
  10. * This program is free software: you can redistribute it and/or modify
  11. * it under the terms of the GNU Affero General Public License as
  12. * published by the Free Software Foundation, either version 3 of the
  13. * License, or (at your option) any later version.
  14. *
  15. * This program is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. * GNU Affero General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU Affero General Public License
  21. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  22. *
  23. */
  24. namespace OC\AppFramework\Middleware\Security;
  25. use OC\AppFramework\Http\Request;
  26. use OC\AppFramework\Middleware\Security\Exceptions\LaxSameSiteCookieFailedException;
  27. use OC\AppFramework\Utility\ControllerMethodReflector;
  28. use OCP\AppFramework\Http;
  29. use OCP\AppFramework\Http\Response;
  30. use OCP\AppFramework\Middleware;
  31. class SameSiteCookieMiddleware extends Middleware {
  32. /** @var Request */
  33. private $request;
  34. /** @var ControllerMethodReflector */
  35. private $reflector;
  36. public function __construct(Request $request,
  37. ControllerMethodReflector $reflector) {
  38. $this->request = $request;
  39. $this->reflector = $reflector;
  40. }
  41. public function beforeController($controller, $methodName) {
  42. $requestUri = $this->request->getScriptName();
  43. $processingScript = explode('/', $requestUri);
  44. $processingScript = $processingScript[count($processingScript) - 1];
  45. if ($processingScript !== 'index.php') {
  46. return;
  47. }
  48. $noSSC = $this->reflector->hasAnnotation('NoSameSiteCookieRequired');
  49. if ($noSSC) {
  50. return;
  51. }
  52. if (!$this->request->passesLaxCookieCheck()) {
  53. throw new LaxSameSiteCookieFailedException();
  54. }
  55. }
  56. public function afterException($controller, $methodName, \Exception $exception) {
  57. if ($exception instanceof LaxSameSiteCookieFailedException) {
  58. $respone = new Response();
  59. $respone->setStatus(Http::STATUS_FOUND);
  60. $respone->addHeader('Location', $this->request->getRequestUri());
  61. $this->setSameSiteCookie();
  62. return $respone;
  63. }
  64. throw $exception;
  65. }
  66. protected function setSameSiteCookie() {
  67. $cookieParams = $this->request->getCookieParams();
  68. $secureCookie = ($cookieParams['secure'] === true) ? 'secure; ' : '';
  69. $policies = [
  70. 'lax',
  71. 'strict',
  72. ];
  73. // Append __Host to the cookie if it meets the requirements
  74. $cookiePrefix = '';
  75. if ($cookieParams['secure'] === true && $cookieParams['path'] === '/') {
  76. $cookiePrefix = '__Host-';
  77. }
  78. foreach ($policies as $policy) {
  79. header(
  80. sprintf(
  81. 'Set-Cookie: %snc_sameSiteCookie%s=true; path=%s; httponly;' . $secureCookie . 'expires=Fri, 31-Dec-2100 23:59:59 GMT; SameSite=%s',
  82. $cookiePrefix,
  83. $policy,
  84. $cookieParams['path'],
  85. $policy
  86. ),
  87. false
  88. );
  89. }
  90. }
  91. }