<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/css" href="/stylesheets/rss.css"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/">
  <channel>
    <title>Wojno: Session of Fear</title>
    <link>http://christopher.wojno.com/articles/2007/08/10/session-of-fear</link>
    <language>en-us</language>
    <ttl>40</ttl>
    <description>Exploration through Code</description>
    <item>
      <title>Session of Fear</title>
      <description>&lt;p&gt;Now, before you think &amp;#8220;&lt;acronym title="Fear, Uncertainty, Disorder"&gt;FUD&lt;/acronym&gt; Time!&amp;#8221;, I preface this post with the following warning: Yes, this is a problem with not just Rails but all sessions; no, it&amp;#8217;s not unsolvable. So, in light of the bad news, there is much good news.&lt;/p&gt;


	&lt;h1&gt;The Problem&lt;/h1&gt;


	&lt;p&gt;&lt;a href="http://www.rubyonrails.org/"&gt;Rails&lt;/a&gt; applications are very useful. However, most require sessions in order to be useful. Sure, you can provide an &lt;a href="http://api.rubyonrails.org/classes/ActionWebService/Base.html"&gt;ActionWebService&lt;/a&gt; or &lt;span class="caps"&gt;REST&lt;/span&gt;-based service to not use sessions, but for the majority of user services, you&amp;#8217;re stuck with sessions.&lt;/p&gt;


	&lt;h2&gt;A Session About Sessions&lt;/h2&gt;


	&lt;p&gt;(Go ahead and skip this part if you&amp;#8217;re already familiar with how sessions work)&lt;/p&gt;


	&lt;p&gt;A session is a way a server remembers who you are (in case you didn&amp;#8217;t know). The most common way of allowing a server to ID you, without knowing who you are exactly, is by sharing a secret! Well, it&amp;#8217;s supposed to be secret and we&amp;#8217;ll come to that in a bit. When a new session is created, your session ID is generated (it&amp;#8217;s random, hopefully) and saved in the server. The id can be associated with other data, such as your name, or permissions. When you request a page, the server will give you this ID. You almost never see that ID because it&amp;#8217;s sent in the background as a &amp;#8220;cookie.&amp;#8221; You&amp;#8217;ve probably heard of these before. From now on, every time you request a page from the server, your cookie data is automatically included in the request (your web browser takes care of this) so the server can figure out who you are. Done correctly, no personally identifiable information is sent over the Web. Just your (hopefully) random ID.&lt;/p&gt;


	&lt;p&gt;Sounds good so far. But if you&amp;#8217;re not using &lt;span class="caps"&gt;HTTPS&lt;/span&gt; (SSL/TSL encryption), your secret contained in that cookie can be seen when it is first sent, and when you access any page thereafter (because you&amp;#8217;re sending it each time remember). So, if someone has access to your traffic (if you&amp;#8217;re using a shared WiFi or a hub or have a shady &lt;span class="caps"&gt;ISP&lt;/span&gt;), they can pull out your secret. Here&amp;#8217;s an old session I sniffed using a program called &lt;a href="http://www.snort.org/"&gt;snort:&lt;/a&gt;&lt;/p&gt;


&lt;pre style="overflow:auto;"&gt;
GET /javascripts/prototype.js?1186461045 HTTP/1.1..
Host: christopher.wojno.com..
User-Agent: Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.8.1.6) Gecko/20070810 Firefox/2.0.0.6..
Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5..Accept-Language: en-us,en;q=0.5..
Accept-Encoding: gzip,deflate..
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7..
Keep-Alive: 300..
Connection: keep-alive..
Cookie: _session_id=db392fa5b39125fa7c1e581b9c1ec71d; is_admin=yes....
&lt;/pre&gt;

	&lt;p&gt;There it is, the last line. &amp;#8220;Cookie.&amp;#8221; So when my browser was trying to download some javascript libraries (&lt;a href="http://www.prototypejs.org/"&gt;Prototype&lt;/a&gt; is quite good), it sent my session ID. Now, the javascript doesn&amp;#8217;t care about my session ID, but it was sent any way. If someone were to see that sent over the Internet (at any point on it&amp;#8217;s way to the server), he or she could create a fake cookie with that ID and login as me without my password! (don&amp;#8217;t try it, I&amp;#8217;ve already logged out and reset the session) They could then, go into the settings and lock me out of my own system (until I change the password in the ruby console&amp;#8230; that&amp;#8217;ll show &amp;#8216;em?). In the meantime, the damage has been done and it can happen again.&lt;/p&gt;


	&lt;h1&gt;&lt;span class="caps"&gt;SSL&lt;/span&gt;!&lt;/h1&gt;


	&lt;p&gt;I won&amp;#8217;t go into &lt;span class="caps"&gt;SSL&lt;/span&gt;, but that little piece of technology has enabled credit card purchases over the Internet for years and will hopefully continue to do so for years to come. Any way, in short, it&amp;#8217;s encryption and it will encrypt cookies too!&lt;/p&gt;


	&lt;p&gt;So, we need to force rails to encrypt cookies. Not as simple as it sounds. First, you need to setup an &lt;span class="caps"&gt;SSL&lt;/span&gt; certificate on your server. Easier said than done, though, some Apache packages come with the tools to automatically generate one. For a confusing, yet interesting read, see &lt;a href="http://en.wikipedia.org/wiki/X.509"&gt;&lt;span class="caps"&gt;X509&lt;/span&gt;&lt;/a&gt; on Wikipedia.&lt;/p&gt;


	&lt;p&gt;I assume you installed your &lt;span class="caps"&gt;SSL&lt;/span&gt; certificate and have configured &lt;a href="http://www.apache.org/"&gt;Apache&lt;sup&gt;&lt;a href="#fn1"&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/a&gt; to run with &lt;span class="caps"&gt;SSL&lt;/span&gt; (or &lt;a href="http://www.lighttpd.net"&gt;lighty,&lt;/a&gt; if you&amp;#8217;re using that instead (&lt;a href="http://mongrel.rubyforge.org/"&gt;mongrel&lt;/a&gt; is not mentioned as it does not have &lt;span class="caps"&gt;SSL&lt;/span&gt;, though there is a way to use &lt;span class="caps"&gt;SSL&lt;/span&gt; and mongrel together)). If not, there are loads of &lt;a href="http://www.google.com/search?hl=en&amp;#38;client=firefox-a&amp;#38;rls=org.mozilla%3Aen-US%3Aofficial&amp;#38;hs=Kie&amp;#38;q=apache+ssl+tutorial&amp;#38;btnG=Search"&gt;tutorials.&lt;/a&gt; I warn you though, it&amp;#8217;s fairly technical.&lt;/p&gt;


	&lt;h1&gt;Hold onto your Cookies!&lt;/h1&gt;


	&lt;p&gt;So, you have &lt;span class="caps"&gt;SSL&lt;/span&gt; and a Rails application running (I&amp;#8217;m assuming). How do you tell Rails to make sure your cookies are only sent via &lt;span class="caps"&gt;SSL&lt;/span&gt;? Rails lets you specify it.&lt;/p&gt;


	&lt;h2&gt;Tell Rails to use &lt;span class="caps"&gt;SSL&lt;/span&gt; Only&lt;/h2&gt;


	&lt;p&gt;By default, Rails does &lt;em&gt;&lt;span class="caps"&gt;NOT&lt;/span&gt;&lt;/em&gt; enforce &lt;span class="caps"&gt;SSL&lt;/span&gt; on cookies or sessions (that would be frustrating for development, wouldn&amp;#8217;t it?). So you have to enable that enforcement yourself. If you want your session cookie to be sent over &lt;span class="caps"&gt;SSL&lt;/span&gt; site-wide (and generally, you do!), head into your rails application directory and open (in your favorite editor) app/controllers/application.rb  Add the following anywhere in the ApplicationController class:&lt;/p&gt;


&lt;pre&gt;
class ApplicationController &amp;lt; ActionController::Base
  session :session_key =&amp;gt; '_session_id', :session_secure =&amp;gt; true
end
&lt;/pre&gt;

	&lt;p&gt;The ApplicationController class definition should already exist, don&amp;#8217;t duplicate it. Also, make sure that session isn&amp;#8217;t already specified. If it is, the important part here is &amp;#8221;:session_secure =&amp;gt; true&amp;#8221;. Rails will now tell the browser to only send the session cookie &lt;em&gt;if&lt;/em&gt; the browser is using the https  (SSL) protocol. This feature is poorly &lt;a href="http://api.rubyonrails.org/classes/ActionController/SessionManagement/ClassMethods.html"&gt;documented&lt;/a&gt; but hopefully this will help keep your applications that you write, safe. &lt;b&gt;&lt;span class="caps"&gt;NOTE&lt;/span&gt;: You &lt;em&gt;&lt;span class="caps"&gt;MUST&lt;/span&gt;&lt;/em&gt; use &lt;span class="caps"&gt;SSL&lt;/span&gt; if you enable this or your application will become extremely forgetful&lt;/b&gt; (Who are you? What are you doing in my kitchen?!).&lt;/p&gt;


	&lt;p&gt;If you&amp;#8217;re interested in storing &lt;span class="caps"&gt;OTHER&lt;/span&gt; data (not overly recommended though due to this and another exploit) in other cookies, Rails offers &lt;a href="http://api.rubyonrails.org/classes/ActionController/Cookies.html"&gt;cookie&amp;#8212;manipulation&lt;/a&gt; (not really management, the &lt;span class="caps"&gt;API&lt;/span&gt; leaves something to be desired). You can tell individual cookies to only be sent over encrypted connections, just like the session cookie. The other exploit: if the computer is shared and the browser doesn&amp;#8217;t clear out the cookies, the next person to sit at the computer can harvest the cookie information, so don&amp;#8217;t store passwords, e-mail addresses&amp;#8230; really anything in cookies, it&amp;#8217;s just a bad idea. DO store worthless information you don&amp;#8217;t want to save in your server, such as squirrel preferences.&lt;/p&gt;


	&lt;p&gt;Admittedly, generally the odds of someone having access to your network traffic (and your cookies, no! &lt;em&gt;MY&lt;/em&gt; cookies!) directly is moderate. For the attacker to successfully pick out your cookie data from the slew of traffic wizzing by, he/she would have to be looking and looking for a specific cookie name. So make sure no one has it out for you.&lt;/p&gt;


	&lt;p&gt;I don&amp;#8217;t mean to sound down on the Rails team. Dang-fine-job I say. Cookies aren&amp;#8217;t really important and the session is cookie-based, so session security falls by the way-side. It&amp;#8217;s up to all developers to keep his or her eyes open for potential pitfalls.&lt;/p&gt;


&lt;pre&gt;
1_000.thank( Rails::DevTeam.members.collect{|m|m.email} )
&lt;/pre&gt;

	&lt;p id="fn1"&gt;&lt;sup&gt;1&lt;/sup&gt; Note: Apache doesn&amp;#8217;t know how to run Ruby code as of this writing. You need to use an Apache&amp;#8217;s mod_proxy. This will (after it&amp;#8217;s been configured) then pass the requests from Apache, to &lt;a href="http://mongrel.rubyforge.org/"&gt;mongrel&lt;/a&gt;, &lt;a href="http://www.lighttpd.net"&gt;lighty&lt;/a&gt;, or&amp;#8230; WEBrick (if you&amp;#8217;re nuts)&lt;/p&gt;</description>
      <pubDate>Fri, 10 Aug 2007 16:48:00 -0700</pubDate>
      <guid isPermaLink="false">urn:uuid:360a7ead-402b-4c87-be50-8ade85a22381</guid>
      <author>Christopher Wojno</author>
      <link>http://christopher.wojno.com/articles/2007/08/10/session-of-fear</link>
      <category>Rails Snippets</category>
      <category>ruby</category>
      <category>rails</category>
      <category>ssl</category>
      <category>cookie</category>
      <category>session</category>
      <category>secure_session</category>
      <category>security</category>
      <category>hijack</category>
    </item>
    <item>
      <title>"Session of Fear" by Christopher Wojno</title>
      <description>&lt;p&gt;Sorry if I downplayed the importance of cookies; that&amp;#8217;s how I feel how cookies are being treated, not how I feel they ought to be treated.&lt;/p&gt;


	&lt;p&gt;I agree, this is a problem. But if I can help one person realize they might be affected by this, then isn&amp;#8217;t the world a better place? Alright, not really, but you get the idea. At the very least, most developers should have the ability to really control sessions (and cookies) now. Expand those horizons!&lt;/p&gt;


	&lt;p&gt;Good tip with the SSL requirement plugin. A+&lt;/p&gt;


	&lt;p&gt;Thanks&lt;/p&gt;</description>
      <pubDate>Mon, 13 Aug 2007 20:47:47 -0700</pubDate>
      <guid isPermaLink="false">urn:uuid:6056fe7b-25b2-42f0-bae7-4656eeeb97a0</guid>
      <link>http://christopher.wojno.com/articles/2007/08/10/session-of-fear#comment-9</link>
    </item>
    <item>
      <title>"Session of Fear" by Trevor Johns</title>
      <description>&lt;p&gt;First off, this is a very real vulnerability. Just head over to a &lt;a href="http://blogs.zdnet.com/Ou/?p=651" rel="nofollow"&gt;DEFCON conference&lt;/a&gt; if you need proof. It&amp;#8217;s actually a pretty well known attack vector.&lt;/p&gt;


	&lt;p&gt;That being said, I find this line misleading:&lt;/p&gt;


	&lt;blockquote&gt;
		&lt;p&gt;Cookies aren&#8217;t really important and the session is cookie-based, so session security falls by the way-side.&lt;/p&gt;
	&lt;/blockquote&gt;


	&lt;p&gt;Cookies are &lt;strong&gt;very&lt;/strong&gt; important, and I&amp;#8217;m sure the Rails devs know it. However, there&amp;#8217;s just no other technical way to prevent this short of using SSL/TLS and having your X.509 certificate signed by a trusted CA. Other frameworks are just as vulnerable to this. (There are some other ways to at least make things harder, like restricting the cookie by IP or rotating the cookie on every page view, but these all still have workarounds.)&lt;/p&gt;


	&lt;p&gt;So, why don&amp;#8217;t they just require encrypted traffic for everything? Because enabling SSL comes with a lot of overhead, on both ends of the connection. It really is up to the application developer to determine whether SSL is required. For example, It would be silly to encrypt every page on Slashdot just because I&amp;#8217;m logged in.&lt;/p&gt;


	&lt;p&gt;Finally, if you decide that you actually do need SSL, a better way to do this is to use the Rails &lt;a href="http://dev.rubyonrails.org/svn/rails/plugins/ssl_requirement/README" rel="nofollow"&gt;ssl_requirement plugin&lt;/a&gt;. If a user arrives via unsecured HTTP, they&amp;#8217;re silently redirected to an HTTPS version of the page.&lt;/p&gt;</description>
      <pubDate>Mon, 13 Aug 2007 12:43:04 -0700</pubDate>
      <guid isPermaLink="false">urn:uuid:5826d4bc-1552-4b0b-9991-aa8d668cddb1</guid>
      <link>http://christopher.wojno.com/articles/2007/08/10/session-of-fear#comment-6</link>
    </item>
  </channel>
</rss>
