Foundations of Python Network Programming

(WallPaper) #1

Chapter 11 ■ the World Wide Web


200


They can attempt to forge the cookie by clicking through the correct privacy menus in their browser, or they can
attempt to access the site from Python. Using Requests, they might first see whether they can fetch the front page. An
unauthenticated request gets forwarded to the /login page, as one would expect.





import requests
r = requests.get('http://localhost:5000/')
print(r.url)
http://localhost:5000/login





But what if the bad guy inserts a cookie that makes it look like the brandon user has already logged on?




r = requests.get('http://localhost:5000/', cookies={'username': 'brandon'})
print(r.url)
http://localhost:5000/





Success! Because the site trusts that it set the value of this cookie, it is now responding to HTTP requests as
though they came from another user. All that the bad guy has to know is the username of another user of the payment
system, and they can forge a request to send money anywhere they want.





r = requests.post('http://localhost:5000/pay',
... {'account': 'hacker', 'dollars': 100, 'memo': 'Auto-pay'},
... cookies={'username': 'brandon'})
print(r.url)
http://localhost:5000/?flash=Payment+successful





It worked—$100 has now been paid from the brandon account to one under their control.
The lesson is that cookies should never be designed so that a user, on their own, could construct one. Assume
that your users are clever and will eventually catch on if all you are doing is obscuring their username with base-64
encoding, or swapping the letters around or performing a simple exclusive-or of the value with a constant mask. There
are three safe approaches to creating nonforgeable cookies.


•    You can leave the cookie readable but sign it with a digital signature. This leaves attackers
frustrated. They can see that the cookie has their username in it and will wish that they could
just rewrite the username with that of an account they want to hijack. But because they cannot
forge the digital signature to sign this new version of the cookie, they cannot convince your site
that the rewritten cookie is legitimate.

•    You can completely encrypt the cookie so that the user cannot even interpret its value. It will
appear as an opaque value that they cannot parse or understand.

•    You can create a purely random string for the cookie that has no inherent meaning, perhaps
using a standard UUID library, and save it in your own database so that you recognize the
cookie as belonging to the user when they make their next request. This persistent session
storage will need to be accessible to all of your front-end web machines if several successive
HTTP requests from the same user might wind up being forwarded to your different servers.
Some applications put sessions in their main database, while others use a Redis instance or
other shorter-term storage to prevent increasing the query load to their main persistent
data store.
Free download pdf