Flask cookies, when stored client-side, are .
-delimited, often zlib-deflated, and Base64-encoded with _
subbed in for /
and -
subbed in for +
(URL-safe encoding).
Let's take an example cookie from https://snowball2.kringlecastle.com/:
.eJy1kT8PgjAQxb9L5w7UIv9mNJoYB3UjDI1WJQE0IENj_O6WZxFQYhw0l7z23l1yvV-vJEz2-2RbpRdFAouSSS4ztRDqVF1IEEUWfYuYapf90WXdgDv8BqvX23WHe_tubHZdH5NzWa8aPaaNoBxqQ8da9aFPH5kHdaGOqXBkNnQMz0WHqztqbTyOzI7r8dMikfku_YJ2E_1Nf0v71W1ndml_dj_SbtZtgQ-jppFjgHsGF4f3QMxRYYDLAJcZuC3-9mNcfJajtX7BpipyEpBzKpQsCDWXeai9WXU4rkRenrKwUOVOpPJZX4pM6g7f9rjv-CNObncEAMTx.YaTaAA.SGRJEzFnk9BCtFwX-SmuSHrKofM
We can take the first piece (ignoring the signature) and store it as a variable in python3:
>>> cookie = "eJy1kT8PgjAQxb9L5w7UIv9mNJoYB3UjDI1WJQE0IENj_O6WZxFQYhw0l7z23l1yvV-vJEz2-2RbpRdFAouSSS4ztRDqVF1IEEUWfYuYapf90WXdgDv8BqvX23WHe_tubHZdH5NzWa8aPaaNoBxqQ8da9aFPH5kHdaGOqXBkNnQMz0WHqztqbTyOzI7r8dMikfku_YJ2E_1Nf0v71W1ndml_dj_SbtZtgQ-jppFjgHsGF4f3QMxRYYDLAJcZuC3-9mNcfJajtX7BpipyEpBzKpQsCDWXeai9WXU4rkRenrKwUOVOpPJZX4pM6g7f9rjv-CNObncEAMTx"
Then we import the libraries we need:
>>> import zlib; import itsdangerous
Then decode and decompress:
>>> zlib.decompress(itsdangerous.base64_decode(cookie))
And we get the resulting bytes:
b'{"Difficulty":0,"EnemyLayout":[[0,0,0,0,0,0,0,0,0,0],[0,1,0,0,0,0,0,0,0,0],[0,1,0,0,0,0,0,0,0,0],[0,1,0,0,0,0,0,0,0,0],[0,1,0,0,0,0,0,0,0,0],[0,1,0,1,1,1,1,1,1,1],[0,0,0,0,0,0,0,0,0,0],[0,0,0,1,1,1,1,1,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0]],"EnemyShips":[[[1,1],[2,1],[3,1],[4,1],[5,1]],[[5,9],[5,8],[5,7],[5,6]],[[5,3],[5,4],[5,5]],[[7,7],[7,6],[7,5]],[[7,3],[7,4]]],"FriendlyLayout":[[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,1,1,1,0,0],[0,1,0,0,0,0,0,0,0,0],[0,1,0,0,0,0,0,0,0,0],[0,1,0,0,0,0,0,0,0,0],[0,1,0,1,1,1,1,0,0,0],[0,1,0,1,0,0,0,0,1,0],[0,0,0,1,0,0,0,0,1,0],[0,0,0,1,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0]],"FriendlyShips":[[[2,1],[3,1],[4,1],[5,1],[6,1]],[[8,3],[7,3],[6,3],[5,3]],[[1,7],[1,6],[1,5]],[[5,4],[5,5],[5,6]],[[7,8],[6,8]]],"Turn":"player","playerID":"HughRansomDrysdale","playerName":"948396923"}'
Yay!
The same can be done with Cyber Chef:
- Put the cookie in the Input field
- Drag From Base64 and Zlib Inflate into the Recipe
- Set the Base64 alphabet to URL safe
- Bake and poof! You get Output like:
{"Difficulty":0,"EnemyLayout":[[0,0,0,0,0,0,0,0,0,0],[0,1,0,0,0,0,0,0,0,0],[0,1,0,0,0,0,0,0,0,0],[0,1,0,0,0,0,0,0,0,0],[0,1,0,0,0,0,0,0,0,0],[0,1,0,1,1,1,1,1,1,1],[0,0,0,0,0,0,0,0,0,0],[0,0,0,1,1,1,1,1,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0]],"EnemyShips":[[[1,1],[2,1],[3,1],[4,1],[5,1]],[[5,9],[5,8],[5,7],[5,6]],[[5,3],[5,4],[5,5]],[[7,7],[7,6],[7,5]],[[7,3],[7,4]]],"FriendlyLayout":[[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,1,1,1,0,0],[0,1,0,0,0,0,0,0,0,0],[0,1,0,0,0,0,0,0,0,0],[0,1,0,0,0,0,0,0,0,0],[0,1,0,1,1,1,1,0,0,0],[0,1,0,1,0,0,0,0,1,0],[0,0,0,1,0,0,0,0,1,0],[0,0,0,1,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0]],"FriendlyShips":[[[2,1],[3,1],[4,1],[5,1],[6,1]],[[8,3],[7,3],[6,3],[5,3]],[[1,7],[1,6],[1,5]],[[5,4],[5,5],[5,6]],[[7,8],[6,8]]],"Turn":"player","playerID":"HughRansomDrysdale","playerName":"948396923"}
Cyber Chef example here.
Aha - thank you both! I've also added the caveat that they are "often" zlib deflated. Developers who are more sparing with
session
in Flask may find theirs don't need compression. (-: