Skip to content

Commit 8b7fe7f

Browse files
committed
Update docs re #5's re-opening / #6
1 parent d7d8620 commit 8b7fe7f

4 files changed

Lines changed: 44 additions & 25 deletions

File tree

docs/source/quickstart.rst

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,17 @@ Using the flask decorator
66

77
::
88

9+
import flask
910
from flask import Flask
1011
from raven.flask_glue import AuthDecorator
1112

13+
# Werkzeug deduces the hostname from the 'Host' or
14+
# 'X-Forwarded-Host' headers, so we need a whitelist
15+
class R(flask.Request):
16+
trusted_hosts = {'your-domain.com', 'www.your-domain.com'}
17+
1218
app = Flask(__name__)
19+
app.request_class = R
1320
app.secret_key = "a secret key"
1421
auth_decorator = AuthDecorator(desc="My website")
1522

@@ -26,10 +33,17 @@ Requiring all flask requests be authenticated
2633

2734
::
2835

36+
import flask
2937
from flask import Flask
3038
from raven.flask_glue import AuthDecorator
3139

40+
# Werkzeug deduces the hostname from the 'Host' or
41+
# 'X-Forwarded-Host' headers, so we need a whitelist
42+
class R(flask.Request):
43+
trusted_hosts = {'your-domain.com', 'www.your-domain.com'}
44+
3245
app = Flask(__name__)
46+
app.request_class = R
3347
app.secret_key = "a secret key"
3448
auth_decorator = AuthDecorator()
3549

@@ -98,9 +112,8 @@ Integrating with existing authentication or session management
98112
99113
# checking url, issue, iact and aauth is very important!
100114
# Werkzeug deduces the hostname from the 'Host' or
101-
# 'X-Forwarded-Host' headers. A whitelist is safest, or you
102-
# may like to pass a secret in `params`.
103-
request.trusted_hosts = {'www.danielrichman.co.uk'}
115+
# 'X-Forwarded-Host' headers, so we need a whitelist
116+
request.trusted_hosts = {'www.your-domain.com', 'your-domain.com'}
104117
if r.url != request.base_url:
105118
print "Bad url"
106119
abort(400)

docs/source/security.rst

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -15,21 +15,26 @@ response:
1515
Not checking `url` will allow another evil website administrator to replay
1616
responses produced by Raven log-ins to her website to yours, thereby
1717
impersonating someone else.
18+
(Using params as a token (below) doesn't help, since the attacker can
19+
obtain a matching `(cookie, params)` pair from you first, and then ask
20+
the victim to authenticate with `params` set to that value.)
1821

1922
Some frameworks, notably Werkzeug, deduce the current hostname from
2023
the `Host` or `X-Forwarded-Host` headers (with the latter taking
21-
precedence). If you are not checking the `Host` header / doing virtual
22-
hosting *and* wiping the `X-Forwarded-Host` header in your web server,
23-
you need to check the host against a whitelist in your application.
24+
precedence).
25+
26+
.. seealso::
27+
`werkzeug#609 <https://github.com/mitsuhiko/werkzeug/issues/609>`_ and
28+
`issue 5 <https://github.com/danielrichman/python-raven/issues/5>`_
2429

25-
This may be used to whitelist domains in Flask::
30+
This technique may be used to whitelist domains in Flask::
2631

2732
class R(flask.Request):
2833
trusted_hosts = {'www.danielrichman.co.uk'}
2934
app.request_class = R
3035

31-
You may forgo checking `url` *if* you instead use a token in `params`
32-
as described below.
36+
Alternatively, you could sanitise `Host` and `X-Forwarded-Host` in your
37+
web-server.
3338

3439
* check `issue` is within an acceptable range of *now*
3540

@@ -45,25 +50,24 @@ response:
4550
Using params as a token
4651
-----------------------
4752

48-
If checking `url` (above) is a pain, you could:
53+
You might like to set a random nonce in the Request's `params`, save
54+
a hashed (with secret salt) or signed copy in a cookie, and check that they
55+
match in the `Response`.
4956

50-
* generate a random string just before you redirect to Raven
51-
* set a cookie on the client with that string
52-
* include that string as `params` in the :class:`ucam_webauth.Request`
53-
* check that they match in the :class:`ucam_webauth.Response`
57+
This is *not* a substitute for any of the checks above, but does make the
58+
`WLS-Response` values in your web server access logs useless.
5459

55-
The principle is similar to that of an CSRF token for submitting forms.
56-
57-
This is what :class:`ucam_webauth.flask_glue.AuthDecorator` does.
60+
:class:`ucam_webauth.flask_glue.AuthDecorator` does this.
5861

5962
Signing keys
6063
------------
6164

6265
The keys used by Raven to sign responses are included with `python-raven`.
6366
I took care in retrieving them, however you should trust neither me nor the
6467
method by which you installed this package.
65-
**You should check that the copies of the certificates you have are
66-
correct / match the files at the links below**.
68+
*You should check that the copies of the certificates you have are
69+
correct / match the files at the links below* (and audit the code you've
70+
just installed, I guess).
6771

6872
* ``pubkey2`` from `<https://raven.cam.ac.uk/project/keys/>`_
6973
* ``pubkey901`` from `<https://raven.cam.ac.uk/project/keys/demo_server/>`_

simple_demo/app.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,16 @@
1010
import raven.demoserver
1111
import raven.flask_glue
1212

13+
import flask
1314
from flask import Flask, request, render_template, redirect, \
1415
url_for, abort, session, flash
16+
17+
class Request(flask.Request):
18+
trusted_hosts = {'localhost', '127.0.0.1'}
19+
1520
app = Flask(__name__)
1621

22+
app.request_class = Request
1723
app.config["SECRET_KEY"] = os.urandom(16)
1824

1925
app.add_template_global(repr, name="repr")

ucam_webauth/flask_glue.py

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -281,17 +281,13 @@ def before_request(self):
281281
* checks if there is a response from the WLS
282282
283283
* checks if the current URL matches that which the WLS said it
284-
redirected to (the intention is to avoid an evil admin of another
285-
site replaying successful authentications to us, but it isn't
286-
perfect unless you're careful with your `Host` and
287-
`X-Forwarded-Host` headers)
284+
redirected to (avoid an evil admin of another site replaying
285+
successful authentications)
288286
* checks if ``flask.session`` is empty - if so, then we deduce that
289287
the user has cookies disabled, and must abort immediately with
290288
403 Forbidden, or we will start a redirect loop
291289
* checks if `params` matches the token we set (and saved in
292290
``flask.session``) when redirecting to Raven
293-
(preventing replaying successful authentications from other
294-
sites onto ours)
295291
* checks if the authentication method used is permitted by `aauth`
296292
and user-interaction respected `iact` - if not, abort with
297293
400 Bad Request

0 commit comments

Comments
 (0)