1
0
Fork 0
mirror of https://github.com/rails/rails.git synced 2022-11-09 12:12:34 -05:00

Added support for HTTP Only cookies (works in IE6+ and FF 2.0.5+) as an improvement for XSS attacks (closes #8895) [lifo/Spakman]

git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@7525 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
This commit is contained in:
David Heinemeier Hansson 2007-09-21 15:05:49 +00:00
parent 26238ac173
commit eede82ccb9
4 changed files with 37 additions and 37 deletions

View file

@ -1,5 +1,7 @@
*SVN*
* Added support for HTTP Only cookies (works in IE6+ and FF 2.0.5+) as an improvement for XSS attacks #8895 [lifo/Spakman]
* Don't warn when a path segment precedes a required segment. Closes #9615. [Nicholas Seckar]
* Fixed CaptureHelper#content_for to work with the optional content parameter instead of just the block #9434 [sandofsky/wildchild].

View file

@ -3,6 +3,9 @@ CGI.module_eval { remove_const "Cookie" }
# TODO: document how this differs from stdlib CGI::Cookie
class CGI #:nodoc:
class Cookie < DelegateClass(Array)
attr_accessor :name, :value, :path, :domain, :expires
attr_reader :secure, :http_only
# Create a new CGI::Cookie object.
#
# The contents of the cookie can be specified as a +name+ and one
@ -19,7 +22,9 @@ class CGI #:nodoc:
# secure:: whether this cookie is a secure cookie or not (default to
# false). Secure cookies are only transmitted to HTTPS
# servers.
#
# http_only:: whether this cookie can be accessed by client side scripts (e.g. document.cookie) or only over HTTP
# More details: http://msdn2.microsoft.com/en-us/library/system.web.httpcookie.httponly.aspx
# Defaults to false.
# These keywords correspond to attributes of the cookie object.
def initialize(name = '', *value)
if name.kind_of?(String)
@ -28,6 +33,7 @@ class CGI #:nodoc:
@domain = nil
@expires = nil
@secure = false
@http_only = false
@path = nil
else
@name = name['name']
@ -35,12 +41,11 @@ class CGI #:nodoc:
@domain = name['domain']
@expires = name['expires']
@secure = name['secure'] || false
@http_only = name['http_only'] || false
@path = name['path']
end
unless @name
raise ArgumentError, "`name' required"
end
raise ArgumentError, "`name' required" unless @name
# simple support for IE
unless @path
@ -55,45 +60,26 @@ class CGI #:nodoc:
@_dc_obj = obj
end
attr_accessor("name", "value", "path", "domain", "expires")
attr_reader("secure")
# Set whether the Cookie is a secure cookie or not.
#
# +val+ must be a boolean.
def secure=(val)
@secure = val if val == true or val == false
@secure
@secure = val == true
end
# Set whether the Cookie is an HTTP only cookie or not.
def http_only=(val)
@http_only = val == true
end
# Convert the Cookie to its string representation.
def to_s
buf = ""
buf = ''
buf << @name << '='
if @value.kind_of?(String)
buf << CGI::escape(@value)
else
buf << @value.collect{|v| CGI::escape(v) }.join("&")
end
if @domain
buf << '; domain=' << @domain
end
if @path
buf << '; path=' << @path
end
if @expires
buf << '; expires=' << CGI::rfc1123_date(@expires)
end
if @secure == true
buf << '; secure'
end
buf
buf << (@value.kind_of?(String) ? CGI::escape(@value) : @value.collect{|v| CGI::escape(v) }.join("&"))
buf << '; domain=' << @domain if @domain
buf << '; path=' << @path if @path
buf << '; expires=' << CGI::rfc1123_date(@expires) if @expires
buf << '; secure' if @secure
buf << '; HttpOnly' if @http_only
end
# Parse a raw cookie string into a hash of cookie-name=>Cookie

View file

@ -23,7 +23,9 @@ module ActionController #:nodoc:
# * <tt>domain</tt> - the domain for which this cookie applies.
# * <tt>expires</tt> - the time at which this cookie expires, as a +Time+ object.
# * <tt>secure</tt> - whether this cookie is a secure cookie or not (default to false).
# Secure cookies are only transmitted to HTTPS servers.
# Secure cookies are only transmitted to HTTPS servers.
# * <tt>http_only</tt> - whether this cookie is accessible via scripting or only HTTP (defaults to false).
module Cookies
protected
# Returns the cookie container, which operates as described above.

View file

@ -32,6 +32,10 @@ class CookieTest < Test::Unit::TestCase
render :text => "hello world"
end
def authenticate_with_http_only
cookies["user_name"] = { :value => "david", :http_only => true }
end
def rescue_action(e)
raise unless ActionController::MissingTemplate # No templates here, and we don't care about the output
end
@ -60,6 +64,12 @@ class CookieTest < Test::Unit::TestCase
assert_equal [ CGI::Cookie::new("name" => "user_name", "value" => "david", "expires" => Time.local(2005, 10, 10)) ], @response.headers["cookie"]
end
def test_setting_cookie_with_http_only
get :authenticate_with_http_only
assert_equal [ CGI::Cookie::new("name" => "user_name", "value" => "david", "http_only" => true) ], @response.headers["cookie"]
assert_equal CGI::Cookie::new("name" => "user_name", "value" => "david", "path" => "/", "http_only" => true).to_s, @response.headers["cookie"].to_s
end
def test_multiple_cookies
get :set_multiple_cookies
assert_equal 2, @response.cookies.size