Tornado – Secure Cookies

Well, as we read about cookies in the previous post, we can also say cookies help in tracking users, understanding their preferences and browsing activities. Cookies thus provide continuity and state
across HTTP connections which we explained with users browsing through different pages without losing out information they posted.

All’s good, but the threat lies in web servers accessing these cookies (stored at client’s location) to get personal and confidential information like Credit Card numbers or passwords. Cookies are readable in clear text and can be easily used for forging clients. The way out is to have secure web cookies and guess what, Tornado is again happy to help! 🙂

In the example, below, Tornado uses methods get_secure_cookie and set_secure_cookie to get and set secure cookies and uses a cookie key that is specified with cookie_secret when an application is created. Signed cookies contain the encoded value in addition to a timestamp and an HMAC signature. Also, by default, Tornado creates secure cookies with an expiry of 1month.

A Secure Cookie looks like this:

technobeans=”MTM0NDM1OTA5NS4yOQ==|1344359095|be3d68ebe6251359e9f8bade853ca99c93ff1daa”; expires=Thu, 06 Sep 2012 17:04:55 GMT; Path=/

Example

import httplib2
h = httplib2.Http()
response, content = h.request("http://127.0.0.1:8888/user/", "GET")
print"HTTP GET request"
print "Reponse:", response, "\nContent:", content, "\nCookie:", response['set-cookie']
## Resending the request with cookie with headers
headers = {"Cookie":response['set-cookie']}
response_2, content_2 = h.request("http://127.0.0.1:8888/user/", "GET", headers = headers)
print "\nResending the request with cookie in headers"
print "Reponse:", response_2, "\nContent:", content_2

view raw
request.py
hosted with ❤ by GitHub

ubuntu@ubuntu:~/tornado-2.2$ python request.py
HTTP GET request
Reponse: {'status': '200', 'content-length': '17', 'content-location': 'http://127.0.0.1:8888/user/', 'set-cookie': 'technobeans="MTM0NDM1OTA5NS4yOQ==|1344359095|be3d68ebe6251359e9f8bade853ca99c93ff1daa"; expires=Thu, 06 Sep 2012 17:04:55 GMT; Path=/', 'server': 'TornadoServer/2.2', 'etag': '"25dcbbc84ce1fedc0d4bc15abdc23c4abb1a4006"', 'content-type': 'text/html; charset=UTF-8'}
Content: Secure Cookie is now set
Cookie: technobeans="MTM0NDM1OTA5NS4yOQ==|1344359095|be3d68ebe6251359e9f8bade853ca99c93ff1daa"; expires=Thu, 06 Sep 2012 17:04:55 GMT; Path=/
Resending the request with cookie in headers
Reponse: {'status': '200', 'content-length': '21', 'content-location': 'http://127.0.0.1:8888/user/', 'server': 'TornadoServer/2.2', 'etag': '"95bb30558d14b3d9eb37a1f1fccc5c84f546ce3a"', 'content-type': 'text/html; charset=UTF-8'}
Content: Secure Cookie is technobeans

view raw
response.txt
hosted with ❤ by GitHub

import tornado.ioloop
import tornado.web
import time
class Hello(tornado.web.RequestHandler):
def get(self):
self.write("Hello there")
class User(tornado.web.RequestHandler):
def get(self):
cookieName = "technobeans"
if not self.get_secure_cookie(cookieName):
self.set_secure_cookie(cookieName, str(time.time()))
self.write("Secure Cookie is now set")
else:
self.write("Secure Cookie is " + cookieName)
application = tornado.web.Application([
(r"/", Hello),
(r"/user/", User),
], cookie_secret="61oETzKXQAGaYdkL5gEmGeJJFuYh7EQnp2XdTP1o/Vo=")
if __name__ == "__main__":
application.listen(8888)
tornado.ioloop.IOLoop.instance().start()

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.