Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unset Cookies older than a specific date, for www. and non www domain

Tags:

php

cookies

I want to unset all cookies on my domain so that a "fresh start" can be forced for all users...

The following bit of code kind of works, but it doesn't unset cookies from the domain with via www.

<?
// Check if this script has run before
if (!isset($_COOKIE['purged_once'])) {

  // Check for old cookies
  if (isset($_SERVER['HTTP_COOKIE'])) {

    $cookies = explode(";", $_SERVER['HTTP_COOKIE']);

    // Iterate and unset all cookies
    foreach ($cookies as $cookie) {

      $fields = explode("=", $cookie);
      $name = trim(fields[0]);

      // unset any cookie for the current path
      setcookie($name, "", time() - 3600);

      // unset the cookie for the root path
      setcookie($name, "", time() - 3600, "/");
    }
  }

  // Set a purged marker for the current path
  setcookie("purged_once", "1", strtotime("+6 months"));
}
?>

The website is forced to use non-www and https via .htaccess rules:

<IfModule mod_rewrite.c>
    # Force HTTPS & NON-WWW
    RewriteEngine On
    RewriteCond %{HTTPS} !=on  [OR]
    RewriteCond %{HTTP_HOST} !^website\.com$ [NC]
    RewriteRule ^ https://website.com%{REQUEST_URI} [R=301,L]
</IfModule>

So what I am looking for is a way to run this over the https://www.website.com to forcefully remove all cookies for that subdomain

How can this be achieved?

like image 407
Ryflex Avatar asked Dec 24 '22 11:12

Ryflex


2 Answers

The setcookie function also accepts domain name as a parameter. When you have set no domain name, you create cookie only for current domain. When you have set a domain name, you create cookie for domain and all its sub-domains. For example, setcookie('cookie_name', 'cookie_value', 3600, '/', 'website.com') creates cookies for example.com and all sub-domains, e.g. www.example.com, sub.example.com, etc. Some older browsers require a dot before domain name to indicate that you want to set cookie for sub-domain:

setcookie('cookie_name', 'cookie_value', 3600, '/', '.website.com');

So, if you want to have some guarantee while unsetting cookies, you can use both approaches:

  // unset any cookie for the current path
  setcookie($name, "", time() - 3600, '', 'website.com');
  setcookie($name, "", time() - 3600, '', '.website.com');

  // unset the cookie for the root path
  setcookie($name, "", time() - 3600, "/", 'website.com');
  setcookie($name, "", time() - 3600, "/", '.website.com');

Description for domain parameter of setcookie function:

setcookie ($name, $value, $expire, $path, $domain, $secure, $httponly)

$domain

The (sub)domain that the cookie is available to. Setting this to a subdomain (such as 'www.example.com') will make the cookie available to that subdomain and all other sub-domains of it (i.e. w2.www.example.com). To make the cookie available to the whole domain (including all subdomains of it), simply set the value to the domain name ('example.com', in this case).

Older browsers still implementing the deprecated "RFC 2109" may require a leading . to match all subdomains.

like image 134
Ronin Avatar answered Dec 28 '22 09:12

Ronin


Seems that browsers share cookies over subdomains (and http and https). So possibly the solution is to just unset them with having the domain parameter set to www.website.com, as cookies can only be overwritten with exactly the same set of parameters.

If that does not solve the problem:

  • If the possible cookie names are known and a limited set, you can include rewrite rules in the .htaccess before the redirect to unset them, as described in here
  • To find out which cookies exist on the subdomain, add the content of %{HTTP_COOKIE} to your query string and parse it in your script and run your code over that as above. Set the domain parameter of setcookie().

The RewriteRule would therefore be changed to

RewriteRule ^ https://website.com%{REQUEST_URI}&www_cookies=%{HTTP_COOKIE} [R=301,L]

and the cookies will be accessible via $_REQUEST['www_cookies'] as a string, which still has to be broken apart, for example using parse_str().

like image 35
syck Avatar answered Dec 28 '22 10:12

syck