commit ccf125bce7cd3094bfd4bb8b1ce6b8d2d6890e22 Author: Arturo Filastò art@fuffa.org Date: Tue May 7 18:59:10 2013 +0200
Implement XSRF protection in the HTTP API --- ooni/api/spec.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+)
diff --git a/ooni/api/spec.py b/ooni/api/spec.py index fe18ccc..f707253 100644 --- a/ooni/api/spec.py +++ b/ooni/api/spec.py @@ -4,6 +4,7 @@ import copy import json import types import tempfile +import functools
from twisted.python import usage from cyclone import web, escape @@ -19,8 +20,18 @@ class InvalidInputFilename(Exception): class FilenameExists(Exception): pass
+def check_xsrf(method): + @functools.wraps(method) + def wrapper(self, *args, **kw): + xsrf_header = self.request.headers.get("X-XSRF-TOKEN") + if self.xsrf_token != xsrf_header: + raise web.HTTPError(403, "Invalid XSRF token.") + return method(self, *args, **kw) + return wrapper + class ORequestHandler(web.RequestHandler): serialize_lists = True + xsrf_cookie_name = "XSRF-TOKEN"
def write(self, chunk): """ @@ -33,6 +44,7 @@ class ORequestHandler(web.RequestHandler): web.RequestHandler.write(self, chunk)
class Status(ORequestHandler): + @check_xsrf def get(self): result = {'active_tests': oonidApplication.director.activeNetTests} self.write(result) @@ -47,6 +59,8 @@ class Inputs(ORequestHandler): """ This handler is responsible for listing and adding new inputs. """ + + @check_xsrf def get(self): """ Obtain the list of currently installed inputs. Inputs are stored inside @@ -55,6 +69,7 @@ class Inputs(ORequestHandler): input_list = list_inputs() self.write(input_list)
+ @check_xsrf def post(self): """ Add a new input to the currently installed inputs. @@ -76,6 +91,8 @@ class Inputs(ORequestHandler): fp.write(body)
class ListTests(ORequestHandler): + + @check_xsrf def get(self): test_list = copy.deepcopy(oonidApplication.director.netTests) for test_id in test_list.keys(): @@ -138,6 +155,8 @@ def write_temporary_input(content): return fd, path
class StartTest(ORequestHandler): + + @check_xsrf def post(self, test_name): """ Starts a test with the specified options. @@ -174,6 +193,8 @@ class StartTest(ORequestHandler): 'Insufficient priviledges'})
class StopTest(ORequestHandler): + + @check_xsrf def delete(self, test_name): pass
@@ -199,6 +220,8 @@ def get_test_results(test_id): return test_results
class TestStatus(ORequestHandler): + + @check_xsrf def get(self, test_id): """ Returns the requested test_id details and the stored results for such