Merge lp:~ack/txaws/xss-hardening into lp:txaws

Proposed by Alberto Donato
Status: Merged
Merged at revision: 156
Proposed branch: lp:~ack/txaws/xss-hardening
Merge into: lp:txaws
Diff against target: 88 lines (+34/-8)
2 files modified
txaws/server/resource.py (+7/-6)
txaws/server/tests/test_resource.py (+27/-2)
To merge this branch: bzr merge lp:~ack/txaws/xss-hardening
Reviewer Review Type Date Requested Status
Fernando Correa Neto (community) Approve
txAWS Committers Pending
Review via email: mp+181562@code.launchpad.net

Description of the change

Based on Chris' branch lp:~tribaal/txaws/xss-hardening, drops the cgi.escape as json content shoudn't be escaped.

It also adds the "X-Content-Type-Options: nosniff" header, to prevent browsers from guessing the content type, and use the one declared in the response (application/json).

To post a comment you must log in.
Revision history for this message
Fernando Correa Neto (fcorrea) wrote :

+1

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'txaws/server/resource.py'
--- txaws/server/resource.py 2012-05-09 14:21:39 +0000
+++ txaws/server/resource.py 2013-08-22 14:02:04 +0000
@@ -94,6 +94,8 @@
94 def write_response(response):94 def write_response(response):
95 request.setHeader("Content-Length", str(len(response)))95 request.setHeader("Content-Length", str(len(response)))
96 request.setHeader("Content-Type", self.content_type)96 request.setHeader("Content-Type", self.content_type)
97 # Prevent browsers from trying to guess a different content type.
98 request.setHeader("X-Content-Type-Options", "nosniff")
97 request.write(response)99 request.write(response)
98 request.finish()100 request.finish()
99 return response101 return response
@@ -109,16 +111,15 @@
109 log.msg("status: %s message: %s" % (111 log.msg("status: %s message: %s" % (
110 status, safe_str(failure.value)))112 status, safe_str(failure.value)))
111113
112 bytes = failure.value.response114 body = failure.value.response
113 if bytes is None:115 if body is None:
114 bytes = self.dump_error(failure.value, request)116 body = self.dump_error(failure.value, request)
115 else:117 else:
116 log.err(failure)118 log.err(failure)
117 bytes = safe_str(failure.value)119 body = safe_str(failure.value)
118 status = 500120 status = 500
119 request.setResponseCode(status)121 request.setResponseCode(status)
120 request.write(bytes)122 write_response(body)
121 request.finish()
122123
123 deferred.addCallback(write_response)124 deferred.addCallback(write_response)
124 deferred.addErrback(write_error)125 deferred.addErrback(write_error)
125126
=== modified file 'txaws/server/tests/test_resource.py'
--- txaws/server/tests/test_resource.py 2012-05-09 14:21:39 +0000
+++ txaws/server/tests/test_resource.py 2013-08-22 14:02:04 +0000
@@ -120,8 +120,7 @@
120 "access_key_id": request.args["access_key"][0],120 "access_key_id": request.args["access_key"][0],
121 "signature_method": "Hmacsha256",121 "signature_method": "Hmacsha256",
122 "signature_version": 2,122 "signature_version": 2,
123 "signature": request.args["signature"][0],123 "signature": request.args["signature"][0]}
124 }
125 params = dict((k, v[-1]) for k, v in request.args.iteritems())124 params = dict((k, v[-1]) for k, v in request.args.iteritems())
126 raw = params.copy()125 raw = params.copy()
127 raw.pop("signature")126 raw.pop("signature")
@@ -153,6 +152,8 @@
153 self.assertEqual("data", request.response)152 self.assertEqual("data", request.response)
154 self.assertEqual("4", request.headers["Content-Length"])153 self.assertEqual("4", request.headers["Content-Length"])
155 self.assertEqual("text/plain", request.headers["Content-Type"])154 self.assertEqual("text/plain", request.headers["Content-Type"])
155 self.assertEqual(
156 "nosniff", request.headers["X-Content-Type-Options"])
156 self.assertEqual(200, request.code)157 self.assertEqual(200, request.code)
157158
158 self.api.principal = TestPrincipal(creds)159 self.api.principal = TestPrincipal(creds)
@@ -428,6 +429,30 @@
428429
429 return self.api.handle(request).addCallback(check)430 return self.api.handle(request).addCallback(check)
430431
432 def test_handle_error_is_api_content_type(self):
433 """
434 If an error occurs while parsing the parameters, L{QueryAPI.handle}
435 responds with HTTP status 400, and the resulting response has a
436 Content-Type header matching the content type defined in the QueryAPI.
437 """
438 creds = AWSCredentials("access", "secret")
439 endpoint = AWSServiceEndpoint("http://uri")
440 query = Query(action="SomeAction", creds=creds, endpoint=endpoint)
441 query.sign()
442 query.params.pop("Action")
443 request = FakeRequest(query.params, endpoint)
444
445 def check(ignored):
446 errors = self.flushLoggedErrors()
447 self.assertEquals(0, len(errors))
448 self.assertEqual(400, request.code)
449 self.assertEqual(
450 self.api.content_type, request.headers['Content-Type'])
451 self.assertEqual(
452 "nosniff", request.headers["X-Content-Type-Options"])
453
454 return self.api.handle(request).addCallback(check)
455
431 def test_handle_unicode_api_error(self):456 def test_handle_unicode_api_error(self):
432 """457 """
433 If an L{APIError} contains a unicode message, L{QueryAPI} is able to458 If an L{APIError} contains a unicode message, L{QueryAPI} is able to

Subscribers

People subscribed via source and target branches