<h1>New post</h1> + +<%= render :partial => "form" %> + +<%= link_to 'Back', posts_path %>+
diff --git a/railties/doc/guides/html/2_2_release_notes.html b/railties/doc/guides/html/2_2_release_notes.html index c657be20b4..d21905f715 100644 --- a/railties/doc/guides/html/2_2_release_notes.html +++ b/railties/doc/guides/html/2_2_release_notes.html @@ -586,16 +586,15 @@ by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite -->
class Photo < ActiveRecord::Base - belongs_to :Product + belongs_to :product end class Product < ActiveRecord::Base - has_many :products + has_many :photos end # Get all products with copyright-free photos: -Product.find(:all, :joins => :photo, - :conditions => { :photos => { :copyright => false }}) +Product.all(:joins => :photos, :conditions => { :photos => { :copyright => false }})
+More information: +
+ +The Layouts & rendering guide explains this in more detail.
The Layouts & rendering guide explains this in more detail.
For example, to a Rails application a request such as this:
DELETE /photos/17
would be understood to refer to a photo resource with the ID of 17, and to indicate a desired action - deleting that resource. REST is a natural style for the architecture of web applications, and Rails makes it even more natural by using conventions to shield you from some of the RESTful complexities.
If you’d like more details on REST as an architectural style, these resources are more approachable than Fielding’s thesis:
+A Brief Introduction to REST by Stefan Tilkov +
++An Introduction to REST (video tutorial) by Joe Gregorio +
++Representational State Transfer article in Wikipedia +
+The destroy method of an Active Record model instance removes the corresponding record from the database. After that's done, there isn't any record to display, so Rails redirects the user's browser to the index view for the model.
At this point, it’s worth looking at some of the tools that Rails provides to eliminate duplication in your code. In particular, you can use partials to clean up duplication in views and filters to help with duplication in controllers.
As you saw earlier, the scaffold-generated views for the new and edit actions are largely identical. You can pull the shared code out into a partial template. This requires editing the new and edit views, and adding a new template:
new.html.erb: +[source, ruby]
<h1>New post</h1> + +<%= render :partial => "form" %> + +<%= link_to 'Back', posts_path %>+
edit.html.erb: +[source, ruby]
<h1>Editing post</h1> + +<%= render :partial => "form" %> + +<%= link_to 'Show', @post %> | +<%= link_to 'Back', posts_path %>+
_form.html.erb: +[source, ruby]
<% form_for(@post) do |f| %> + <%= f.error_messages %> + + <p> + <%= f.label :name %><br /> + <%= f.text_field :name %> + </p> + <p> + <%= f.label :title, "title" %><br /> + <%= f.text_field :title %> + </p> + <p> + <%= f.label :content %><br /> + <%= f.text_area :content %> + </p> + <p> + <%= f.submit "Save" %> + </p> +<% end %>+
Now, when Rails renders the new or edit view, it will insert the _form partial at the indicated point. Note the naming convention for partials: if you refer to a partial named form inside of a view, the corresponding file is _form.html.erb, with a leading underscore.
For more information on partials, refer to the Layouts and Rending in Rails guide.
At this point, if you look at the controller for posts, you’ll see some duplication:
class PostsController < ApplicationController + # ... + def show + @post = Post.find(params[:id]) + # ... + end + + def edit + @post = Post.find(params[:id]) + end + + def update + @post = Post.find(params[:id]) + # ... + end + + def destroy + @post = Post.find(params[:id]) + # ... + end +end +
Four instances of the exact same line of code doesn’t seem very DRY. Rails provides filters as a way to address this sort of repeated code. In this case, you can DRY things up by using a before_filter:
class PostsController < ApplicationController + before_filter :find_post, :only => [:show, :edit, :update, :destroy] + # ... + def show + # ... + end + + def edit + end + + def update + # ... + end + + def destroy + # ... + end + + private + def find_post + @post = Post.find(params[:id]) + end +end +
Rails runs before filters before any action in the controller. You can use the :only clause to limit a before filter to only certain actions, or an :except clause to specifically skip a before filter for certain actions. Rails also allows you to define after filters that run after processing an action, as well as around filters that surround the processing of actions. Filters can also be defined in external classes to make it easy to share them between controllers.
For more information on filters, see the Action Controller Basics guide.
Now that you've seen what's in a model built with scaffolding, it's time to add a second model to the application. The second model will handle comments on blog posts.
Models in Rails use a singular name, and their corresponding database tables use a plural name. For the model to hold comments, the convention is to use the name Comment. Even if you don't want to use the entire apparatus set up by scaffolding, most Rails developers still use generators to make things like models and controllers. To create the new model, run this command in your terminal:
$ rake db:migrate
Rails is smart enough to only execute the migrations that have not already been run against this particular database.
Active Record associations let you declaratively quantify the relationship between two models. In the case of comments and posts, you could write out the relationships this way:
Active Record associations let you easily declare the relationship between two models. In the case of comments and posts, you could write out the relationships this way:
@@ -1538,10 +1680,10 @@ http://www.gnu.org/software/src-highlite -->
Routes are entries in the config/routes.rb file that tell Rails how to match incoming HTTP requests to controller actions. Open up that file and find the existing line referring to posts. Then edit it as follows:
With the model in hand, you can turn your attention to creating a matching controller. Again, there's a generator for this:
@comment = @post.comments.build
This creates a new Comment object and sets up the post_id field to have the id from the specified Post object in a single operation.
Because you skipped scaffolding, you'll need to build views for comments "by hand." Invoking script/generate controller will give you skeleton views, but they'll be devoid of actual content. Here's a first pass at fleshing out the comment views.
The index.html.erb view:
Again, the added complexity here (compared to the views you saw for managing comments) comes from the necessity of juggling a post and its comments at the same time.
As a final step, I'll modify the show.html.erb view for a post to show the comments on that post, and to allow managing those comments:
Note that each post has its own individual comments collection, accessible as @post.comments. That's a consequence of the declarative associations in the models. Path helpers such as post_comments_path come from the nested route declaration in config/routes.rb.
Now that you've seen your first Rails application, you should feel free to update it and experiment on your own. But you don't have to do everything without help. As you need assistance getting up and running with Rails, feel free to consult these support resources:
render :file => filename, :content_type => 'application/rss'
With most of the options to render, the rendered content is displayed as part of the current layout. You'll learn more about layouts and how to use them later in this guide. To find the current layout, Rails first looks for a file in app/views/layouts with the same base name as the controller. For example, rendering actions from the PhotosController class will use /app/views/layouts/photos.html.erb. If there is no such controller-specific layout, Rails will use /app/views/layouts/application.html.erb.
With most of the options to render, the rendered content is displayed as part of the current layout. You'll learn more about layouts and how to use them later in this guide.
You can use the :layout option to tell Rails to use a specific file as the layout for the current action:
render :xml => photo, :location => photo_url(photo)
To find the current layout, Rails first looks for a file in app/views/layouts with the same base name as the controller. For example, rendering actions from the PhotosController class will use /app/views/layouts/photos.html.erb. If there is no such controller-specific layout, Rails will use /app/views/layouts/application.html.erb. If there is no .erb layout, Rails will use a .builder layout if one exists. Rails also provides several ways to more precisely assign specific layouts to individual controllers and actions.
You can override the automatic layout conventions in your controllers by using the layout declaration in the controller. For example:
class ProductsController < ApplicationController + layout "inventory" + #... +end +
With this declaration, all methods within ProductsController will use app/views/layouts/inventory.html.erb for their layout.
To assign a specific layout for the entire application, use a declaration in your ApplicationController class:
class ApplicationController < ActionController::Base + layout "main" + #... +end +
With this declaration, all views in the entire application will use app/views/layouts/main.html.erb for their layout.
You can use a symbol to defer the choice of layout until a request is processed:
class ProductsController < ApplicationController + layout :products_layout + + def show + @product = Product.find(params[:id]) + end + + private + def products_layout + @current_user.special? ? "special" : "products" + end + +end +
Now, if the current user is a special user, they'll get a special layout when viewing a product. You can even use an inline method to determine the layout:
class ProductsController < ApplicationController + layout proc{ |controller| controller. + # ... +end +
Layouts specified at the controller level support :only and :except options that take either a method name or an array of method names:
class ProductsController < ApplicationController + layout "inventory", :only => :index + layout "product", :except => [:index, :rss] + #... +end+
With those declarations, the inventory layout would be used only for the index method, the product layout would be used for everything else except the rss method, and the rss method will have its layout determined by the automatic layout rules.
Layouts are shared downwards in the hierarchy, and more specific layouts always override more general ones. For example:
class ApplicationController < ActionController::Base + layout "main" + #... +end + +class PostsController < ApplicationController + # ... +end + +class SpecialPostsController < PostsController + layout "special" + # ... +end + +class OldPostsController < SpecialPostsController + layout nil + + def show + @post = Post.find(params[:id]) + end + + def index + @old_posts = Post.older + render :layout => "old" + end + # ... +end +
In this application:
+In general, views will be rendered in the main layout +
++PostsController#index will use the main layout +
++SpecialPostsController#index will use the special layout +
++OldPostsController#show will use no layout at all +
++OldPostsController#index will use the old layout +
+Sooner or later, most Rails developers will see the error message "Can only render or redirect once per action". While this is annoying, it's relatively easy to fix. Usually it happens because of a fundamental misunderstanding of the way that render works.
For example, here's some code that will trigger this error:
When Rails renders a view as a response, it does so by combining the view with the current layout. To find the current layout, Rails first looks for a file in app/views/layouts with the same base name as the controller. For example, rendering actions from the PhotosController class will use /app/views/layouts/photos.html.erb. If there is no such controller-specific layout, Rails will use /app/views/layouts/application.html.erb. You can also specify a particular layout by using the :layout option to render.
Within a layout, you have access to three tools for combining different bits of output to form the overall response:
When Rails renders a view as a response, it does so by combining the view with the current layout (using the rules for finding the current layout that were covered earlier in this guide). Within a layout, you have access to three tools for combining different bits of output to form the overall response:
diff --git a/railties/doc/guides/html/security.html b/railties/doc/guides/html/security.html index 4ece0814d5..a135d9b486 100644 --- a/railties/doc/guides/html/security.html +++ b/railties/doc/guides/html/security.html @@ -303,6 +303,8 @@ ul#navMain {
This manual describes common security problems in web applications and how to avoid them with Rails. If you have any questions or suggestions, please -mail me at 42 {et} rorsecurity.info. After reading it, you should be familiar with:
@@ -1206,7 +1208,10 @@ s = sanitize(user_input, :tags => tags, :attributes => %w(href title))
This example, again, showed that a blacklist filter is never complete. However, as custom CSS in web applications is a quite rare feature, I am not aware of a whitelist CSS filter. If you want to allow custom colours or images, you can allow the user to choose them and build the CSS in the web application. Use Rails' sanitize() method as a model for a whitelist CSS filter, if you really need one.
— If you want to provide text formatting other than HTML (due to security), use a mark-up language which is converted to HTML on the server-side. RedCloth is such a language for Ruby, but without precautions, it is also vulnerable to XSS.
For example, RedCloth translates test to <em>test<em>, which makes the text italic. However, up to the current version 3.0.4, it is still vulnerable to XSS:
For example, RedCloth translates _test_ to <em>test<em>, which makes the text italic. However, up to the current version 3.0.4, it is still vulnerable to XSS. Get the http://www.redcloth.org[all-new version 4] that removed serious bugs. However, even that version has http://www.rorsecurity.info/journal/2008/10/13/new-redcloth-security.html[some security bugs], so the countermeasures still apply. Here is an example for version 3.0.4:+
>> RedCloth.new('<script>alert(1)</script>').to_html @@ -1241,6 +1246,53 @@ s = sanitize(user_input, :tags => tags, :attributes => %w(href title))system("/bin/echo","hello; rm *") # prints "hello; rm *" and does not delete files
— HTTP headers are dynamically generated and under certain circumstances user input may be injected. This can lead to false redirection, XSS or HTTP response splitting.
HTTP request headers have a Referer, User-Agent (client software) and Cookie field, among others. Response headers for example have a status code, Cookie and Location (redirection target URL) field. All of them are user-supplied and may be manipulated with more or less effort. Remember to escape these header fields, too. For example when you display the user agent in an administration area.
Besides that, it is important to know what you are doing when building response headers partly based on user input. For example you want to redirect the user back to a specific page. To do that you introduced a “referer“ field in a form to redirect to the given address:
redirect_to params[:referer]+
What happens is that Rails puts the string into the Location header field and sends a 302 (redirect) status to the browser. The first thing a malicious user would do, is this:
http://www.yourapplication.com/controller/action?referer=http://www.malicious.tld+
And due to a bug in (Ruby and) Rails up to version 2.1.2 (excluding it), a hacker may inject arbitrary header fields; for example like this:
http://www.yourapplication.com/controller/action?referer=http://www.malicious.tld%0d%0aX-Header:+Hi! +http://www.yourapplication.com/controller/action?referer=path/at/your/app%0d%0aLocation:+http://www.malicious.tld+
Note that "%0d%0a" is URL-encoded for "\r\n" which is a carriage-return and line-feed (CRLF) in Ruby. So the resulting HTTP header for the second example will be the following because the second Location header field overwrites the first.
HTTP/1.1 302 Moved Temporarily +(...) +Location: http://www.malicious.tld+
So attack vectors for Header Injection are based on the injection of CRLF characters in a header field. And what could an attacker do with a false redirection? He could redirect to a phishing site that looks the same as yours, but asks to login again (and sends the login credentials to the attacker). Or he could install malicious software through browser security holes on that site. Rails 2.1.2 escapes these characters for the Location field in the redirect_to method. Make sure you do it yourself when you build other header fields with user input.
If Header Injection was possible, Response Splitting might be, too. In HTTP, the header block is followed by two CRLFs and the actual data (usually HTML). The idea of Response Splitting is to inject two CRLFs into a header field, followed by another response with malicious HTML. The response will be:
HTTP/1.1 302 Found [First standard 302 response] +Date: Tue, 12 Apr 2005 22:09:07 GMT +Location: Content-Type: text/html + + +HTTP/1.1 200 OK [Second New response created by attacker begins] +Content-Type: text/html + + +<html><font color=red>hey</font></html> [Arbitary malicious input is +Keep-Alive: timeout=15, max=100 shown as the redirected page] +Connection: Keep-Alive +Transfer-Encoding: chunked +Content-Type: text/html+
Under certain circumstances this would present the malicious HTML to the victim. However, this seems to work with Keep-Alive connections, only (and many browsers are using one-time connections). But you can't rely on this. In any case this is a serious bug, and you should update your Rails to version 2.0.5 or 2.1.2 to eliminate Header Injection (and thus response splitting) risks.
+ <%= f.label :name %>
+ <%= f.text_field :name %>
+
+ <%= f.label :title, "title" %>
+ <%= f.text_field :title %>
+
+ <%= f.label :content %>
+ <%= f.text_area :content %>
+
+ <%= f.submit "Save" %> +
+<% end %> +------------------------------------------------------- + +Now, when Rails renders the +new+ or +edit+ view, it will insert the +_form+ partial at the indicated point. Note the naming convention for partials: if you refer to a partial named +form+ inside of a view, the corresponding file is +_form.html.erb+, with a leading underscore. + +For more information on partials, refer to the link:../layouts_and_rendering.html[Layouts and Rending in Rails] guide. + +=== Using Filters to Eliminate Controller Duplication + +At this point, if you look at the controller for posts, you’ll see some duplication: + +[source, ruby] +------------------------------------------------------- +class PostsController < ApplicationController + # ... + def show + @post = Post.find(params[:id]) + # ... + end + + def edit + @post = Post.find(params[:id]) + end + + def update + @post = Post.find(params[:id]) + # ... + end + + def destroy + @post = Post.find(params[:id]) + # ... + end +end +------------------------------------------------------- + +Four instances of the exact same line of code doesn’t seem very DRY. Rails provides _filters_ as a way to address this sort of repeated code. In this case, you can DRY things up by using a +before_filter+: + +[source, ruby] +------------------------------------------------------- +class PostsController < ApplicationController + before_filter :find_post, :only => [:show, :edit, :update, :destroy] + # ... + def show + # ... + end + + def edit + end + + def update + # ... + end + + def destroy + # ... + end + + private + def find_post + @post = Post.find(params[:id]) + end +end +------------------------------------------------------- + +Rails runs _before filters_ before any action in the controller. You can use the +:only+ clause to limit a before filter to only certain actions, or an +:except+ clause to specifically skip a before filter for certain actions. Rails also allows you to define _after filters_ that run after processing an action, as well as _around filters_ that surround the processing of actions. Filters can also be defined in external classes to make it easy to share them between controllers. + +For more information on filters, see the link:actioncontroller_basics.html[Action Controller Basics] guide. + == Adding a Second Model Now that you've seen what's in a model built with scaffolding, it's time to add a second model to the application. The second model will handle comments on blog posts. @@ -798,7 +923,7 @@ Rails is smart enough to only execute the migrations that have not already been === Associating Models -Active Record associations let you declaratively quantify the relationship between two models. In the case of comments and posts, you could write out the relationships this way: +Active Record associations let you easily declare the relationship between two models. In the case of comments and posts, you could write out the relationships this way: * Each comment belongs to one post * One post can have many comments @@ -825,7 +950,7 @@ end These two declarations enable a good bit of automatic behavior. For example, if you have an instance variable +@post+ containing a post, you can retrieve all the comments belonging to that post as the array +@post.comments+. -TIP: For more information on Active Record associations, see the link:../association_basics.html+[Active Record Associations] guide. +TIP: For more information on Active Record associations, see the link:../association_basics.html[Active Record Associations] guide. === Adding a Route diff --git a/railties/doc/guides/source/layouts_and_rendering.txt b/railties/doc/guides/source/layouts_and_rendering.txt index ed56b82ffd..c4bb5b0591 100644 --- a/railties/doc/guides/source/layouts_and_rendering.txt +++ b/railties/doc/guides/source/layouts_and_rendering.txt @@ -186,7 +186,7 @@ render :file => filename, :content_type => 'application/rss' ===== The +:layout+ Option -With most of the options to +render+, the rendered content is displayed as part of the current layout. You'll learn more about layouts and how to use them later in this guide. To find the current layout, Rails first looks for a file in +app/views/layouts+ with the same base name as the controller. For example, rendering actions from the +PhotosController+ class will use +/app/views/layouts/photos.html.erb+. If there is no such controller-specific layout, Rails will use +/app/views/layouts/application.html.erb+. +With most of the options to +render+, the rendered content is displayed as part of the current layout. You'll learn more about layouts and how to use them later in this guide. You can use the +:layout+ option to tell Rails to use a specific file as the layout for the current action: @@ -223,6 +223,124 @@ You can use the +:location+ option to set the HTTP +Location+ header: render :xml => photo, :location => photo_url(photo) ------------------------------------------------------- +==== Finding Layouts + +To find the current layout, Rails first looks for a file in +app/views/layouts+ with the same base name as the controller. For example, rendering actions from the +PhotosController+ class will use +/app/views/layouts/photos.html.erb+. If there is no such controller-specific layout, Rails will use +/app/views/layouts/application.html.erb+. If there is no +.erb+ layout, Rails will use a +.builder+ layout if one exists. Rails also provides several ways to more precisely assign specific layouts to individual controllers and actions. + +===== Specifying Layouts on a per-Controller Basis + +You can override the automatic layout conventions in your controllers by using the +layout+ declaration in the controller. For example: + +[source, ruby] +------------------------------------------------------- +class ProductsController < ApplicationController + layout "inventory" + #... +end +------------------------------------------------------- + +With this declaration, all methods within +ProductsController+ will use +app/views/layouts/inventory.html.erb+ for their layout. + +To assign a specific layout for the entire application, use a declaration in your +ApplicationController+ class: + +[source, ruby] +------------------------------------------------------- +class ApplicationController < ActionController::Base + layout "main" + #... +end +------------------------------------------------------- + +With this declaration, all views in the entire application will use +app/views/layouts/main.html.erb+ for their layout. + +===== Choosing Layouts at Runtime + +You can use a symbol to defer the choice of layout until a request is processed: + +[source, ruby] +------------------------------------------------------- +class ProductsController < ApplicationController + layout :products_layout + + def show + @product = Product.find(params[:id]) + end + + private + def products_layout + @current_user.special? ? "special" : "products" + end + +end +------------------------------------------------------- + +Now, if the current user is a special user, they'll get a special layout when viewing a product. You can even use an inline method to determine the layout: + +[source, ruby] +------------------------------------------------------- +class ProductsController < ApplicationController + layout proc{ |controller| controller. + # ... +end +------------------------------------------------------- + +===== Conditional Layouts + +Layouts specified at the controller level support +:only+ and +:except+ options that take either a method name or an array of method names: + +------------------------------------------------------- +class ProductsController < ApplicationController + layout "inventory", :only => :index + layout "product", :except => [:index, :rss] + #... +end +------------------------------------------------------- + +With those declarations, the +inventory+ layout would be used only for the +index+ method, the +product+ layout would be used for everything else except the +rss+ method, and the +rss+ method will have its layout determined by the automatic layout rules. + +===== Layout Inheritance + +Layouts are shared downwards in the hierarchy, and more specific layouts always override more general ones. For example: + +[source, ruby] +------------------------------------------------------- +class ApplicationController < ActionController::Base + layout "main" + #... +end + +class PostsController < ApplicationController + # ... +end + +class SpecialPostsController < PostsController + layout "special" + # ... +end + +class OldPostsController < SpecialPostsController + layout nil + + def show + @post = Post.find(params[:id]) + end + + def index + @old_posts = Post.older + render :layout => "old" + end + # ... +end +------------------------------------------------------- + +In this application: + +* In general, views will be rendered in the +main+ layout +* +PostsController#index+ will use the +main+ layout +* +SpecialPostsController#index+ will use the +special+ layout +* +OldPostsController#show+ will use no layout at all +* +OldPostsController#index+ will use the +old+ layout + ==== Avoiding Double Render Errors Sooner or later, most Rails developers will see the error message "Can only render or redirect once per action". While this is annoying, it's relatively easy to fix. Usually it happens because of a fundamental misunderstanding of the way that +render+ works. @@ -332,9 +450,7 @@ head :created, :location => photo_path(@photo) == Structuring Layouts -When Rails renders a view as a response, it does so by combining the view with the current layout. To find the current layout, Rails first looks for a file in +app/views/layouts+ with the same base name as the controller. For example, rendering actions from the +PhotosController+ class will use +/app/views/layouts/photos.html.erb+. If there is no such controller-specific layout, Rails will use +/app/views/layouts/application.html.erb+. You can also specify a particular layout by using the +:layout+ option to +render+. - -Within a layout, you have access to three tools for combining different bits of output to form the overall response: +When Rails renders a view as a response, it does so by combining the view with the current layout (using the rules for finding the current layout that were covered earlier in this guide). Within a layout, you have access to three tools for combining different bits of output to form the overall response: * Asset tags * +yield+ and +content_for+ diff --git a/railties/doc/guides/source/security.txt b/railties/doc/guides/source/security.txt index d068a22491..53819babb7 100644 --- a/railties/doc/guides/source/security.txt +++ b/railties/doc/guides/source/security.txt @@ -2,7 +2,7 @@ Ruby On Rails Security Guide ============================ This manual describes common security problems in web applications and how to avoid them with Rails. If you have any questions or suggestions, please -mail me at 42 {_et_} rorsecurity.info. After reading it, you should be familiar with: +mail me, Heiko Webers, at 42 {_et_} rorsecurity.info. After reading it, you should be familiar with: - All countermeasures [,#fffcdb]#that are highlighted# - The concept of sessions in Rails, what to put in there and popular attack methods @@ -858,7 +858,8 @@ This example, again, showed that a blacklist filter is never complete. However, -- _If you want to provide text formatting other than HTML (due to security), use a mark-up language which is converted to HTML on the server-side. http://whytheluckystiff.net/ruby/redcloth/[RedCloth] is such a language for Ruby, but without precautions, it is also vulnerable to XSS._ -For example, RedCloth translates _test_ to test, which makes the text italic. However, up to the current version 3.0.4, it is still vulnerable to XSS: + For example, RedCloth translates _test_ to test, which makes the text italic. However, up to the current version 3.0.4, it is still vulnerable to XSS. Get the http://www.redcloth.org[all-new version 4] that removed serious bugs. However, even that version has http://www.rorsecurity.info/journal/2008/10/13/new-redcloth-security.html[some security bugs], so the countermeasures still apply. Here is an example for version 3.0.4: + ........... >> RedCloth.new('').to_html @@ -908,6 +909,64 @@ system("/bin/echo","hello; rm *") # prints "hello; rm *" and does not delete files .......... + +=== Header Injection +-- _HTTP headers are dynamically generated and under certain circumstances user input may be injected. This can lead to false redirection, XSS or HTTP response splitting._ + +HTTP request headers have a Referer, User-Agent (client software) and Cookie field, among others. Response headers for example have a status code, Cookie and Location (redirection target URL) field. All of them are user-supplied and may be manipulated with more or less effort. [,#fffcdb]#Remember to escape these header fields, too.# For example when you display the user agent in an administration area. + +Besides that, it is [,#fffcdb]#important to know what you are doing when building response headers partly based on user input.# For example you want to redirect the user back to a specific page. To do that you introduced a “referer“ field in a form to redirect to the given address: + +.......... +redirect_to params[:referer] +.......... + +What happens is that Rails puts the string into the Location header field and sends a 302 (redirect) status to the browser. The first thing a malicious user would do, is this: + +.......... +http://www.yourapplication.com/controller/action?referer=http://www.malicious.tld +.......... + +And due to a bug in (Ruby and) Rails up to version 2.1.2 (excluding it), a hacker may inject arbitrary header fields; for example like this: + +.......... +http://www.yourapplication.com/controller/action?referer=http://www.malicious.tld%0d%0aX-Header:+Hi! +http://www.yourapplication.com/controller/action?referer=path/at/your/app%0d%0aLocation:+http://www.malicious.tld +.......... + +Note that "%0d%0a" is URL-encoded for "\r\n" which is a carriage-return and line-feed (CRLF) in Ruby. So the resulting HTTP header for the second example will be the following because the second Location header field overwrites the first. + +.......... +HTTP/1.1 302 Moved Temporarily +(...) +Location: http://www.malicious.tld +.......... + +So [,#fffcdb]#attack vectors for Header Injection are based on the injection of CRLF characters in a header field.# And what could an attacker do with a false redirection? He could redirect to a phishing site that looks the same as yours, but asks to login again (and sends the login credentials to the attacker). Or he could install malicious software through browser security holes on that site. [,#fffcdb]#Rails 2.1.2 escapes these characters for the Location field in the redirect_to method. Make sure you do it yourself when you build other header fields with user input.# + +==== Response Splitting +If Header Injection was possible, Response Splitting might be, too. In HTTP, the header block is followed by two CRLFs and the actual data (usually HTML). The idea of Response Splitting is to inject two CRLFs into a header field, followed by another response with malicious HTML. The response will be: + +.......... +HTTP/1.1 302 Found [First standard 302 response] +Date: Tue, 12 Apr 2005 22:09:07 GMT +Location: Content-Type: text/html + + +HTTP/1.1 200 OK [Second New response created by attacker begins] +Content-Type: text/html + + +hey [Arbitary malicious input is +Keep-Alive: timeout=15, max=100 shown as the redirected page] +Connection: Keep-Alive +Transfer-Encoding: chunked +Content-Type: text/html +.......... + +Under certain circumstances this would present the malicious HTML to the victim. However, this seems to work with Keep-Alive connections, only (and many browsers are using one-time connections). But you can't rely on this. [,#fffcdb]#In any case this is a serious bug, and you should update your Rails to version 2.0.5 or 2.1.2 to eliminate Header Injection (and thus response splitting) risks.# + + == Additional resources The security landscape shifts and it is important to keep up to date, because missing a new vulnerability can be catastrophic. You can find additional resources about (Rails) security here: