<spanid="security-xss"></span><h2>Cross-Site Scripting (XSS)<aclass="headerlink"href="#cross-site-scripting-xss"title="Link to this heading">¶</a></h2>
<p>Cross site scripting is the concept of injecting arbitrary HTML (and with
it JavaScript) into the context of a website. To remedy this, developers
have to properly escape text so that it cannot include arbitrary HTML
tags. For more information on that have a look at the Wikipedia article
on <aclass="reference external"href="https://en.wikipedia.org/wiki/Cross-site_scripting">Cross-Site Scripting</a>.</p>
<p>Flask configures Jinja2 to automatically escape all values unless
explicitly told otherwise. This should rule out all XSS problems caused
in templates, but there are still other places where you have to be
careful:</p>
<ulclass="simple">
<li><p>generating HTML without the help of Jinja2</p></li>
<li><p>calling <codeclass="xref py py-class docutils literal notranslate"><spanclass="pre">Markup</span></code> on data submitted by users</p></li>
<li><p>sending out HTML from uploaded files, never do that, use the
<codeclass="docutils literal notranslate"><spanclass="pre">Content-Disposition:</span><spanclass="pre">attachment</span></code> header to prevent that problem.</p></li>
<li><p>sending out textfiles from uploaded files. Some browsers are using
content-type guessing based on the first few bytes so users could
trick a browser to execute HTML.</p></li>
</ul>
<p>Another thing that is very important are unquoted attributes. While
Jinja2 can protect you from XSS issues by escaping HTML, there is one
thing it cannot protect you from: XSS by attribute injection. To counter
this possible attack vector, be sure to always quote your attributes with
either double or single quotes when using Jinja expressions in them:</p>
<p>When the user would then move with the mouse over the input, the cookie
would be presented to the user in an alert window. But instead of showing
the cookie to the user, a good attacker might also execute any other
JavaScript code. In combination with CSS injections the attacker might
even make the element fill out the entire page so that the user would
just have to have the mouse anywhere on the page to trigger the attack.</p>
<p>There is one class of XSS issues that Jinja’s escaping does not protect
against. The <codeclass="docutils literal notranslate"><spanclass="pre">a</span></code> tag’s <codeclass="docutils literal notranslate"><spanclass="pre">href</span></code> attribute can contain a <codeclass="code docutils literal notranslate"><spanclass="pre">javascript:</span></code> URI,
which the browser will execute when clicked if not secured properly.</p>
<divclass="highlight-html notranslate"><divclass="highlight"><pre><span></span><spanclass="p"><</span><spanclass="nt">a</span><spanclass="na">href</span><spanclass="o">=</span><spanclass="s">"{{ value }}"</span><spanclass="p">></span>click here<spanclass="p"></</span><spanclass="nt">a</span><spanclass="p">></span>
<p>To prevent this, you’ll need to set the <aclass="reference internal"href="#security-csp"><spanclass="std std-ref">Content Security Policy (CSP)</span></a> response header.</p>
<spanid="security-json"></span><h2>JSON Security<aclass="headerlink"href="#json-security"title="Link to this heading">¶</a></h2>
<p>In Flask 0.10 and lower, <codeclass="xref py py-func docutils literal notranslate"><spanclass="pre">jsonify()</span></code> did not serialize top-level
arrays to JSON. This was because of a security vulnerability in ECMAScript 4.</p>
<p>ECMAScript 5 closed this vulnerability, so only extremely old browsers are
still vulnerable. All of these browsers have <aclass="reference external"href="https://github.com/pallets/flask/issues/248#issuecomment-59934857">other more serious
vulnerabilities</a>, so
this behavior was changed and <codeclass="xref py py-func docutils literal notranslate"><spanclass="pre">jsonify()</span></code> now supports serializing
arrays.</p>
</section>
<sectionid="security-headers">
<h2>Security Headers<aclass="headerlink"href="#security-headers"title="Link to this heading">¶</a></h2>
<p>Browsers recognize various response headers in order to control security. We
recommend reviewing each of the headers below for use in your application.
The <aclass="reference external"href="https://github.com/GoogleCloudPlatform/flask-talisman">Flask-Talisman</a> extension can be used to manage HTTPS and the security
headers for you.</p>
<sectionid="http-strict-transport-security-hsts">
<h3>HTTP Strict Transport Security (HSTS)<aclass="headerlink"href="#http-strict-transport-security-hsts"title="Link to this heading">¶</a></h3>
<p>Tells the browser to convert all HTTP requests to HTTPS, preventing
<spanid="security-csp"></span><h3>Content Security Policy (CSP)<aclass="headerlink"href="#content-security-policy-csp"title="Link to this heading">¶</a></h3>
<p>Tell the browser where it can load various types of resource from. This header
should be used whenever possible, but requires some work to define the correct
policy for your site. A very strict policy would be:</p>
<spanid="security-cookie"></span><h3>Set-Cookie options<aclass="headerlink"href="#set-cookie-options"title="Link to this heading">¶</a></h3>
<p>These options can be added to a <codeclass="docutils literal notranslate"><spanclass="pre">Set-Cookie</span></code> header to improve their
security. Flask has configuration options to set these on the session cookie.
They can be set on other cookies too.</p>
<ulclass="simple">
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">Secure</span></code> limits cookies to HTTPS traffic only.</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">HttpOnly</span></code> protects the contents of cookies from being read with
JavaScript.</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">SameSite</span></code> restricts how cookies are sent with requests from
external sites. Can be set to <codeclass="docutils literal notranslate"><spanclass="pre">'Lax'</span></code> (recommended) or <codeclass="docutils literal notranslate"><spanclass="pre">'Strict'</span></code>.
<codeclass="docutils literal notranslate"><spanclass="pre">Lax</span></code> prevents sending cookies with CSRF-prone requests from
external sites, such as submitting a form. <codeclass="docutils literal notranslate"><spanclass="pre">Strict</span></code> prevents sending
cookies with all external requests, including following regular links.</p></li>
<p>Specifying <codeclass="docutils literal notranslate"><spanclass="pre">Expires</span></code> or <codeclass="docutils literal notranslate"><spanclass="pre">Max-Age</span></code> options, will remove the cookie after
the given time, or the current time plus the age, respectively. If neither
option is set, the cookie will be removed when the browser is closed.</p>
<divclass="highlight-default notranslate"><divclass="highlight"><pre><span></span><spanclass="c1"># cookie expires after 10 minutes</span>
<p>For the session cookie, if <aclass="reference internal"href="api.html#flask.session.permanent"title="flask.session.permanent"><codeclass="xref py py-attr docutils literal notranslate"><spanclass="pre">session.permanent</span></code></a>
is set, then <aclass="reference internal"href="config.html#PERMANENT_SESSION_LIFETIME"title="PERMANENT_SESSION_LIFETIME"><codeclass="xref py py-data docutils literal notranslate"><spanclass="pre">PERMANENT_SESSION_LIFETIME</span></code></a> is used to set the expiration.
Flask’s default cookie implementation validates that the cryptographic
signature is not older than this value. Lowering this value may help mitigate
replay attacks, where intercepted cookies can be sent at a later time.</p>
<p>Use <codeclass="xref py py-class docutils literal notranslate"><spanclass="pre">itsdangerous.TimedSerializer</span></code> to sign and validate other cookie
values (or any values that need secure signatures).</p>
<h2>Copy/Paste to Terminal<aclass="headerlink"href="#copy-paste-to-terminal"title="Link to this heading">¶</a></h2>
<p>Hidden characters such as the backspace character (<codeclass="docutils literal notranslate"><spanclass="pre">\b</span></code>, <codeclass="docutils literal notranslate"><spanclass="pre">^H</span></code>) can
cause text to render differently in HTML than how it is interpreted if
<aclass="reference external"href="https://security.stackexchange.com/q/39118">pasted into a terminal</a>.</p>
<p>For example, <codeclass="docutils literal notranslate"><spanclass="pre">import</span><spanclass="pre">y\bose\bm\bi\bt\be\b</span></code> renders as
<codeclass="docutils literal notranslate"><spanclass="pre">import</span><spanclass="pre">yosemite</span></code> in HTML, but the backspaces are applied when pasted
into a terminal, and it becomes <codeclass="docutils literal notranslate"><spanclass="pre">import</span><spanclass="pre">os</span></code>.</p>
<p>If you expect users to copy and paste untrusted code from your site,
such as from comments posted by users on a technical blog, consider
applying extra filtering, such as replacing all <codeclass="docutils literal notranslate"><spanclass="pre">\b</span></code> characters.</p>