diff --git a/railties/guides/source/security.textile b/railties/guides/source/security.textile index 6b84ca1965..5797eb888b 100644 --- a/railties/guides/source/security.textile +++ b/railties/guides/source/security.textile @@ -91,12 +91,12 @@ Rails 2 introduced a new default session storage, CookieStore. CookieStore saves That means the security of this storage depends on this secret (and on the digest algorithm, which defaults to SHA512, which has not been compromised, yet). So _(highlight)don't use a trivial secret, i.e. a word from a dictionary, or one which is shorter than 30 characters_. Put the secret in your environment.rb: -
+
config.action_controller.session = {
:key => '_app_session',
:secret => '0x0dkfj3927dkc7djdh36rkckdfzsg...'
}
-
+
There are, however, derivatives of CookieStore which encrypt the session hash, so the client cannot see it.
@@ -211,9 +211,9 @@ If your web application is RESTful, you might be used to additional HTTP verbs,
_(highlight)The verify method in a controller can make sure that specific actions may not be used over GET_. Here is an example to verify the use of the transfer action over POST. If the action comes in using any other verb, it redirects to the list action.
-
+
verify :method => :post, :only => [:transfer], :redirect_to => {:action => :list}
-
+
With this precaution, the attack from above will not work, because the browser sends a GET request for images, which will not be accepted by the web application.
@@ -264,9 +264,9 @@ end
This will redirect the user to the main action if he tried to access a legacy action. The intention was to preserve the URL parameters to the legacy action and pass them to the main action. However, it can exploited by an attacker if he includes a host key in the URL:
-++ If it is at the end of the URL it will hardly be noticed and redirects the user to the attacker.com host. A simple countermeasure would be to _(highlight)include only the expected parameters in a legacy action_ (again a whitelist approach, as opposed to removing unexpected parameters). _(highlight)And if you redirect to an URL, check it with a whitelist or a regular expression_. @@ -424,10 +424,10 @@ There are some authorization and authentication plug-ins for Rails available. A Every new user gets an activation code to activate his account when he gets an e-mail with a link in it. After activating the account, the activation_code columns will be set to NULL in the database. If someone requested an URL like these, he would be logged in as the first activated user found in the database (and chances are that this is the administrator): -http://www.example.com/site/legacy?param1=xy¶m2=23&host=www.attacker.com -
++ This is possible because on some servers, this way the parameter id, as in params[:id], would be nil. However, here is the finder from the activation action: @@ -437,9 +437,9 @@ User.find_by_activation_code(params[:id]) If the parameter was nil, the resulting SQL query will be -http://localhost:3006/user/activate http://localhost:3006/user/activate?id= -
++ And thus it found the first user in the database, returned it and logged him in. You can find out more about it in "my blog post":http://www.rorsecurity.info/2007/10/28/restful_authentication-login-security/. _(highlight)It is advisable to update your plug-ins from time to time_. Moreover, you can review your application to find more flaws like this. @@ -534,9 +534,9 @@ end This means, upon saving, the model will validate the file name to consist only of alphanumeric characters, dots, + and -. And the programmer added \^ and $ so that file name will contain these characters from the beginning to the end of the string. However, _(highlight)in Ruby ^ and $ matches the *line* beginning and line end_. And thus a file name like this passes the filter without problems: -SELECT * FROM users WHERE (users.activation_code IS NULL) LIMIT 1 -
++ Whereas %0A is a line feed in URL encoding, so Rails automatically converts it to "file.txt\n<script>alert('hello')</script>". This file name passes the filter because the regular expression matches – up to the line end, the rest does not matter. The correct expression should read: @@ -599,9 +599,9 @@ Project.find(:all, :conditions => "name = '#{params[:name]}'") This could be in a search action and the user may enter a project's name that he wants to find. If a malicious user enters ' OR 1=1', the resulting SQL query will be: -file.txt%0A -
++ The two dashes start a comment ignoring everything after it. So the query returns all records from the projects table including those blind to the user. This is because the condition is true for all records. @@ -615,9 +615,9 @@ User.find(:first, "login = '#{params[:name]}' AND password = '#{params[:password If an attacker enters ' OR '1'='1 as the name, and ' OR '2'>'1 as the password, the resulting SQL query will be: -SELECT * FROM projects WHERE name = '' OR 1 --' -
++ This will simply find the first record in the database, and grants access to this user. @@ -631,16 +631,16 @@ Project.find(:all, :conditions => "name = '#{params[:name]}'") And now let's inject another query using the UNION statement: -SELECT * FROM users WHERE login = '' OR '1'='1' AND password = '' OR '2'>'1' LIMIT 1 -
++ This will result in the following SQL query: -') UNION SELECT id,login AS name,password AS description,1,1,1 FROM users -- -
++ The result won't be a list of projects (because there is no project with an empty name), but a list of user names and their password. So hopefully you encrypted the passwords in the database! The only problem for the attacker is, that the number of columns has to be the same in both queries. That's why the second query includes a list of ones (1), which will be always the value 1, in order to match the number of columns in the first query. @@ -686,36 +686,36 @@ The most common XSS language is of course the most popular client-side scripting Here is the most straightforward test to check for XSS: -SELECT * FROM projects WHERE (name = '') UNION SELECT id,login AS name,password AS description,1,1,1 FROM users --') -
+ -+ This JavaScript code will simply display an alert box. The next examples do exactly the same, only in very uncommon places: -
+![]()