logo

CVE-2021-43846 solidus_frontend

Package

Manager: gem
Name: solidus_frontend
Vulnerable Version: >=0 <2.11.14 || >=3.0.0 <3.0.5 || >=3.1.0 <3.1.5

Severity

Level: Medium

CVSS v3.1: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N

CVSS v4.0: CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:P/VC:N/VI:L/VA:N/SC:N/SI:N/SA:N

EPSS: 0.00127 pctl0.32903

Details

CSRF forgery protection bypass in solidus_frontend ### Impact CSRF vulnerability that allows a malicious site to add an item to the user's cart without their knowledge. All `solidus_frontend` versions are affected. If you're using your own storefront, please, follow along to make sure you're not affected. To reproduce the issue: - Pick the id for a variant with available stock. From the rails console: ```ruby Spree::Variant.in_stock.pluck(:id) ``` Say we pick variant id `2`. - Launch your application, for instance, on `http://localhost:3000`: ```bash bin/rails server ``` - Open your browser dev tools. - Click on whatever link in your store. - Copy the value of the `Cookie` request header sent for the previous request from your browser dev tools. - Execute the following, using your previously selected variant id and the value of the `Cookie` header (notice how it doesn't contain any authentication token): ```bash curl -X POST -d "variant_id=2&quantity=1" -H "Cookie: guest_token=eyJfcmFpbHMiOnsibWVzc2FnZSI6IklrWlRVMWRQWnpKMVZVdFNXRzlPVW1aaWJHTjZZa0VpIiwiZXhwIjpudWxsLCJwdXIiOiJjb29raWUuZ3Vlc3RfdG9rZW4ifX0%3D--5006ba5d346f621c760a29b6a797bf351d17d1b8; _sandbox_session=vhutu5%2FL9NmWrUpGc3DxrFA%2FFsQD1dHn1cNsD7nvE84zcjWf17Af4%2F%2F2Vab3md71b6KTb9NP6WktdXktpwH4eU01jEGIBXG5%2BMzW5nL0nb4W269qk1io4LYljvoOg8%2BZVll7oJCVkJLKKh0sSoS0Kg8j%2FCHHs%2BsShohP%2BGnA%2Bfr9Ub8H6HofpSmloSpsfHHygmX0ho03fEgzHJ4DD5wJctaNKwg7NhVikHh5kgIPPHl84OGCgv3p2oe9jR19HTxOKq7BtyvDd7XZsecWhkcfS8BPnvDDUWZG6qpAEFI5kWo81KkpSJ%2Bp6Q1HOo8%3D--n3G2vgaDG7VS%2B%2FhF--ZTjxBAkfGG3hpr4GRQ2S1Q%3D%3D; __profilin=p%3Dt" http://localhost:3000/orders/populate ``` - Reload your browser and look at how your cart got updated. ### Patches Please, upgrade `solidus` to versions `3.1.5`, `3.0.5` or `2.11.14`. After upgrading, make sure you read the "Upgrade notes" section below. ### Upgrade notes The patch adds CSRF token verification to the "Add to cart" action. Adding forgery protection to a form that missed it can have some side effects. #### `InvalidAuthenticityToken` errors If you're using the `:exception` strategy, it's likely that after upgrading, you'll see more `ActionController::InvalidAuthenticityToken` errors popping out in your logs. Due to browser-side cache, a form can be re-rendered and sent without any attached request cookie (for instance, when re-opening a mobile browser). That will cause an authentication error, as the sent token won't match with the one in the session (none in this case). That's a known problem in the Rails community (see https://github.com/rails/rails/issues/21948), and, at this point, there's no perfect solution. Any attempt to mitigate the issue should be seen at the application level. For an excellent survey of all the available options, take a look at https://github.com/betagouv/demarches-simplifiees.fr/blob/5b4f7f9ae9eaf0ac94008b62f7047e4714626cf9/doc/adr-csrf-forgery.md. The latter is a third-party link. As the information is relevant here, we're going to copy it below, but it should be clear that all the credit goes to @kemenaran: > # Protecting against request forgery using CRSF tokens > > ## Context > > Rails has CSRF protection enabled by default, to protect against POST-based CSRF attacks. > > To protect from this, Rails stores two copies of a random token (the so-named CSRF token) on each request: > - one copy embedded in each HTML page, > - another copy in the user session. > > When performing a POST request, Rails checks that the two copies match – and otherwise denies the request. This protects against an attacker that would generate a form secretly pointing to our website: the attacker can't read the token in the session, and so can't post a form with a valid token. > > The problem is that, much more often, this has false positives. There are several cases for that, including: > > 1. The web browser (often mobile) loads a page containing a form, then is closed by the user. Later, when the browser is re-opened, it restores the page from the cache. But the session cookie has expired, and so is not restored – so the copy of the CSRF token stored in the session is missing. When the user submits the form, they get an "InvalidAuthenticityToken" exception. > > 2. The user attempts to fill a form, and gets an error message (usually in response to a POST request). They close the browser. When the browser is re-opened, it attempts to restore the page. On Chrome this is blocked by the browser, because the browser denies retrying a (probably non-idempotent) POST request. Safari however happily retries the POST request – but without sending any cookies (in an attempt to avoid having unexpected side-effects). So the copy of the CSRF token in the session is missing (because no cookie was sent), and the user get an "InvalidAuthenticityToken" exception. > > ## Options considered > > ### Extend the session cookie duration > > We can configure the session cookie to be valid for a longer time (like 2 weeks). > > Pros: > - It solves 1., because when the browser restores the page, the session cookie is still valid. > > Cons: > - Users would be signed-in for a much longer time by default, which has unacceptable security implications. > - It doesn't solve 2. (because Safari doesn't send any cookie when restoring a page from a POST request) > > ### Change the cache parameters > > We can send a HTTP cache header stating 'Cache-Control: no-store, no-cache'. This instructs the browser to never keep any copy of the page, and to always make a request to the server to restore it. > > This solution was attempted during a year in production, and solved 1. – but also introduced another type of InvalidAuthenticityToken errors. In that scenario, the user attempts to fill a form, and gets an error message (usually in response to a POST request). They then navigate on another domain (like France Connect), then hit the "Back" button. Crossing back the domain boundary may cause the browser to either block the request or retry an invalid POST request. > > Pros: > - It solves 1., because on relaunch the browser requests a fresh page again (instead of serving it from its cache), thus retrieving a fresh session and a fresh matching CSRF token. > > Cons: > - It doesn't solve 2. > - It causes another type of InvalidAuthenticityToken errors. > > ### Using a null-session strategy > > We can change the default protect_from_forgery strategy to :null_session. This makes the current request use an empty session for the request duration. > > Pros: > - It kind of solves 1., by redirecting to a "Please sign-in" page when a stale form is submitted. > > Cons: >

Metadata

Created: 2022-01-06T18:33:44Z
Modified: 2023-05-04T19:59:15Z
Source: https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2022/01/GHSA-h3fg-h5v3-vf8m/GHSA-h3fg-h5v3-vf8m.json
CWE IDs: ["CWE-352"]
Alternative ID: GHSA-h3fg-h5v3-vf8m
Finding: F007
Auto approve: 1