Skip to content

Reject the request before hashing a token that does not exist yet - #250

Draft
boo-code wants to merge 1 commit into
PrestaShop:devfrom
boo-code:fix/no-token-hash-before-the-login-check
Draft

boo-code wants to merge 1 commit into
PrestaShop:devfrom
boo-code:fix/no-token-hash-before-the-login-check

Conversation

@boo-code

Copy link
Copy Markdown
Questions Answers
Description? ExportCustomerData::customerIsAuthenticated() hashed the customer's secure key before checking whether the customer is logged in at all. A guest has no secure key, so every guest request to that controller went through sha1(null) - deprecated since PHP 8.1 - before being rejected by the check that follows. The login check now comes first, so the hash is only computed for a request that can actually be authenticated.
Type? bug fix
BC breaks? no
Deprecations? no
Fixed ticket? Fixes #236, Fixes #239
Sponsor company
How to test? With PHP 8.1 or later and deprecations logged, request the module's ExportCustomerData front controller without being logged in. Before: sha1(): Passing null to parameter #1 ($string) of type string is deprecated. After: no entry, and the request is still rejected. A logged-in customer with the correct token still exports, and with a wrong token is still refused.

What was already fixed, and what was not

The line both issues quote - psgdpr.php:701 - is v1.4.3's
sha1(Context::getContext()->customer->secure_key). On dev that block initialises $secureKey = ''
and only fills it for a logged-in customer, so it can no longer receive null. That was commit
5a0915f "Fix sha1 deprecation", 2023-09-26.

Two things follow from that, and they are worth stating on the issues rather than closing them:

  • master carries module 2.0.2 and still has the unguarded call at line 764.
  • The copy that ships with PrestaShop 9 is 1.4.3, which is what both reporters run, so the
    deprecation is live for them whatever dev says.

This PR is about the instance the 2023 fix did not cover.

The remaining instance

$customer = Context::getContext()->customer;
$secure_key = sha1($customer->secure_key);
$token = Tools::getValue('token');

if ($customer->isLogged() === false || !isset($token) || $token != $secure_key) {

The hash is computed before the isLogged() check that rejects the visitor. Reordering removes the
deprecation and also avoids hashing for a request that cannot be authenticated.

The comparison moves to hash_equals at the same time, so the check does not leak the token through
its timing. FrontAjaxGdpr already compares the same token with ===; this brings the two into
line rather than introducing a new convention.

FrontAjaxGdpr.php needs no change - its sha1($customer->secure_key) is already inside an
isLogged() === true branch - and controllers/front/gdpr.php redirects an empty customer id before
reaching its own call. So this is the whole class, not one of several.

Verification

Measured on PHP 8.1.33.

  • sha1(null) raises exactly the reported deprecation; sha1((string) null) does not.
  • A non-logged Customer has secure_key === null and isLogged() === false, so the guest path is
    the one that reaches it.
  • Old and new method bodies run over the same three cases - guest with no token, logged in with the
    correct token, logged in with a wrong token. Old: 1 deprecation. New: 0. Results identical
    in all three cases, so the authentication outcome is unchanged.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant