4
votes

I have inherited an Opencart 2.0.1.1 website using SagePay Direct for payments.

With the changes to samesite cookies in Chrome 80 transcations have been failing to call back correctly - transaction is not found. The payment goes through but it seems the session/transcation reference is lost so the order status does not get updated. I think this is because of the changes to how cookies are handled and the redirection to the 3D secure screen breaking this.

I have updated the session cookie to be samesite=None and set it to secure but this didn’t correct the problem. Currently payments work in other browsers and, when run using a local development copy of the website and SagePay’s test service Chrome will work too.

Has anyone else run into this problem and know of a fix?

I don’t think updating OpenCart is a viable option as some core files have been tweaked by previous developers but I don’t know which.

1
Have you got any solution for this?Harikrishnan
I am having a similar problem. Some user's old cookies may still be experiencing problems because they are not updated. Are you sure the cookies on the browsers that are experiencing the problem are SameSite = None?Okan

1 Answers

0
votes

The Solution:

First, make sure that the php version you are using is 7.3 or higher. For this solution, at least 7.3 version is required, but if you are using a lower version, you can change the codes by looking at the sources I provided, I didn’t add it because I couldn’t test it. Again, I should mention that I tried this solution on Opencart 2.3 version and it works without any problems. I will give details below, but generally I have solved it by adding ‘samesite’ => ‘None’ and secure parameters before session_start() and setcookie() commands.

1. system/library/session.php

Find:

session_set_cookie_params(0, '/');
session_start();

Replace:

if (PHP_VERSION_ID < 70300) {
    session_set_cookie_params(0, '/; samesite=None', '.yoursite.com', true, true);
} else {
    ini_set('session.cookie_samesite', 'None');
    session_set_cookie_params([
        'lifetime' => 0,
        'path' => '/',
        'domain' => '.yoursite.com',
        'secure' => true,
        'httponly' => true,
        'samesite' => 'None'
    ]);
}
session_start();

Find:

if ($key != 'PHPSESSID') {
    setcookie($key, $this->session_id, ini_get('session.cookie_lifetime'), ini_get('session.cookie_path'), ini_get('session.cookie_domain'), ini_get('session.cookie_secure'), ini_get('session.cookie_httponly'));
}

Replace:

if (PHP_VERSION_ID < 70300) {
    setcookie($key, $this->session_id, ini_get('session.cookie_lifetime'), ini_get('session.cookie_path'), ini_get('session.cookie_domain'), ini_get('session.cookie_secure'), ini_get('session.cookie_httponly'));
} else {
    $samsite_cookie_options = array (
        'expires' => ini_get('session.cookie_lifetime'),
        'path' => ini_get('session.cookie_path'),
        'domain' => ini_get('session.cookie_domain'),
        'secure' => true, // or false
        'httponly' => true, // or false
        'samesite' => 'None' // None || Lax || Strict
    );
    setcookie($key, $this->session_id, $samsite_cookie_options);
}

Find:

setcookie($key, '', time() - 42000, ini_get('session.cookie_path'), ini_get('session.cookie_domain'));

Replace:

if (PHP_VERSION_ID < 70300) {
    setcookie($key, '', time() - 42000, ini_get('session.cookie_path'), ini_get('session.cookie_domain'));
} else {
    $samsite_cookie_options = array (
        'expires' => time() - 42000,
        'path' => ini_get('session.cookie_path'),
        'domain' => ini_get('session.cookie_domain'),
        'secure' => true, // or false
        'httponly' => true, // or false
        'samesite' => 'None' // None || Lax || Strict
    );
    setcookie($key, '', $samsite_cookie_options);
}

2. catalog/controller/startup/startup.php

Find:

setcookie('language', $code, time() + 60 * 60 * 24 * 30, '/', $this->request->server['HTTP_HOST']);

Replace:

if (PHP_VERSION_ID < 70300) {
    setcookie('language', $code, time() + 60 * 60 * 24 * 30, '/', $this->request->server['HTTP_HOST']);
} else {
    $samsite_cookie_options = array (
        'expires' => time() + 60 * 60 * 24 * 30,
        'path' => '/',
        'domain' => $this->request->server['HTTP_HOST'],
        'secure' => true, // or false
        'httponly' => true, // or false
        'samesite' => 'None' // None || Lax || Strict
    );
    setcookie('language', $code, $samsite_cookie_options);
}

Find:

setcookie('tracking', $this->request->get['tracking'], time() + 3600 * 24 * 1000, '/');

Replace:

if (PHP_VERSION_ID < 70300) {
    setcookie('tracking', $this->request->get['tracking'], time() + 3600 * 24 * 1000, '/');
} else {
    $samsite_cookie_options = array (
        'expires' => time() + 3600 * 24 * 1000,
        'path' => '/',
        'domain' => $this->request->server['HTTP_HOST'],
        'secure' => true, // or false
        'httponly' => true, // or false
        'samesite' => 'None' // None || Lax || Strict
    );
    setcookie('tracking', $this->request->get['tracking'], $samsite_cookie_options);
}

Find:

setcookie('currency', $code, time() + 60 * 60 * 24 * 30, '/', $this->request->server['HTTP_HOST']);

Replace:

if (PHP_VERSION_ID < 70300) {
    setcookie('currency', $code, time() + 60 * 60 * 24 * 30, '/', $this->request->server['HTTP_HOST']);
} else {
    $samsite_cookie_options = array (
        'expires' => time() + 60 * 60 * 24 * 30,
        'path' => '/',
        'domain' => $this->request->server['HTTP_HOST'],
        'secure' => true, // or false
        'httponly' => true, // or false
        'samesite' => 'None' // None || Lax || Strict
    );
    setcookie('currency', $code, $samsite_cookie_options);
}

3. Search all your files and change the session_start() and setcookie() commands as above. Actually, the changes on the first two files are sufficient, but I still recommend scanning your other files to avoid any surprises.