imedo Development Blog

there is no charge for awesomeness

Archive for the ‘secure coding’ tag

Secure coding with Ruby on Rails 7: Cross-site request forgery (CSRF)

without comments

Although discovered already in 1988 by Norm Hardy, cross-site request forgery (CSRF) has been the shooting star of web attacks in 2008. As a result it has become one of the 2009 CWE/SANS Top 25 Most Dangerous Programming Errors.

The idea behind CSRF is that an attacker sends a malicious request to the target application using a trusted connection which he expects to have been established by an innocent user. In case of web applications this could be done by hiding the request in a web page with harmless content. If the user visits the malicious web page while he is logged in to the target application in another browser tab, the dangerous request is send to the target over the trusted connection between browser and web application. Two basic scenarios are possible. In the first scenario the attacker forges a request to a commonly used web application so that it doesn’t matter who opens the malicious web page. The other scenario is to trick somebody who is known to have special privileges for one web application to open the prepared web page.

In both scenarios the malicious web page of the attacker is crafted so that it sends a hidden request to the target application. For example a HTTP GET request could be executed by using the src attribute of an img tag like in the following line of code. In this case it would delete one user account.

<img src="http://victim.example.com/user/destroy/1" />

Another possibility to hide a request in a web page is displayed in the next example. It’s a hidden HTTP POST request which changes the name and email address of the logged in user. It sends the request automatically on page load. With the changed email address the attacker can use the “forgot password?” function in order to receive a newly generated password and capture the account.

<SCRIPT>
  function SendAttack() {
    var form = document.createElement("form");
    form.style.display = "none";
    this.parentNode.appendChild(form);
    form.method = "POST";
    form.action = "http://victim.example.com/profile.php";
    form.first_name = "Bad";
    form.last_name = "Guy";
    form.email = "attacker@example.com";
    form.submit();
  }
</SCRIPT>
<BODY onload="javascript:SendAttack();"></BODY>

These two examples demonstrate that HTTP GET as well as HTTP POST are vulnerable by CSRF. Hence it is not enough to allow only POST requests to alter data. Other measure need to be applied, too. An obvious client-side countermeasures is to use separate browsers for surfing and administration, but Rails provides a server-side measure as well. The method protect_from_forgery() automatically inserts a security token in all forms and Ajax request generated by Rails. The token is calculated from the current session and the server-side secret. If the session storage is not CookieStorage the secret needs to be passed as option to the method. If an attacker is trying to send a request without the valid token to the application an ActionController::InvalidAuthenticityToken error is raised.

In Rails versions newer than 2.0 protect_from_forgery() is called for all HTTP POST requests by default. Hence it only has to be taken care of that HTTP GET  and HTTP POST requests are used appropriately (see W3C checklist) and that this is enforced. For assuring that actions are only called by HTTP POST requests Rails provides the verify() method which can be added to a controller as demonstrated in the following example. It is also shown how to define actions which should be callable by other HTTP methods than POST with the except option.

class MyController < ApplicationController
  verify :method => "post", :except => :index
end

In older Rails versions the protect_from_forgery() method can be used like shown in the following lines of code. In this example CSRF protection is disabled for the index action.

class MyController < ApplicationController
  protect_from_forgery :except => :index
end

For further information on cross-side request forgery see www.cgisecurity.com/csrf-faq.html.

Popularity: 1% [?]

Written by ehartung

December 4th, 2009 at 4:45 pm

Secure coding with Ruby on Rails 5: OS command injection

without comments

OS command injection is ranked number five on the 2009 CWE/SANS Top 25 Most Dangerous Programming Errors listing. It means to extend input, which is meant to be used as parameter for a shell command, with malicious shell commands. This is possible since operating systems like UNIX support the execution of several commands in one line by separating the commands with a ”;”.

The following line of code could be part of a simple web interface to Subversion. It downloads a copy of the repository given by the user by executing a system call to the svn-checkout command with the provided repository as parameter.

system "svn checkout #{params[:repository]}"

While this code is doing what it is supposed to, it also represents a great risk for the system’s security, i.e. its non-repudiation. Web applications which pass input values to system calls unchecked, enable an attacker to easily access the command line on the web server’s host with the privileges of the web server. E.g. if an attacker enters the string “https://svn.mydomain.org/code; rm -rf /var/www/*” for the above example he might delete all web pages on the host.

A countermeasure against OS command injection in Ruby on Rails is the usage of the system(command, parameter) method which ensures that no part of the parameter is handled as a shell command.

system("svn", "checkout #{params[:repository]}")

Popularity: 1% [?]

Written by ehartung

October 7th, 2009 at 4:24 pm

Secure coding with Ruby on Rails 4: Cross-site scripting (XSS)

without comments

A Failure to Preserve Web Page Structure, which is number four of the 2009 CWE/SANS Top 25 Most Dangerous Programming Errors, is a programming error which makes an application vulnerable to cross-site scripting (XSS). For XSS an attacker injects malicious content into the output of a web application loading code from an external resource which is executed by the client’s web browser.

For example an attacker writes the following piece of code in a forum post. This line loads malicious JavaScript code from an external host which is executed when ever somebody reads the forum post.


<SCRIPT SRC=http://ha.ckers.org/xss.js></SCRIPT>

While in order to prevent SQL injection it is important to sanitize the input data, for XSS especially the output of a web application should be sanitized. In order to achieve this, dynamic content could be displayed as followed.


escapeHTML(<SCRIPT SRC=http://ha.ckers.org/xss.js></SCRIPT>)

The output escaper of ERB html_escape() has an alias called h() which makes it easier to use. For those this is still too much overhead or who want to be sure should use the Rails plugin SafeERB which ensures that all strings in a rhtml template are escaped properly.

When using a HTML output escaper it is important to verify that it is using a whitelist, since XSS attacks do not necessarily look like the example above. It can also have the form of the following strings which are hard to filter with a blacklist. The first attack string uses the IMG tag to insert the malicious JavaScript code which is encoded in UTF-8. Older browsers like IE6, IE7, and Firefox2 which are-for several reasons-still in use, are known to support such encodings and treat them as valid HTML code.


<IMG SRC=&#106;&#97;&#118;&#97;&#115;&#99;&#114;&#105;&#112;&#116;&#58;&#97;&#108;&#101;&#114;&#116;&#40;&#39;&#88;&#83;&#83;&#39;&#41;>

This example can also be written the following way, which does not even use the semicolons at the end of an UTF-8 character encoding, since an UTF-8 character is encoded in 7 digits. The syntax with the semicolon is only a short form.


<IMG SRC=&#0000106&#0000097&#0000118&#0000097&#0000115&#0000099&#0000114&#0000105&#0000112&#0000116&#0000058&#0000097&#0000108&#0000101&#0000114&#0000116&#0000040&#0000039&#0000088&#0000083&#0000083&#0000039&#0000041>

For these and more cross-site scripting attack examples visit the XSS cheat sheet.

Although not direct measures against XSS, input sanitation and input validation can help to prevent malicious code from getting into the application. So the usage of sanitize() and Ruby on Rails validation methods is highly recommended to provide an in-depth defense strategy against cross-site scripting. A really useful plugin is acts_as_sanitized which provides XSS input sanitation.

Popularity: 1% [?]

Written by ehartung

October 2nd, 2009 at 9:41 am

Secure coding with Ruby on Rails 3: SQL injection

with 2 comments

Number three of the 2009 CWE/SANS Top 25 Most Dangerous Programming Errors is Improper Sanitization of Special Elements used in an SQL Command which could lead to the possibility of SQL injection.

If an application is vulnerable to SQL injection an attacker can add SQL commands to input values in order to manipulate the behavior of this application or to gain unauthorized access. The classic example for SQL injection is the circumvention of authorization by adding an always true condition like ‘or 1=1’ to the passed password in a login dialog as shown in the following example.


User.find(:first, "login = '#{params[:user_name]}' AND password = '#{params[:password]}'")

Entering ’ OR ‘1’=’1 as password will result in the following MySQL query.


SELECT * FROM users WHERE login = 'asdf' AND password = '' OR '1'='1' LIMIT 1

This query will return the first user in the database and therefore the authorization will always succeed as long as there is at least one user in the database.

Besides getting unauthorized access to an application, SQL injection can be used to manipulate the displayed information so that sensitive information may be revealed. In the following example lazy SQL querying of non-sensitive data opens a door to the complete database and an attacker is able to read the user table by extending the input with SQL commands.


Article.find(:all, :conditions => "author = '#{params[:author]}'")

The database for this example consists of two tables: articles and users. While the articles table has four columns (id, author, title, text) the users table has only three (id, login, password). Here’s the attacker’s input for this scenario.


') UNION SELECT id,login AS author,password AS title,1 FROM users --

The input provided by the attacker generates the following MySQL query, which result will not contain any article but all entries from the users table masqueraded as articles.


SELECT * FROM articles WHERE (author = '') UNION SELECT id,login AS author,password AS title,1 FROM users -- ')

In order to prevent SQL injection the build in filters of Ruby on Rails like Model.find(id) or Model.find_by_*() should be used. They have sanitizers included which escape special SQL characters. For the first example this could look like the following.


user = User.find_by_login(params[:login])
raise "Access denied!" if user.password != params[:password]

If the conditions parameter is needed, e.g. in order to filter for several criteria, sanitizers like sanitize_sql_for_conditions in ActiveRecord::Base will create safe condition statements.


Article.find(:all, :conditions => sanitize_sql_for_conditions(:author => params[:author], :title => params[:title]))

Popularity: 1% [?]

Written by ehartung

September 23rd, 2009 at 7:36 am

Secure coding with Ruby on Rails 2: Output escaping

without comments

While input validation prevents the malicious manipulation of an application by users, proper output data escaping prevents failures in other applications which receive the generated data, but lack input validation.

Improper encoding or escaping of output is therefor the number two of the 2009 CWE/SANS Top 25 Most Dangerous Programming Errors. A popular example for this kind of vulnerability are browsers which are manipulated by malicious JavaScript code injected into user-generated content of web applications. This kind of attack is called cross-site scripting (XSS).

In client-server environments applications communicate over APIs using more or less well defined protocols. Server and client applications can be developed by different parties unaware of the other side’s source code. A server which expects input data in a certain format can run into serious problems when a client application sends data in a wrong encoding or does not escape SQL, OS, or other commands. This is even more dangerous if the client application constructs the output from user input, e.g. a chat client which does not escape control commands.

Of course, it should be common knowledge that input data needs to be validated, but as long as it cannot be verified, e.g. by reviewing the source code, proper output encoding and escaping should be provided.

The most common output formats of a Rails web application are HTML and JSON. For escaping those formats Ruby on Rails provides the following mechanisms.

  • The ERB method html_escape() or its alias h() for HTML output
  • The SanitizeHelper methods to escape HTML output
  • The SafeERB plugin for enforcing the escaping of strings in rhtml templates
  • The ERB method json_escape() or its alias j() for JSON output

If other output formats are needed it is highly recommended to use provided escape methods or to write a custom output escaper.

Popularity: 1% [?]

Written by ehartung

September 21st, 2009 at 6:31 pm

Secure coding with Ruby on Rails 1: Input validation

without comments

Improper input validation is the number one error according to the 2009 CWE/SANS Top 25 Most Dangerous Programming Errors listing. It can be exploited by changing input values in such a way so as to cause the application to crash, confidential information to be revealed or the flow of the program to be changed in an unexpected way. This kind of exploit is called input validation attack. The following example demonstrates how lazy input handling can lead to unwanted effects. It shows a piece of code which calculates the price of a sale by multiplying a product’s fixed price with the quantity provided by the user. Afterwards it charges the user’s account with the total price.


class Sale < ActiveRecord::Base
 belongs_to :user

 def buy
   total_price = single_price * quantity
   user.account.charge(total_price)
 end

end

sale = Sale.new(:single_price => 10, :quantity => params[:quantity], :user => buying_user)
sale.buy

Consider the case a user provides a negative value for the quantity. The total price would be negative as well and therefore the user or attacker is able to increase the amount on his account for free.

In order to prevent misuse, input data which is provided by the user should never be trusted. Proper input validation is absolutely necessary. For the example above a check for integer values greater or equal to zero would prevent the exploit of the code. Ruby on Rails already brings a set of easy to use input validation methods which usage is demonstrated in the following.


class Sale < ActiveRecord::Base
 belongs_to :user
  validates_numericality_of :quantity,
    :o nly_integer => true
    :greater_than_or_equal_to => 0

 def buy
   total_price = single_price * quantity
   user.account.charge(total_price)
 end

end

sale = Sale.new(:single_price => 10, :quantity => params[:quantity], :user => buying_user)
sale.buy

More Rails validation methods can be found under Module
ActiveRecord::Validations::ClassMethods
.

Popularity: 1% [?]

Written by ehartung

September 1st, 2009 at 7:06 am