Skip to content

Commit b8dd6e4

Browse files
committed
gh-90309: Base64-encode cookie values embedded in JS
1 parent 9a1c70c commit b8dd6e4

File tree

3 files changed

+26
-13
lines changed

3 files changed

+26
-13
lines changed

Lib/http/cookies.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -391,17 +391,21 @@ def __repr__(self):
391391
return '<%s: %s>' % (self.__class__.__name__, self.OutputString())
392392

393393
def js_output(self, attrs=None):
394+
import base64
394395
# Print javascript
395396
output_string = self.OutputString(attrs)
396397
if _has_control_character(output_string):
397398
raise CookieError("Control characters are not allowed in cookies")
399+
# Base64-encode value to avoid template
400+
# injection in cookie values.
401+
output_encoded = base64.b64encode(output_string.encode('utf-8')).decode("ascii")
398402
return """
399403
<script type="text/javascript">
400404
<!-- begin hiding
401-
document.cookie = \"%s\";
405+
document.cookie = atob(\"%s\");
402406
// end hiding -->
403407
</script>
404-
""" % (output_string.replace('"', r'\"'))
408+
""" % (output_encoded,)
405409

406410
def OutputString(self, attrs=None):
407411
# Build up our result

Lib/test/test_http_cookies.py

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# Simple test suite for http/cookies.py
2-
2+
import base64
33
import copy
44
import unittest
55
import doctest
@@ -175,17 +175,19 @@ def test_load(self):
175175

176176
self.assertEqual(C.output(['path']),
177177
'Set-Cookie: Customer="WILE_E_COYOTE"; Path=/acme')
178-
self.assertEqual(C.js_output(), r"""
178+
cookie_encoded = base64.b64encode(b'Customer="WILE_E_COYOTE"; Path=/acme; Version=1').decode('ascii')
179+
self.assertEqual(C.js_output(), fr"""
179180
<script type="text/javascript">
180181
<!-- begin hiding
181-
document.cookie = "Customer=\"WILE_E_COYOTE\"; Path=/acme; Version=1";
182+
document.cookie = atob("{cookie_encoded}");
182183
// end hiding -->
183184
</script>
184185
""")
185-
self.assertEqual(C.js_output(['path']), r"""
186+
cookie_encoded = base64.b64encode(b'Customer="WILE_E_COYOTE"; Path=/acme').decode('ascii')
187+
self.assertEqual(C.js_output(['path']), fr"""
186188
<script type="text/javascript">
187189
<!-- begin hiding
188-
document.cookie = "Customer=\"WILE_E_COYOTE\"; Path=/acme";
190+
document.cookie = atob("{cookie_encoded}");
189191
// end hiding -->
190192
</script>
191193
""")
@@ -290,17 +292,19 @@ def test_quoted_meta(self):
290292

291293
self.assertEqual(C.output(['path']),
292294
'Set-Cookie: Customer="WILE_E_COYOTE"; Path=/acme')
293-
self.assertEqual(C.js_output(), r"""
295+
expected_encoded_cookie = base64.b64encode(b'Customer=\"WILE_E_COYOTE\"; Path=/acme; Version=1').decode('ascii')
296+
self.assertEqual(C.js_output(), fr"""
294297
<script type="text/javascript">
295298
<!-- begin hiding
296-
document.cookie = "Customer=\"WILE_E_COYOTE\"; Path=/acme; Version=1";
299+
document.cookie = atob("{expected_encoded_cookie}");
297300
// end hiding -->
298301
</script>
299302
""")
300-
self.assertEqual(C.js_output(['path']), r"""
303+
expected_encoded_cookie = base64.b64encode(b'Customer=\"WILE_E_COYOTE\"; Path=/acme').decode('ascii')
304+
self.assertEqual(C.js_output(['path']), fr"""
301305
<script type="text/javascript">
302306
<!-- begin hiding
303-
document.cookie = "Customer=\"WILE_E_COYOTE\"; Path=/acme";
307+
document.cookie = atob("{expected_encoded_cookie}");
304308
// end hiding -->
305309
</script>
306310
""")
@@ -391,13 +395,16 @@ def test_setter(self):
391395
self.assertEqual(
392396
M.output(),
393397
"Set-Cookie: %s=%s; Path=/foo" % (i, "%s_coded_val" % i))
398+
expected_encoded_cookie = base64.b64encode(
399+
("%s=%s; Path=/foo" % (i, "%s_coded_val" % i)).encode("ascii")
400+
).decode('ascii')
394401
expected_js_output = """
395402
<script type="text/javascript">
396403
<!-- begin hiding
397-
document.cookie = "%s=%s; Path=/foo";
404+
document.cookie = atob("%s");
398405
// end hiding -->
399406
</script>
400-
""" % (i, "%s_coded_val" % i)
407+
""" % (expected_encoded_cookie,)
401408
self.assertEqual(M.js_output(), expected_js_output)
402409
for i in ["foo bar", "foo@bar"]:
403410
# Try some illegal characters
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Base64-encode values when embedding cookies to JavaScript to avoid injection
2+
and escaping.

0 commit comments

Comments
 (0)