Skip to content


Subversion checkout URL

You can clone with
Download ZIP
100644 169 lines (135 sloc) 7.11 KB
33a035b @mitsuhiko Added security document
1 Security Considerations
2 =======================
4 Web applications usually face all kinds of security problems and it's very
5 hard to get everything right. Flask tries to solve a few of these things
6 for you, but there are a couple more you have to take care of yourself.
4a2d2ba @mitsuhiko Added templating docs. This basically fixes #92
8 .. _xss:
33a035b @mitsuhiko Added security document
10 Cross-Site Scripting (XSS)
11 --------------------------
4a2d2ba @mitsuhiko Added templating docs. This basically fixes #92
13 Cross site scripting is the concept of injecting arbitrary HTML (and with
14 it JavaScript) into the context of a website. To rememdy this, developers
15 have to properly escape text so that it cannot include arbitrary HTML
16 tags. For more information on that have a look at the Wikipedia article
17 on `Cross-Site Scripting
18 <>`_.
33a035b @mitsuhiko Added security document
20 Flask configures Jinja2 to automatically escape all values unless
21 explicitly told otherwise. This should rule out all XSS problems caused
22 in templates, but there are still other places where you have to be
23 careful:
25 - generating HTML without the help of Jinja2
26 - calling :class:`~flask.Markup` on data submitted by users
27 - sending out HTML from uploaded files, never do that, use the
28 `Content-Disposition: attachment` header to prevent that problem.
29 - sending out textfiles from uploaded files. Some browsers are using
30 content-type guessing based on the first few bytes so users could
31 trick a browser to execute HTML.
559d281 @mitsuhiko Expanded the security docs to mention unquoted attributes as dangerous
33 Another thing that is very important are unquoted attributes. While
34 Jinja2 can protect you from XSS issues by escaping HTML, there is one
35 thing it cannot protect you from: XSS by attribute injection. To counter
36 this possible attack vector, be sure to always quote your attributes with
37 either double or single quotes when using Jinja expressions in them:
39 .. sourcecode:: html+jinja
41 <a href="{{ href }}">the text</a>
43 Why is this necessary? Because if you would not be doing that, an
44 attacker could easily inject custom JavaScript handlers. For example an
45 attacker could inject this piece of HTML+JavaScript:
47 .. sourcecode:: html
49 onmouseover=alert(document.cookie)
51 When the user would then move with the mouse over the link, the cookie
52 would be presented to the user in an alert window. But instead of showing
53 the cookie to the user, a good attacker might also execute any other
54 JavaScript code. In combination with CSS injections the attacker might
55 even make the element fill out the entire page so that the user would
56 just have to have the mouse anywhere on the page to trigger the attack.
33a035b @mitsuhiko Added security document
58 Cross-Site Request Forgery (CSRF)
59 ---------------------------------
61 Another big problem is CSRF. This is a very complex topic and I won't
62 outline it here in detail just mention what it is and how to theoretically
63 prevent it.
65 So if your authentication information is stored in cookies you have
66 implicit state management. By that I mean that the state of "being logged
67 in" is controlled by a cookie and that cookie is sent with each request to
68 a page. Unfortunately that really means "each request" so also requests
69 triggered by 3rd party sites. If you don't keep that in mind some people
70 might be able to trick your application's users with social engineering to
71 do stupid things without them knowing.
73 Say you have a specific URL that, when you sent `POST` requests to will
74 delete a user's profile (say ``). If an
ff2786d @jgraeme Fix some typos in the docs
jgraeme authored
75 attacker now creates a page that sends a post request to that page with
33a035b @mitsuhiko Added security document
76 some JavaScript he just has to trick some users to that page and their
77 profiles will end up being deleted.
79 Imagine you would run Facebook with millions of concurrent users and
80 someone would send out links to images of little kittens. When a user
81 would go to that page their profiles would get deleted while they are
82 looking at images of fluffy cats.
84 So how can you prevent yourself from that? Basically for each request
85 that modifies content on the server you would have to either use a
86 one-time token and store that in the cookie **and** also transmit it with
87 the form data. After recieving the data on the server again you would
88 then have to compare the two tokens and ensure they are equal.
90 Why does not Flask do that for you? The ideal place for this to happen is
91 the form validation framework which does not exist in Flask.
93 .. _json-security:
95 JSON Security
96 -------------
7083b35 @florentx Typo.
florentx authored
98 JSON itself is a high-level serialization format, so there is barely
33a035b @mitsuhiko Added security document
99 anything that could cause security problems, right? You can't declare
100 recursive structures that could cause problems and the only thing that
101 could possibly break are very large responses that can cause some kind of
7083b35 @florentx Typo.
florentx authored
102 denial of service at the receiver's side.
33a035b @mitsuhiko Added security document
52f38bb @mitsuhiko Fixed a broken sentence
104 However there is a catch. Due to how browsers work the CSRF issue comes
105 up with JSON unfortunately. Fortunately there is also a weird part of the
33a035b @mitsuhiko Added security document
106 JavaScript specification that can be used to solve that problem easily and
107 Flask is kinda doing that for you by preventing you from doing dangerous
108 stuff. Unfortunately that protection is only there for
109 :func:`~flask.jsonify` so you are still at risk when using other ways to
110 generate JSON.
112 So what is the issue and how to avoid it? The problem are arrays at
113 toplevel in JSON. Imagine you send the following data out in a JSON
114 request. Say that's exporting the names and email adresses of all your
115 friends for a part of the userinterface that is written in JavaScript.
116 Not very uncommon:
118 .. sourcecode:: javascript
120 [
121 {"username": "admin",
122 "email": "admin@localhost"}
123 ]
125 And it is doing that of course only as long as you are logged in and only
126 for you. And it is doing that for all `GET` requests to a certain URL,
127 say the URL for that request is
128 ````.
130 So now what happens if a clever hacker is embedding this to his website
131 and social engineers a victim to visiting his site:
133 .. sourcecode:: html
135 <script type=text/javascript>
136 var captured = [];
137 var oldArray = Array;
138 function Array() {
139 var obj = this, id = 0, capture = function(value) {
140 obj.__defineSetter__(id++, capture);
141 if (value)
142 captured.push(value);
143 };
144 capture();
145 }
146 </script>
147 <script type=text/javascript
148 src=></script>
149 <script type=text/javascript>
150 Array = oldArray;
151 // now we have all the data in the captured array.
152 </script>
154 If you know a bit of JavaScript internals you might know that it's
155 possible to patch constructors and register callbacks for setters. An
156 attacker can use this (like above) to get all the data you exported in
157 your JSON file. The browser will totally ignore the ``application/json``
158 mimetype if ``text/javascript`` is defined as content type in the script
159 tag and evaluate that as JavaScript. Because toplevel array elements are
160 allowed (albeit useless) and we hooked in our own constructor, after that
161 page loaded the data from the JSON response is in the `captured` array.
163 Because it is a syntax error in JavaScript to have an object literal
164 (``{...}``) toplevel an attacker could not just do a request to an
165 external URL with the script tag to load up the data. So what Flask does
ff2786d @jgraeme Fix some typos in the docs
jgraeme authored
166 is to only allow objects as toplevel elements when using
33a035b @mitsuhiko Added security document
167 :func:`~flask.jsonify`. Make sure to do the same when using an ordinary
168 JSON generate function.
Something went wrong with that request. Please try again.