Security
This section is currently not exhaustive.
This document describes the different security measures and deployment settings provided by Saleor.
Looking to report a security issue instead? See our Security Policy.
External Connectivityβ
HTTP Redirects and Timeoutsβ
Out of the box, Saleor disables HTTP redirects for outgoing connections, and sets a strict timeout value (typically <20s).
This is a design choice intended to prevent potential Denial of Service (DoS) attacks from being done by internal actors.
Without such measure in place, a malicious staff user could, for example, create an infinite redirection loop in a malicious endpoint and exhaust server resources.
Timeout settings cannot be overridden dynamically. However, they can be altered inside settings.py.
IP Address Filtering (SSRF Protection)β
This section describes the IP address filtering capabilities of Saleor Core. By default, Saleor rejects any outgoing traffic to private and loopback IP addresses.
This behavior prevents malicious staff users from accessing inward-facing resources, which could lead to unauthorized access to resources you may deploy within your networks or even gaining a foothold (such as achieving lateral movements to gain more privileges).
For in-depth details, refer to:
Implementation Details:
- IP Addresses are Pinned: the resolved IP address for each outgoing HTTP(S) request is pinned, meaning that a malicious actor cannot set-up round-robin DNS responses or use race-condition attacks (Time-of-Check) to trick Saleor into connecting to a different IP address after validation.
- IP Address Validation for Each Request: validation is ran before sending each and every HTTP(S) request. This prevents a malicious actor from changing the DNS records after adding a non-malicious URL inside the database.
Settings:
HTTP_IP_FILTER_ENABLED- controls whether the IP filtering feature should be enabled. IP Filtering is enabled by default.HTTP_IP_FILTER_ALLOW_LOOPBACK_IPS- whether to allow outgoing traffic to loopback addresses. Loopback addresses are disallowed by default.
Caveats:
- Allow-Lists: it is not currently possible to put given IP addresses into an allow-list (or block-list). It currently only supports: "block-all" or "allow-all".
Additional Capabilities:
-
Proxies: SOCKS and HTTP proxies can be used in combination with the IP Filtering.
-
The IP address used to establish the proxy tunnel itself is not restricted. However, any HTTP requests sent through the proxy will be filtered based on their destination IP address.
For example, setting
HTTPS_PROXY=socks5://10.0.0.1:8888is allowed, but attempting to accesshttps://10.0.0.2through the tunnel will be blocked. -
Can be configured through environment variables, such as:
$ export HTTP_PROXY="http://10.10.1.10:3128"
$ export HTTPS_PROXY="http://10.10.1.10:1080"
# Alternatively:
$ export ALL_PROXY="http://10.10.1.10:1080"
-
-
HTTP redirects: each redirection is checked whether it points to a private or loopback IP address range.
Restricting Public API Accessβ
The Shop.allowStorefrontTraffic setting lets you close the GraphQL API to unauthenticated & unprivileged users, leaving it reachable only by apps and staff users. See Blocking storefront traffic.
Note that this is an access-control switch, not a DoS protection and therefore doesn't act as a replacement for the placements of a WAF, proper rate-limits, and other controls.
Restricted File Uploadsβ
Out of the box Saleor restricts the type of files that can be uploaded in mutations like fileUpload() and digitalContentCreate() (list may not be exhaustive).
This is done in order to limit the risks of misuse from staff users who could upload malicious files like .html, .svg, or even .exe. By default Saleor only allows popular file formats but if needed you can relax it using the UPLOAD_ADDITIONAL_ALLOWED_MIME_TYPES environment variable.
You shouldn't allow dangerous file formats (e.g., HTML or SVG), instead prefer using zip files to reduce the risks of the browser rendering them.
Saleor's behavior is as follows:
- Saleor checks the file extensions to determine whether the file extension is allowed.
- AND Saleor checks whether the file's MIME matches the file extension, e.g., if
image.pngbut has the MIMEtext/htmlthen it's rejected.
We highly recommend that you also return Content-Disposion: attachment in HTTP responses for the media files to further reduce risks, for example, if you use AWS Cloudfront you can follow our AWS Best Practices.
EditorJS & HTML Cleaningβ
Saleor accepts HTML in rich text fields (such as product descriptions, pages, collections, etc.), under the hood it cleans the untrusted HTML inputs using nh3 and Ammonia. These libraries rely on strict allow-lists for HTML elements, attributes, and attribute values to mitigate the risks of XSS attacks.
Our cleaner can be configured through the following settings:
EDITOR_JS_ALLOWED_ATTRIBUTES(docs) - a list of HTML attributes to allow for given HTML elements. For example, if you want to allow users to passmy-attrfor all<a>elements, then you this is the correct environment variable to modify.EDITOR_JS_ALLOWED_ATTRIBUTE_VALUES(docs) - a list of values allowed inside given attributes within a given element, this a stricter version of the previous setting: instead of allowing all values, it only allows the given values.EDITOR_JS_LINK_REL(docs) - controls which values to put in therelattribute for links (<a href=... rel="XXX">). We recommend setting both noopener and noreferrer, at minimum noopener.UNSAFE_EDITOR_JS_ALLOWED_URL_SCHEMES(docs) - a list of allowed URL schemes. By default we allow only HTTP(S) links, telephone numbers and mailto addresses.EDITOR_JS_LISTS_MAX_DEPTH(docs) - limits the list depth for nested list from EditorJS - defaults to 10, meaning you can have indentation 10 levels in lists (typically a person only uses max 3 levels).
Automatic Account Association of Anonymous Ordersβ
When a customer places orders or uses gift cards without signing in, Saleor can later associate those objects with an account created using the same email address.
A legitimate flow may look as follows:
guest@example.complaces several orders as a guest- The customer creates an account using
guest@example.com - Saleor sends an account-confirmation link to that email address
- The customer opens the link and confirms the account.
- Saleor associates the customer's previous orders and gift cards with the newly confirmed account.
This allows customers to access their previous order history and other objects after creating an account, improving the overall shopping experience.
Account Pre-Hijacking Riskβ
This behavior could create an account pre-hijacking risk when possession of the confirmation link is treated as sufficient proof that the person confirming the account also created and controls it.
An attacker could perform the following flow:
- Create an account using the victimβs email address and a password chosen by the attacker.
- Saleor sends a legitimate account-confirmation email to the victim.
- Attacker tricks or persuades the victim into opening the confirmation link, or the victim simply clicks it out of curiosity.
- Attacker signs-in using their attacker-chosen password after the account has been confirmed.
- Attacker can now access orders, gift cards, addresses, and other data that Saleor associated with the account.
How Saleor mitigates against this:
To prevent this attack, Saleor requires a proof that the person opening the confirmation link also knows the password assigned to that account.
Saleor therefore requires the user to provide the account password when calling the
confirmAccount() mutation:
mutation ($email: String!, $password: String!, $token: String!) {
confirmAccount(email: $email, password: $password, token: $token) {
errors {
field
message
}
}
}
A victim who did not create the account will not know the attacker-chosen password and therefore cannot complete the confirmation flow. Instead, the victim must initiate a password reset which invalidates the attacker's control of the password before associating the existing objects.
This ensures that access to the email account alone does not activate an account whose credentials remain under an attacker's control.
For users coming from versions earlier than 3.24.0, you must follow the migration guide to fully benefit from the mitigations.
PCI DSSβ
Diagrams representing payment-related data flow: