Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 169 lines (135 sloc) 7.228 kB
33a035b @mitsuhiko Added security document
authored
1 Security Considerations
2 =======================
3
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.
7
4a2d2ba @mitsuhiko Added templating docs. This basically fixes #92
authored
8 .. _xss:
9
33a035b @mitsuhiko Added security document
authored
10 Cross-Site Scripting (XSS)
11 --------------------------
12
4a2d2ba @mitsuhiko Added templating docs. This basically fixes #92
authored
13 Cross site scripting is the concept of injecting arbitrary HTML (and with
67f483b @doobeh Typo.
doobeh authored
14 it JavaScript) into the context of a website. To remedy this, developers
4a2d2ba @mitsuhiko Added templating docs. This basically fixes #92
authored
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 <http://en.wikipedia.org/wiki/Cross-site_scripting>`_.
19
33a035b @mitsuhiko Added security document
authored
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:
24
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.
32
559d281 @mitsuhiko Expanded the security docs to mention unquoted attributes as dangerous
authored
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:
38
39 .. sourcecode:: html+jinja
40
41 <a href="{{ href }}">the text</a>
42
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:
46
47 .. sourcecode:: html
48
49 onmouseover=alert(document.cookie)
50
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.
57
33a035b @mitsuhiko Added security document
authored
58 Cross-Site Request Forgery (CSRF)
59 ---------------------------------
60
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.
64
085faf2 @rduplain First pass to reword security doc for word flow.
rduplain authored
65 If your authentication information is stored in cookies, you have implicit
66 state management. The state of "being logged in" is controlled by a
67 cookie, and that cookie is sent with each request to a page.
68 Unfortunately that includes requests triggered by 3rd party sites. If you
69 don't keep that in mind, some people might be able to trick your
70 application's users with social engineering to do stupid things without
71 them knowing.
33a035b @mitsuhiko Added security document
authored
72
73 Say you have a specific URL that, when you sent `POST` requests to will
74 delete a user's profile (say `http://example.com/user/delete`). 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
085faf2 @rduplain First pass to reword security doc for word flow.
rduplain authored
76 some JavaScript he just has to trick some users to load that page and
77 their profiles will end up being deleted.
33a035b @mitsuhiko Added security document
authored
78
085faf2 @rduplain First pass to reword security doc for word flow.
rduplain authored
79 Imagine you were to run Facebook with millions of concurrent users and
80 someone would send out links to images of little kittens. When users
81 would go to that page, their profiles would get deleted while they are
33a035b @mitsuhiko Added security document
authored
82 looking at images of fluffy cats.
83
085faf2 @rduplain First pass to reword security doc for word flow.
rduplain authored
84 How can you prevent that? Basically for each request that modifies
85 content on the server you would have to either use a one-time token and
86 store that in the cookie **and** also transmit it with the form data.
87 After receiving the data on the server again, you would then have to
88 compare the two tokens and ensure they are equal.
33a035b @mitsuhiko Added security document
authored
89
085faf2 @rduplain First pass to reword security doc for word flow.
rduplain authored
90 Why does Flask not do that for you? The ideal place for this to happen is
91 the form validation framework, which does not exist in Flask.
33a035b @mitsuhiko Added security document
authored
92
93 .. _json-security:
94
95 JSON Security
96 -------------
97
7083b35 @florentx Typo.
florentx authored
98 JSON itself is a high-level serialization format, so there is barely
33a035b @mitsuhiko Added security document
authored
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
authored
103
52f38bb @mitsuhiko Fixed a broken sentence
authored
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
authored
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.
111
112 So what is the issue and how to avoid it? The problem are arrays at
da00160 Fixed some small typos in the documentation.
Sam Anderson authored
113 top-level in JSON. Imagine you send the following data out in a JSON
085faf2 @rduplain First pass to reword security doc for word flow.
rduplain authored
114 request. Say that's exporting the names and email addresses of all your
115 friends for a part of the user interface that is written in JavaScript.
33a035b @mitsuhiko Added security document
authored
116 Not very uncommon:
117
118 .. sourcecode:: javascript
119
120 [
121 {"username": "admin",
122 "email": "admin@localhost"}
123 ]
124
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 ``http://example.com/api/get_friends.json``.
129
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:
132
133 .. sourcecode:: html
134
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=http://example.com/api/get_friends.json></script>
149 <script type=text/javascript>
150 Array = oldArray;
151 // now we have all the data in the captured array.
152 </script>
153
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
da00160 Fixed some small typos in the documentation.
Sam Anderson authored
159 tag and evaluate that as JavaScript. Because top-level array elements are
33a035b @mitsuhiko Added security document
authored
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.
162
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
authored
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.