Security Vulnerability with Django Cookie-Based Sessions

UPDATE: Django updated their documentation to include a warning about this risk: “Unlike other session backends which keep a server-side record of each session and invalidate it when a user logs out, cookie-based sessions are not invalidated when a user logs out. Thus if an attacker steals a user’s cookie, he can use that cookie to login as that user even if the user logs out.”

OSVDB catalogued the vulnerability and Threatpost covered it in an article.


Django has a session invalidation security vulnerability like the Ruby on Rails vulnerability I wrote about here.

Django is a free and open source Web application framework that is written in Python. Django version 1.4 introduced cookie-based session storage and Django version 1.7 is currently under development.


Django provides options for how and where user session data is stored. One of those options is cookie-based storage, which stores all session data in the cookie and signs it.

Without access to the app’s code, detecting which session storage mechanism is in use is slightly harder than with the similar Rails vulnerability. With Django, the default name for a session cookie is “sessionid” regardless of whether the cookie stores only a session identifier or the complete session data hash. So, you’ll need to examine the value of the cookie to determine which session storage mechanism may be in use for a given application.

The Impact

When using Django cookie-based session storage in your Web app, if someone were to find, steal, or intercept a user’s cookie they could log into your website as that user even if that user had logged out.

The main difference from the Rails session security vulnerability is that Django does not use cookie-based sessions by default.

I found most developers are completely shocked to learn about this kind of behavior. I believe this is a risk that was written off without adequate documentation or warning.

Happy hacking! Email me with questions:


Logout is broken by default in Ruby on Rails Web applications

UPDATE: This issue has received press coverage and made it into the Open Sourced Vulnerability Database (OSVDB) available at I will follow up on this post with more technical details as well as my research results from studying this issue in the wild.


Ruby on Rails Web applications versions 2.0 through 4.0 are by default vulnerable to an oft-overlooked Web application security issue: Session cookies are valid for life.* The fix is to configure your Rails app to store most session information on the server side in the database.


The default Rails session storage mechanism is the CookieStore, which holds the entire user session hash on the client side in the Web browser as a cookie. In this configuration there is no entry in a “sessions” database table for your Rails app to delete upon logout.

My concern is more than just current session hijacking via Firesheep or similar; a malicious user could use the stolen cookie from any authenticated request by the user to log in as them at any point in the future.

When a user logs out what happens is not what you would expect. Again, no entry in a “sessions” table exists to delete. Instead, Rails will issue a new, empty-ish cookie to the user’s browser in order to overwrite the one granted when the user originally authenticated, and instruct the Web browser to use this newest one from this point forth. This relies on good browser behavior. But remember, the previous cookie is still valid. There is no way to invalidate these old cookies upon sign out with the default Rails configuration. In addition to network snooping (session sidejacking) and XSS, this presents a problem for users accessing your site via a shared or public computer, or perhaps over a faulty network connection that might drop the very last HTTP response requesting that the user’s browser overwrite the stored authenticated cookie. Also, when your users forget to logout, they will not be able to log themselves out of that living session from a different computer, and anyone who discovers the stored cookie can use it indefinitely.

The default cookie name is:


And before Base64 encoding and URL encoding, the cookie value may look something like this with actual values for “[String]”:

{ I"session_id:EF"%[String]I"_csrf_token;FI"1[String]=;FI"user_credentials;FI"[String];TI"user_credentials_id;Fi

While Rails 4 switched to encrypting the value of the cookie, doing so does not eliminate this issue.

Separately, it is a good design for your Web app to require that the user supply their current password before changing sensitive fields such as password or email address. If the CookieStore-stored session were to be hijacked, the malicious user could change the user’s password: 1) immediately invalidating the legitimate user’s cookie and thus slamming your app’s doors in their face and 2) disallowing the legitimate user the ability to log back into their account.

A note about a red herring: if you use the Authlogic gem you may notice a field called “persistence_token” in your users table and believe that you are already using server-side storage for most of your session data. In my testing of the default CookieStore configuration, the field did not appear to serve a purpose.


Switch to ActiveRecordStore or something else from this list. Switching away from CookieStore is said to be slower. After switching, the cookie will contain a value for “session_id” which corresponds to an entry in your database’s sessions table. You will need to keep in mind replicating session data across multiple databases if you have more than one active behind a load balancer.

Happy hacking! Email me with questions:

*In my testing, the only methods to invalidate these cookies are for the user to change their password or for systems administrators to change the application secret. Both are infrequent occurrences.


Injecting yourself into email threads without an invitation #partycrashing

You probably trust that emails within a thread belong together, right?

Injecting yourself into Gmail threads is like rudely butting into a conversation at a cocktail party. Here we’ll go over how, with two pieces of data, you can inject yourself into the existing email thread of a target person. While not earth-shattering information, this technique can perhaps be leveraged for social engineering, during a penetration test, or while on a phishing expedition.

You need to know the subject line and Message-ID of an email in the thread that you want to inject yourself into. Armed with these two, you can join in the threaded conversation from the outside, and a rushed or unobservant office worker may not notice that you do not belong in that conversation. The subject line is what you’re accustomed to setting when you write in a subject for an email. As it turns out, you are even able to get away with similar subject lines in Gmail: “test” and “Re: test” will both work in this case. Apparently there is some leeway here and other variants work as well. The Message-ID is a globally unique identifier of the digital message, is part of the email header, is typically not viewable to the user, and is automatically generated for the domain where the email was generated. For Gmail, that would be within the “” domain.

Obtain (by whatever your means) the Message-ID of an existing message in the target thread, and place it into both the “In-Reply-To” and “References” fields of the email header of an email that you will craft specially. For more information about the purpose of these two fields, read the full RFC here:

Now, I do not believe that you can edit email headers through Gmail’s Web interface or through a client such as Thunderbird, but here is a Python script that you can use to send email through a Gmail account you control to your target. This script has been configured for Gmail but can be modified to use other SMTP servers if you wish.

import os
import smtplib
import mimetypes
from email.MIMEMultipart import MIMEMultipart
from email.MIMEBase import MIMEBase
from email.MIMEText import MIMEText
from email.MIMEAudio import MIMEAudio
from email.MIMEImage import MIMEImage
from email.Encoders import encode_base64

def sendMail(yourEmail, yourPassword, subjectLine, bodyText,
  targetEmail, messageID, *attachmentFilePaths):
  gmailUser = yourEmail
  gmailPassword = yourPassword
  recipient = targetEmail
  msg = MIMEMultipart()
  msg['From'] = gmailUser
  msg['To'] = recipient
  msg['Subject'] = subjectLine
  msg['In-Reply-To'] = messageID
  msg['References'] = messageID
  for attachmentFilePath in attachmentFilePaths:
  mailServer = smtplib.SMTP('', 587)
  mailServer.login(gmailUser, gmailPassword)
  mailServer.sendmail(gmailUser, recipient, msg.as_string())
  print('Sent email to %s' % recipient)

def getAttachment(attachmentFilePath):
  contentType, encoding = mimetypes.guess_type(attachmentFilePath)
  if contentType is None or encoding is not None:
    contentType = 'application/octet-stream'
  mainType, subType = contentType.split('/', 1)
  file = open(attachmentFilePath, 'rb')
  if mainType == 'text':
    attachment = MIMEText(
  elif mainType == 'message':
    attachment = email.message_from_file(file)
  elif mainType == 'image':
    attachment = MIMEImage(,_subType=subType)
  elif mainType == 'audio':
    attachment = MIMEAudio(,_subType=subType)
    attachment = MIMEBase(mainType, subType)
  attachment.add_header('Content-Disposition', 'attachment',
  return attachment

if __name__ == "__main__":
#Edit the following arguments with your values
  sendMail("yourEmail", "yourPassword", "test",
    "Hello, thread.", "targetEmail",

The important take away from all this is that you can insert your email into a thread that you were not privy to in the first place, and you do not even have to send your message from an email address within the same domain as the recipient(s). Shout out to @baffles for pointing me to the correct parts of the RFC to focus on for this and for testing this out with me.

Caveats and things to note:

  • This has only really been tested briefly with Gmail
  • You can modify this script to supply multiple values to “References” but I do not know the pros and cons of doing so
  • How Message-ID is generated will be the subject of future research

First iPhone 5 broken in 4 days or less

As far as eBay auctions go in the U.S., the first iPhone 5 with a cracked screen surfaced not even four full days after the phone was released to the market.

A seller from New Jersey wins the title for being the first to break an iPhone 5 and appears to be an individual–not a powerseller that got their hands on a shipment of broken phones.

4 days … that is skillful. Even more so: taking into account the possibility that the owner may not have even gotten the phone the instant it came out and that they probably did not list it for sale the second it got smashed, they may have owned it for even less than ~4 days.

It must have been a wild weekend, but for a final difference of $60 the damage to the wallet was less than it could have been.


Make your mornings suck less with a alarm clock (for Mac)

I don’t do mornings. I really don’t. I’ll stay up until them, sure, but I do not want to wake up to them.

Using OS X Mountain Lion, here we go: for the impatient, just read the bold.

Edit: I realize that bold doesn’t show up well with my current configuration. I’ll work on that.

  1. Visit in your default web browser, which will be the same browser that the following alarm clock script will work with, sign in to your Pandora account, and choose the radio station you want to play every AM. I play general Trip Hop, but that’s just me. Close Pandora, but DO NOT LOG OUT of your account.
  2. Fire up Automater (it’s included with the OS) and create a new Calendar Alarm.
  3. For your first Automator Workflow step, Select Actions > Utilities > Set Computer Volume.
  4. Set your Output volume where you like. I set mine as follows: Output volume: 50%; Alert volume: 0%; Input volume: 0%. I didn’t want to be jolted out of bed.
  5. For the next step in your Workflow, choose: Actions > Internet > Get Specified URLs.
  6. Change the “” to “”
  7. For your last Workflow step, select: Actions > Internet > Display Webpages. Your Workflow should now resemble this:
  8. Screenshot of the Automator Workflow to launch as a morning alarm clock
  9. At this point you are done editing your Workflow. (Hooray beer!) Chose File > Save and give your Calendar Alarm a descriptive name. Once saved, the native Calendar application should fire up and you should see your Alarm in the current day. You should also see the “Automator” calendar under “On My Mac.”
  10. Specify the time that you want your Internet radio to start playing by right-clicking on the Alarm, choosing Get Info and setting the time. Also set “repeat” to “Every day” or whatever works for you. If you only work every other day, week, or month, that’s awesome.

Protip: To reduce clutter in the Calendar app you can uncheck the box next to the Automator to hide it. The Alarm should still go off as scheduled (it did during my testing). Or use Google Calendar for all your events and meetings. Also, if your default web browser (USE CHROME!) is already running when your alarm goes off–which is the case for me because I always have an obsessive amount of tabs open even though I use Pocket–this script will simply spawn a new tab. If you already have Pandora running, I have no idea what will happen. Good luck brave soul.

After looking through other Automator actions it appears that you could also do this with an iTunes playlist (and a lot of other applications), but I haven’t tried anything out other than what is above out so you will have to DIY. There was also some talk on the ‘net about using Pandora’s desktop application (via Adobe Air) for this. If you used launchd instead, awesome. Tell us about it. Post your solution in the comments.

Note that the first step you created in the Automator Workflow controls the volume of your Mac. If you are using external speakers with their own volume control (like I am) then you will need to adjust those to your liking as well.

Site update: This is the first post in the Life Automation series that I hope to continue posting to. I had an awesome boss that was the master of automation and he got me hooked on attempting to automate everything in life.

Once you’re out of bed, get some Powerthirst.

Disclaimer: Just bought a Mac so this may not be the most optimal way to go about doing this.


Anti-abortion Georgia is really curious about where to find abortion clinics

While I was doing some SEO work late last night for an Inc.less ( client, I got a little curious–probably given the current political atmosphere. I decided to take a glance at Google search volume by specific region using Google Insights for Search on a controversial subject: abortion. Here are the states that really want to know “where to get an abortion.”

Google Insights for search volume by region for abortion clinic locations

The darker the color, the more searches are being done

Now to be scientific about this, I’m not sure if this reflects an interest among people in Georga in locating clinics in order to use their services or to protest in front of them, but I still find it ironic.

… and the Dirty Little Secret song that popped into my head upon realizing this curiosity will not leave my brainspace.


A Dictionary with Google Images for Definitions

As reported by TechCrunch, two artists have taken the thousands of terms from your average dictionary and defined them with words pictures. In an automated manner they scraped the first image result from Google Images for a given term and created a physical book.

Google Images Dictionary

So what if the images are not the best representation of the term or if the images become obsolete the second the dictionary is printed? It’s simply beautiful and a great reflection of today’s Internet culture. I can’t wait to get my copy.


Facebook is having a rough day

Facebook doesn’t go down … ever.

As reported, Facebook is experiencing technical issues today. This is very usual. Twitter blew up with tweets about the issues.

Loading comments for the wrong pictures, messages being dropped, everything being unbearably slow are all the more obvious symptoms. As my friend put it, “Pages load like they did in 1994.”

But, I also noticed something more subtle:

Facebook Shared Link Algorithm Fail

Notice that the “link” referenced by Facebook as supposedly being shared by both Lifehacker and Kogeto? Yea, the links published by the two users are different.

I got trapped in an elevator leaving the office today. Not a great day for technology all around.



Image Not Displayed In Internet Explorer 7 – Red X

Are you not seeing pictures in Internet Explorer, but instead getting a red X? It could be due to a number of factors, including “Show Pictures” not checked in Internet Options, or sloppy XHTML coding (make sure to close your tags). But this was not the case for me. Everything was working perfectly in Mozilla (which I use primarily), but I was just double checking in other browsers. Here is the reason:


Interesting. I could not find that answer anywhere on the net, but decided to start back at the beginning in Adobe Photoshop CS4. Reopened the JPEG (seen below) and noticed that it was still in the CMYK color model because I was working on business card designs for commercial print.

Be sure to transform your images back into RGB if they will be viewed on the net or in IE7 (or probably any version of I.E. for that matter). This is also important if there is the possibility that your client uses Internet Explorer to preview images.

Pretty cool design I was working on last night for myself, and the cause of today’s troubles.
Click for larger view with subtle details.
G. S. McNamara Company Logo

Need a business card designed? Request An Estimate.

Catch my latest post: RSS Feed
Email Me

Color Isolation in Grayscale, Signature, and Business Card with Mirror Effect in Photoshop

Had a bit of fun in Photoshop recently. Tested out how to correctly isolate certain colors in an image and change the rest to gray scale. I was also was able to scan in my signature, clean it up, vectorize it, and make it a custom shape for use in work down the road. Finally, I delved into the mirror effect that is now pretty popular for text and images. I’ll use it on the front of my business card.

Porsche in red.
This image is also viewable on my deviantART page. I will probably upload most of my work there in the future.

I had to track down this font from GIMP 2.6 and install it for use in Photoshop. Now to find a printer for these business cards . . .

Web 2.0 Business Card

Grab a copy of Photoshop for yourself and give it a try.

Catch my latest post: RSS Feed
Email Me