CSRF protection (#798)

Closes #793.

* Rename RequestParameters to MultiParams, refs #799
* Allow tuples as well as lists in MultiParams, refs #799
* Use csrftokens when running tests, refs #799
* Use new csrftoken() function, refs https://github.com/simonw/asgi-csrf/issues/7
* Check for Vary: Cookie hedaer, refs https://github.com/simonw/asgi-csrf/issues/8
This commit is contained in:
Simon Willison 2020-06-05 12:05:57 -07:00 committed by GitHub
commit 84a9c4ff75
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 67 additions and 19 deletions

View file

@ -1,4 +1,5 @@
import asyncio
import asgi_csrf
import collections
import datetime
import hashlib
@ -884,7 +885,14 @@ class Datasette:
await database.table_counts(limit=60 * 60 * 1000)
asgi = AsgiLifespan(
AsgiTracer(DatasetteRouter(self, routes)), on_startup=setup_db
AsgiTracer(
asgi_csrf.asgi_csrf(
DatasetteRouter(self, routes),
signing_secret=self._secret,
cookie_name="ds_csrftoken",
)
),
on_startup=setup_db,
)
for wrapper in pm.hook.asgi_wrapper(datasette=self):
asgi = wrapper(asgi)

View file

@ -8,7 +8,7 @@
<p>Set a message:</p>
<form action="/-/messages" method="POST">
<form action="/-/messages" method="post">
<div>
<input type="text" name="message" style="width: 40%">
<div class="select-wrapper">
@ -19,6 +19,7 @@
<option>all</option>
</select>
</div>
<input type="hidden" name="csrftoken" value="{{ csrftoken() }}">
<input type="submit" value="Add message">
</div>
</form>

View file

@ -52,6 +52,7 @@
{% endif %}
<p>
<button id="sql-format" type="button" hidden>Format SQL</button>
{% if canned_query %}<input type="hidden" name="csrftoken" value="{{ csrftoken() }}">{% endif %}
<input type="submit" value="Run SQL">
</p>
</form>

View file

@ -772,6 +772,9 @@ class MultiParams:
new_data.setdefault(key, []).append(value)
self._data = new_data
def __repr__(self):
return "<MultiParams: {}>".format(self._data)
def __contains__(self, key):
return key in self._data

View file

@ -95,6 +95,7 @@ class BaseView(AsgiView):
**context,
**{
"database_url": self.database_url,
"csrftoken": request.scope["csrftoken"],
"database_color": self.database_color,
"show_messages": lambda: self.ds._show_messages(request),
"select_templates": [