0

There is my code:

class WebHandler(RequestHandler):

  def get(self):
    self.set_cookie('name1', 'value.1')
    self.set_cookie('name2', 'value.2')
    self.write('OK')

When I run this code, chrome browser doesn't set cookie 'name1' but still set cookie 'name2'. When I remove dot character in value of cookies, it's oke. How do I set multiple cookies with dot character in value?

  • This code works well in my environment - Python 2.7 and Tornado 4.4.2. I can see 2 `Set-Cookie` headers in the HTTP response and these 2 cookies are stored in browser eventually. Do you miss some interesting detail? Can you attach the HTTP response headers information? – shaochuancs Mar 20 '17 at 10:30
  • I use nginx as proxy, then header is modified as _Set-Cookie:name1=value.1; Path=/,name2=value.2; Path=/_ – Hub Nguyen Mar 20 '17 at 11:00
  • Combined `Set-Cookie` is deprecated now and many browsers does not support the syntax, refer to http://stackoverflow.com/questions/11533867/set-cookie-header-with-multiple-cookies – shaochuancs Mar 20 '17 at 11:16
  • Tornado does not use the combined `Set-Cookie` syntax; it puts each cookie on its own `Set-Cookie` line. There must be something else in the stack that is combining them; please show a *complete* example including the nginx config. – Ben Darnell Mar 25 '17 at 14:24
  • Thanks all. I resolved my problem. The error is in my proxy server. – Hub Nguyen Mar 27 '17 at 03:02

1 Answers1

1

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&rsquo;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.

Milovan Tomašević
  • 6,823
  • 1
  • 50
  • 42