From my point of view, it is possible that the question is a bit incomplete, but I will still try to answer it in the hope that it will help you and others.
Tornado’s set_secure_cookie()
and get_secure_cookie()
functions send and retrieve browser cookies that are protected against malicious modifications in the browser. To use these functions, you must specify the cookie_secret
parameter in the application constructor. Let’s look at a simple example.
The application will render a page that counts how many times it has been reloaded in the browser. If no cookie has been set (or if the cookie has been tampered with), the application will set a new cookie with the value 1. Otherwise, the application will increment the value read from the cookie.
import tornado.httpserver
import tornado.ioloop
import tornado.web
import tornado.options
from tornado.options import define, options
define("port", default=8000, help="run on the given port", type=int)
class MainHandler(tornado.web.RequestHandler):
def get(self):
cookie = self.get_secure_cookie("count")
count = int(cookie) + 1 if cookie else 1
countString = "1 time" if count == 1 else "{} times".format(count)
self.set_secure_cookie("count", str(count))
self.write(
"""
<html><head><title>Cookie Counter</title></head>
<body><h1>You’ve viewed this page {} times.</h1>
</body></html>
""".format(
countString
)
)
if __name__ == "__main__":
tornado.options.parse_command_line()
settings = {
"cookie_secret": "u5SXVuerTfyQTT7uTbu7HjqiqHnh8UsBm37J4Y5lwto="
}
application = tornado.web.Application([(r"/", MainHandler)], **settings)
http_server = tornado.httpserver.HTTPServer(application)
http_server.listen(options.port)
try:
tornado.ioloop.IOLoop.instance().start()
except KeyboardInterrupt:
print("Server has shut down.")
If you inspect the value of the cookie in the browser, you will notice that the value stored for count is "count=\"2|1:0|10:1612910394|5:count|4:MQ==|e8c35def2daaec8da8ca5f3f1db63168f97027024a824d17b5e405f4f97c26ce\""
. Tornado encodes the cookie value as a Base-64 string and appends a timestamp and an HMAC signature to the cookie contents. If the cookie’s timestamp is too old (or from the future), or if the signature doesn’t match the expected value, the get_secure_cookie()
function assumes the cookie has been tampered with and will return None
, as if the cookie had not been set.
The cookie_secret
value passed to the Application
constructor should be a unique, random string. Executing the following code snippet in a Python shell will generate one for you:
>>> import base64, uuid
>>> base64.b64encode(uuid.uuid4().bytes + uuid.uuid4().bytes)
b'KeQWrXgiTjWQIEzcRbx0vV/IM/mYAEqvs+EtZ/5dvfs='
Tornado’s secure cookies are still susceptible to snooping, however. Attackers may be able to intercept cookies via scripts or plug ins in the browser, or simply by eavesdropping unencrypted network data. Remember that cookie values are signed rather than encrypted. Malicious programs are able to read stored cookies and either transmit their data to arbitrary servers or forge requests by sending them unmodified to the application. Therefore, it’s important to avoid storing sensitive user data in a browser cookie.
We also need to be aware of the possibility that a user could modify his own cookies, which could lead to a privilege escalation attack. If, for example, we store the number of remaining articles a user has paid to view in a cookie, we would want to prevent the user from updating that number himself in an attempt to get free content. The httponly
and secure
cookie properties can help prevent these sorts of attacks.
Setting the secure attribute on a cookie instructs the browser to transfer the cookie only over SSL connections. (It’s a little confusing, but this is not the same as Tornado’s secure cookies, which are more accurately described as signed cookies.) Since Python version 2.6, the Cookie
object also supports the httponly
attribute. Including this attribute instructs the browser to make the cookie inaccessible to JavaScript, which can prevent cross-site scripting attacks from reading the cookie’s value.
To enable these features, you can pass keyword arguments to the set_cookie
and
set_secure_cookie
methods. For example, a secure, HTTP-only cookie (that’s not
signed by Tornado) could be sent with the call:
self.set_cookie('foo', 'bar', httponly=True, secure=True)
Since the Tornado comes with built-in XSRF protection. For more details on this, see the official documentation, you can also see one of my answers in which it is set "xsrf_cookies": True
.