Prevent Cross Script (XSS) vulnerability
- Reflexive XSS: Escape assigned variable on a Smarty templates
- Stored XSS from front to back
- Content Security Policies
- None secure svg files
XSS, or Cross-Site Scripting, is a type of web vulnerability where an attacker injects malicious scripts into web pages viewed by other users. These scripts can be executed in the context of the victim’s browser, allowing the attacker to steal sensitive information, perform actions on behalf of the victim, or otherwise compromise the security and integrity of the affected website.
It’s important for web developers and website owners to understand the dangers of XSS and implement proper security measures, such as input validation, output encoding, and other security best practices, to prevent XSS attacks and protect the security and privacy of their users. Regular security audits and testing can help identify and address XSS vulnerabilities in web applications.
IMPORTANT: There is no “perfect” protection against XSS, it is a polymorphic threat, which is constantly evolving. At any time, what was safe, becomes critically risky on an improbable dependency which adds an equally improbable event.
Reflexive XSS: Escape assigned variable on a Smarty templates
Reflected XSS, also known as non-persistent XSS, is a type of cross-site scripting vulnerability where an attacker injects malicious scripts into a website, and these scripts are then reflected back to users by the website’s server without proper sanitization. When a user visits the affected website and the malicious scripts are executed in their browser, it can lead to the execution of arbitrary code or other malicious activities.
Case <span>{$variable}</span>
The assign value of $variable
can be: <script>alert(123);</script>
.
In the front-office PrestaShop 1.7 and 8+ :
Filter smarty | Render on source |
---|---|
{$variable nofilter} |
Exposed to a XSS: <script>alert(123)</script> |
{$variable} |
<script>alert(123);</script> |
{$variable|escape:'quotes'} |
<script>alert(123);</script> |
{$variable|html_entity_decode} |
<script>alert(123);</script> |
{$variable|htmlspecialchars} |
&lt;script&gt;alert(123);&lt;/script&gt; |
{$variable|htmlspecialchars_decode:3} |
<script>alert(123);</script> |
{$variable|strip_tags:false} |
alert(123); |
{$variable|cleanHtml} |
` ` |
{$variable|escape:'html'} |
<script>console.log(123);</script> |
{$variable|escape:'htmlall':'UTF-8'} |
<script>console.log(123);</script> |
In conclusion, escape a variable in a front template is not mandatory. Please note the behaviour is not the same with PrestaShop 1.6.
In the backoffice PrestaShop 1.7 and 8+ :
Filter smarty | Render on source |
---|---|
{$variable nofilter} |
Exposed to a XSS: <script>alert(123)</script> |
{$variable} |
Exposed to a XSS: <script>alert(123)</script> |
{$variable|escape:'quotes'} |
Exposed to a XSS: <script>alert(123)</script> |
{$variable|html_entity_decode} |
Exposed to a XSS: <script>alert(123)</script> |
{$variable|htmlspecialchars_decode:3} |
Exposed to a XSS: <script>alert(123)</script> |
{$variable|strip_tags:false} |
alert(123); |
{$variable|cleanHtml} |
` ` |
{$variable|htmlspecialchars} |
<script>alert(123);</script> |
{$variable|escape:'html'} |
<script>alert(123);</script> |
{$variable|escape:'htmlall':'UTF-8'} |
<script>alert(123);</script> |
In conclusion, escaping with |escape:'htmlall':'UTF-8'
is mandatory to prevent XSS executions.
Case <span data-attribute="{$variable}">Test</span>
The assign value of $variable
can be: " onmouseover="alert(123);
.
In the front-office PrestaShop 1.7 and 8+ :
Filter smarty | Render on source |
---|---|
{$variable nofilter} |
Exposed to a XSS: <span class="" data-attribute="" onmouseover="alert(123);">Test</span> |
{$variable} |
" onmouseover="alert(123) |
{$variable|escape:'quotes'} |
" onmouseover="alert(123) |
{$variable|html_entity_decode} |
E" onmouseover="alert(123) |
{$variable|htmlspecialchars} |
" onmouseover="alert(123) |
{$variable|htmlspecialchars_decode:3} |
" onmouseover="alert(123) |
{$variable|strip_tags:false} |
" onmouseover="alert(123) |
{$variable|cleanHtml} |
` ` |
{$variable|escape:'html'} |
" onmouseover="alert(123) |
{$variable|escape:'htmlall':'UTF-8'} |
" onmouseover="alert(123) |
In the backoffice PrestaShop 1.7 and 8+ :
Filter smarty | Render on source |
---|---|
{$variable nofilter} |
Exposed to a XSS: <span class="" data-attribute="" onmouseover="alert(123);">Test</span> |
{$variable} |
Exposed to a XSS: <span class="" data-attribute="" onmouseover="alert(123);">Test</span> |
{$variable|escape:'quotes'} |
Exposed to a XSS: <span class="" data-attribute="" onmouseover="alert(123);">Test</span> |
{$variable|html_entity_decode} |
Exposed to a XSS: <span class="" data-attribute="" onmouseover="alert(123);">Test</span> |
{$variable|htmlspecialchars_decode:3} |
Exposed to a XSS: <span class="" data-attribute="" onmouseover="alert(123);">Test</span> |
{$variable|strip_tags:false} |
Exposed to a XSS: <span class="" data-attribute="" onmouseover="alert(123);">Test</span> |
{$variable|cleanHtml} |
` ` |
{$variable|htmlspecialchars} |
" onmouseover="alert(123) |
{$variable|escape:'html'} |
" onmouseover="alert(123) |
{$variable|escape:'htmlall':'UTF-8'} |
" onmouseover="alert(123) |
In conclusion, escaping with |escape:'htmlall':'UTF-8'
is mandatory to prevent XSS executions.
Please note that:
- urlencode() or addslashes() could be not efficient to prevent against XSS vulnerability at all time.
- striptags() or htmlentities() before saving data in the database could also be a good idea !
In a twig template :
DO:
<p>{{$comment.content|e}}</p>
Stored XSS from front to back
Stored XSS, also known as persistent XSS or Type 2 XSS, is a type of cross-site scripting vulnerability where an attacker injects malicious scripts into a website, and these scripts are stored on the server-side and then retrieved and executed by other users when they visit the affected website. Unlike reflexive XSS, which involves immediate reflection of the malicious script back to the user, stored XSS allows the malicious script to be persisted on the server and can affect multiple users over an extended period of time.
The PrestaShop weakness come from a frontoffice form, stored in database and executed in the backoffice. This kind of XSS are dangerous because an attacker can inject a malicious javascript that create a new employee or import a malware as a module.
To prevent this kind of vulnerability, you need escape properly your template as seen previously, but you need also validate your data to avoid to store XSS on your database.
First, we recommand to create an object model and use save(), add() and update() method this object model instead of creating INSERT UPDATE or REPLACE sql request to manage your data.
- Use a strict field definition. No varchar for int and ajust the length of the field. We consider a field length less than 40 characters is not exploitable for malicious usage.
- Define a validation of your field
// MyModuleObjectModel
public static $definition = [
'table' => 'mymoduletable',
'primary' => 'id_mymoduletable',
'fields' => [
'id_customer' => [
'type' => self::TYPE_INT,
'validate' => 'isUnsignedInt',
'required' => true,
'size' => 10,
],
'content' => [
'type' => self::TYPE_HTML,
'validate' => 'isCleanHtml',
'required' => false,
'size' => 128,
],
],
];
List of PrestaShop validations for previous malicious pattern :
Validate <script>alert(123)</script> |
Return |
---|---|
Validate::isName() | false |
Validate::isMailName | false |
Validate::isMessage | false |
Validate::isAddress | false |
Validate::isGenericName | false |
Validate::isCleanHtml | false |
Validate::isPasswd | true |
Validate::isPlaintextPassword | true |
Validate::isHashedPassword | false |
Validate::isUrl | false |
Validate::isUrlOrEmpty | false |
Validate::isString | true |
Validate::isAnything | true |
Validate::isLabel | false |
Validate::isTabName | false |
Validate::isVoucherDescription | false |
Validate::isMailSubject | false |
Validate::isPhpDateFormat | false |
Validate " onmouseover="alert(123); |
Return |
---|---|
Validate::isName | false |
Validate::isMailName | false |
Validate::isMessage | true |
Validate::isAddress | false |
Validate::isGenericName | false |
Validate::isCleanHtml | false |
Validate::isPasswd | true |
Validate::isPlaintextPassword | true |
Validate::isHashedPassword | false |
Validate::isUrl | false |
Validate::isUrlOrEmpty | false |
Validate::isString | true |
Validate::isLabel | true |
Validate::isTabName | true |
Validate::isVoucherDescription | true |
Validate::isMailSubject | true |
Validate::isPhpDateFormat | true |
In conclusion, avoid isString
isAnything
isLabel
isMessage
…
We recommand for data comming from front office to use isCleanHtml
. This forbid all html tags and suspicious html attributes.
Content Security Policies
Content-Security-Policy (CSP) is an HTTP response header that browsers use to enhance the security of the page. The Content-Security-Policy header allows you to restrict which resources (such as JavaScript, CSS, Images, etc.) can be loaded, and the URLs that they can be loaded from.
It’s recommanded to apply on PrestaShop websites CSP.
You can read CSP
None secure svg files
SVG files can contain javascript that can be executed if you load with your browser the SVG.
Prevent sensitive data disclosure | Prevent logical weakness |