CSC/ECE 517 Fall 2009/wiki1b 8 va

From Expertiza_Wiki
Revision as of 03:37, 26 September 2009 by Apaul (talk | contribs) (→‎References)
Jump to navigation Jump to search

Ruby and Web Security

This page describes top 25 dangerous programming errors identified by SANS 1 and how Ruby on Rails can mitigate them.

Introduction

Security errors are one of the most serious problems affecting today's applications. These errors can result in many undesirable effects, including lost profits, comprimise of sensitive information, or damage to the system. Ruby on Rails has many features and some clever helper methods that automatically prevent security holes. There are additional tools and plugins for Ruby and Rails that can further reduce the risks. Some of the security errors have not yet been addressed by Ruby and Rails. 3

Built in features that can enhance security

  • Safety levels (Ruby) - Ruby can limit how tainted (externally supplied) data is supplied. Meaningful values range from 0 to 4, with 0 being no safety check and increasing levels of security to 4 being the most secure (and most restrictive). Set with $SAFE = number in the Ruby program or the -T command from the command line. [13]
  • Parametric Polymorphism (Ruby) - This language feature can handle a wide variety of inputs without crashing, but unexpected inputs may be processed in unexpected ways, causing the need for greater input testing. Tools have been developed to perform this testing.
  • protect_from_forgery command (Rails)
  • Active Record for SQL Database Manipulation (Rails) - This is a built in class for securely acessing the SQL database.
  • Automatically generated finder methods (Rails) - These methods access the database and are secure against SQL injection attacks [14]
  • Largely automated design (Ruby and Rails) - This helps reduce coding errors which mitigates some security issues
  • Virtual machine (Ruby and Rails) - Code is run by a language interpreter rather than compiled and executed.
  • Test case tools such as Test Unit built in to Aptana's Ruby plug-in for Eclipse (Ruby and Rails)

Tools and plugins

  • Tarantula - A tool that tests applications for common vulnerabilities. This is new and is still in development.
  • R-spec - Another testing unit to be used with eclipse which provides documentation capabilities
  • Clearance - A gem used to perform user login with hashed passwords
  • Safe-ERB - A plugin used to counteract the Cross Site Scripting attack.
  • Sandbox - Prevents damage to other applications
  • Ruby-HMAC - Protects cookie information from unauthorized access.

Common security errors and their mitigations [1]

Category: Insecure Interaction Between Components

CWE-20: Improper Input Validation

Proper input validation is very essential in order to avoid attacks. Improper input can lead to attacks when attackers can modify their inputs in unexpected ways. Ruby has a solution for this. In Ruby input validation can be done in model using Active Records which implements validation by overwriting Base#validate. The methods validates_presence_of, validates_inclusion_of, validates_confirmation_of, validates_length_of etc. are used for input validation. There are other methods like create_with_validation, update_with_validation or save_with_validation that can be used when specific operation is done.

  • Example: 15
 class Employee < ActiveRecord::Base
   validates_confirmation_of :password, :email_address, :on => :create
   validates_presence_of :name, :sex, :age, :salary, :address
   validates_inclusion_of :sex, :in => %w(M F), :message => 'must be M or F'
   validates_inclusion_of :age, :within => 1..60
   validates_length_of :salary :allow_nil => false, :within => 50000..120000
   validates_length_of :address, :allow_blank => false, :allow_nil => false, :maximum => 500
 end

Ruby and Rails also provides Test Unit which should be used to test for this. Polymorphism in Rails makes it very important to perform these checks. Rails has a plugin tarantula, a fuzzy spider. It crawls the rails application, fuzzing inputs and analyzing what comes back. 7

CWE-116: Improper Encoding or Escaping of Output

Insufficient output encoding is the often-ignored sibling to poor input validation, but it is at the root of most injection-based attacks. An attacker can modify the commands that programmer intend to send to other components, possibly leading to a complete compromise of the application. When the program generates outputs to other components in the form of structured messages such as requests or queries, it needs to separate control information and metadata from the actual data. This is often ignored because many paradigms carry data and commands bundled together in the same stream, with only a few special characters enforcing the boundaries.

It is important to escape the output of web applications especially when re-displaying user input that was not input-filtered. Ruby uses escapeHTML() method to replace the HTML input characters &, ", <, > by their uninterpreted representations in HTML (&, ", <, and >). Rails' sanitize() method is a good solution to fend off encoding attacks. Output escaping is easily forgotten by programmer to code. Rails has the SafeErb plugin which reminds the programmer about output escaping if this is forgotten. 2

CWE-89: Failure to Preserve SQL Query Structure (aka 'SQL Injection')

In today's world software applications are all about data. It is all about getting data into the database, pulling it from the database, massaging it into information, showing them in browser and sending it elsewhere. If attackers can influence the SQL that programmer use to communicate with the database, then they can do anything they want. If we use SQL queries in security controls such as authentication, attackers could even alter the logic of those queries to bypass security. They could modify the queries to steal, corrupt, or otherwise change the underlying data.

Ruby has a solution for this. Popular goals of SQL injection attacks are to bypass authorization or carry out data manipulation or reading arbitrary data. SQL injection can also happen by influencing database queries by manipulating web application parameters. Ruby on Rails has a built in filter for special SQL characters, which will escape ’, ", NULL character and line breaks. Instead of passing a string to conditions options an array or an hash can be passed to sanitize tainted strings. Furthermore, Rails has predefined Active Record functions to access the database. These functions are designed to prevent SQL injection attacks from succeeding.

  • Example: How ruby mitigates problem of bypassing authorization:
   Use of User.find(:first, "login = '#{params[:name]}' AND password = '#{params[:password]}'") 

Input of ’ OR ‘1’=‘1 as name, and ’ OR ’2’>’1 as password will create the following query:

   "SELECT * FROM users WHERE login =  OR '1'='1' AND password =  OR '2'>'1' LIMIT 1"  

The above query will find first record from user table and grant access to the user. In Ruby, Model.find(id) can be used in model to mitigate the problem of bypassing authorization. Array and hash are only available in model. There is one function sanitize_sql() which can be used in other places for this purpose. 2

   Model.find(:first, :conditions => {:login => entered_user_name, :password => entered_password})

CWE-79: Failure to Preserve Web Page Structure (aka 'Cross-site Scripting(XSS)')

Due to stateless nature of HTTP, mixture of data and script in HTML or lots of data passing between web sites are very common. If programmers are not careful then attackers can inject Javascript or other browser-executable content into a web page that the application generates. Programmer's web page is then accessed by other users, whose browsers execute that malicious script.

This attack injects client side executable code. Cross site scripting can hijack the session, steal the cookie, display advertisements for the benefit of the attacker, change elements on the web site to get confidential information, redirect the victim to a fake website or install malicious software through security holes in the web browser.

To avoid XSS it is important to filter out malicious inputs and escape output of web application. Rather than blacklisting inputs it is good to create a white list describing the allowed values because blacklist never ends. Rails has helper methods to defend against this problem. Rails has the sanitize() method for this whitelist approach. sanitize() also defends encoding injection attacks. 2

  • Example::
   Attacker injects code to show an alert as follows
   strip_tags("some<script>alert('hello')</script>") 
   Use of Rail's sanitize method
   tags = %w(a acronym b strong i em li ul ol h1 h2 h3 h4 h5 h6 blockquote br cite sub sup ins p) 
   s = sanitize(user_input, :tags => tags, :attributes => %w(href title)) 

Safe-ERB is another plugin developed specifically to counter this threat.

CWE-78: Failure to Preserve OS Command Structure (aka 'OS Command Injection')

Software applications are generally a bridge between an outsider on the network and the internals of the operating system. Attackers can inject malicious code when software applications run system level operations using commands as parameters from user.

Ruby has system(command, parameters) method which defends this attack. 2

  • Example::
   system("/bin/echo","Hello Sam; rm *")

It prints "Hello Sam; rm*". rm* doesn't work here.

Increasing the $SAFE parameter to 1 or greater should also reduce the potential damage of these attacks.

Since Ruby and Rails are run on a virtual machine, the code is one step removed from the operating system. However, the system command can be used to access operating system commands. As stated above, the system command has some protections, but it is likely to have some vulnerabilities as well.

CWE-319: Cleartext Transmission of Sensitive Information

When software applications send sensitive information such as private data or authentication credentials across networks, the information crosses many different nodes in transit to its final destination. An attacker can gain access to it by controlling may be one node in the network.

For example, an attacker may find a username / password transmitted in cleartext and use this to do bad things. A SSL (Secure Socket Layer) plugin is available to prevent the cleartext transmission of sensitive information. To install it, issue the following command

   ruby script/plugin install ssl_requirement.  

And then include it at the top of your application.rb file, which effectively includes it in every controller:

   include SslRequirement

For each controller that require SSL put the following code at the top of each controller

   ssl_required  :login, :account 

Particular methods defined in the classes can also be protected methods as follows

   ssl_required :method1 :method2  

In the above scenario, any access to an action that requires SSL will automatically redirect to https://. If anyone tries to access a page that is supposed to be secure with an http:// link, they’ll be redirected. 16

ssl_allowed may be used to allow (but not require) the use of SSL. Note that TLS (Transport Layer Security) has replaced SSL, so this may be an outdated solution.

Consideration must also be given to not store sensitive information in the clear. Use Active Record hooks to perform AES128 encryption and decryption. Rails logging may log sensitive information, which could be accessed by attackers. Use the filter_parameter_logging :parameter1 :parameter2 to prevent logging of sensitive parameters. Clear sensitive data as soon as it is no longer needed [14]

CWE-352: Cross-Site Request Forgery '(CSRF)'

CSRF happens when an attacker tricks a user into activating a request that goes to your site. Due tpo modern scripting languages and the way web works in general, the user might not even be aware that the request is being sent. But once the request gets to your server, it looks as if it came from the user, not the attacker. If the user has administrative privileges then the attacker also gets access to system critical resources and can do any devastation.

Ruby on Rails is equipped to prevent this attack. Rails 2 or higher has a feature called protect_from_forgery which is specifically designed to combat attacks such as this. HTTP requests from browser generally provides two main types of requests – GET and POST. Some web browsers uses PUT and DELETE also but they are rare. Ruby has hidden_method field in order to handle this barrier. Use of GET and POST can prevent CSRF. A security token in non-GET requests will protect the application from CSRF. Ruby has a verify method which is defined in controller to make sure that specific actions may not be used over GET. 2 The following example to verifies the use of the transfer action over POST. If the action comes in using any other verb, it redirects to the list action.

  • Example::
   verify :method => :post, :only => [:transfer], :redirect_to => {:action => :list}

In the above example if the transfer action comes from any other web address, it redirects to the action list. So, CSRF will never happen. But only this will not protect from CSRF, because POST requests can be sent automatically. 
The solution to this is including a security token in non-GET requests which check on the server-side. In Rails 2 or higher, this is a one-liner in the application controller as follows

   protect_from_forgery :secret => "123456789012345678901234567890..." 

This will automatically include a security token, calculated from the current session and the server-side secret, in all forms and requests generated by Rails. The secret won't be needed, if CookieStorage is used as session storage. It will raise an ActionController::InvalidAuthenticityToken error, if the security token doesn’t match what was expected. 2

CWE-362: Race Condition

Definition of Race Condition can be found here. Ruby and Rails has testing tools (test unit / R-spec) which may be able to detect this. However, these testing tools may not catch such errors in all cases.

Example::
   Assume these two pieces of code can run in parallel
   Code section A    Code Section B
   @balance = 500    @balance = @balance + 100
   puts @balance

In the above example, the balance will usually read 500 from code section A. However, if the first line of code section A executes, then the Code Section B executes, then the print statement in A executes, the balance would read 600. The standard testing tools would most likely miss this error because it would happen very rarely.

Ruby provides the Mutex class 11 which can partially help avoid race conditions. The shared variable can be locked by one thread while it is being modified, then unlocked when the modification is done. This prevents some of the problems that can arise in race conditions, but can cause other problems, such as deadlock or livelock.

There does not appear to be a complete solution yet for the race condition in Ruby, or in any other languages.

CWE-209: Error Message Information Leak

While sending error messages to audience secrets can be discolsed to attacker. The secrets could cover a wide range of valuable data, such as personally identifiable information (PII), authentication credentials, full installation path of the software, server configuration etc. A very common way of error message information leak is from log files. For any web application programmers should restrict detailed error messages to trusted users only. Programmer may use password encryption everywhere but if they come in clear text in log files then attacker can read that. Ruby has filter_parameter_logging method that can be written in controller to filter confidential parameter values. 2 Ruby has error_messages_for helper methods also which can be written in order to secure application from error message information leak.

  • Example:
   filter_parameter_logging :password 
   In log files password will be shown as FILTERED.

Category: Risky Resource Management

SANS experts have identified the following errors as risky resource management errors.

CWE-119: Failure to Constrain Operations within the Bounds of a Memory Buffer

If the memory accessible by the attacker can be effectively controlled, it may be possible to execute arbitrary code, as with a standard buffer overflow.

Suppose, if the attacker can overwrite a pointer's worth of memory (usually 32 or 64 bits), he can redirect a function pointer to his own malicious code. Even when the attacker can only modify a single byte arbitrary code execution can be possible. Sometimes this is because the same problem can be exploited repeatedly to the same effect. Other times it is because the attacker can overwrite security-critical application-specific data such as a flag indicating whether the user is an administrator. Applications written in languages like C or C++ which give direct access to memory are more prone to this kind of attacks. Ruby doesn't give direct access to memory in comparison to other languages like C or C++. This feature of Ruby defends against this kind of attack.

CWE-642: External Control of Critical State Data

Unprotected data such as cookie information, data stored in environment variables, registry keys, configuration files, log files or profile data are vulnerable to attack. While transmitting user state information over stateless protocol such as HTTP attackers can get access to it. If any security critical operation is done based on this data then the system will be vulnerable to attack. So it is very important to protect this information. A common way to do this is to cipher these data using hashed message authentication code(HMAC). Ruby has ruby-hmac interface to provide HMAC functionality. Based on a secret key, HMAC provides integrity check of information stored in or transmitted over an unreliable medium. 6 Ruby has ability to store cookies and sessions in database tables which is much more secure against cookie theft or session theft. For this purpose ActiveRecordStore or CookieStore can be used. It is possible to configure the table name, primary key and data column in database table where cookie information or session information is to be stored. Information of these storage should be appended at the end of config/environment.rb: 17

 CGI::Session::ActiveRecordStore::Session.table_name = 'legacy_session_table'
 CGI::Session::ActiveRecordStore::Session.primary_key = 'session_id'
 CGI::Session::ActiveRecordStore::Session.data_column_name = 'legacy_session_data'

Data store in cookie should be tamper-proof and signed because session data can be visible at client. Ruby solution for this is to sign session data using the below information in config.rb file.

 Rails::Initializer.run do |config|
    config.action_controller.session = {
       :session_key => '_store_session',
       :secret      => 'deri3337903j3h9our9k1heu9w8ejqwk82'
    }
 end

Here the secret is encrypted which makes the data impossible to read.

Even the above process can made to be more secured by using SHA512 algorithm and using separate secret keys for each user. 18. Here is no need to pass encrypted data directly.

   config.action_controller.session = {
       :digest => 'SHA512',
       :secret => Proc.new { User.current.secret_key }
   }

CWE-73: External Control of File Name or Path

While data is often exchanged using files and sometimes we don't intend to expose every file on our system while doing so. When we use an outsider's input while constructing a filename, the resulting path could point outside of the intended directory. An attacker could combine multiple ".." or similar sequences to cause the operating system to navigate out of the restricted directory. Other file-related attacks are simplified by external control of a filename, such as symbolic link following, which causes the application to read or modify files that the attacker can't access directly. The same applies if our program is running with raised privileges and it accepts filenames as input.

All information from the outside world such as from files, sockets, environment variables etc. can be marked as tainted. The Ruby $SAFE parameter to be used to protect against this external control to the application by increasing it to a proper value. There are 5 $SAFE levels, represented by the integers 0 through 4. To set a $SAFE level, assign an integer to $SAFE. By default, $SAFE is set to 0. At this level, no extra checks will be performed by the Ruby interpreter. When running in a safe mode, potentially dangerous methods will raise a SecurityError if a tainted object is passed and tries to lower the value of $SAFE.19

  • Example: 20
  begin
      # Raise the security level
      $SAFE = 1
      # Try to lower the security level
      $SAFE = 0
      rescue SecurityError => e
      puts "Caught security exception: #{e}"
  end

CWE-426: Untrusted Search Path

Applications depend on its environment, to provide a search path so that it knows where it can find critical resources such as code libraries or configuration files. If the search path is under attacker control, then the attacker can modify it to point to any malicious code. This causes the software to access the wrong resource at the wrong time.

Again, the Ruby $SAFE parameter can be used to protect against this by increasing it to a proper value.

CWE-94: Failure to Control Generation of Code (aka 'Code Injection')

For the ease of development it is general trick to dynamically generate codes. It becomes a serious vulnerability when the code is directly callable by unauthorized parties who can contaminate inputs to the code and the result may be disastrous.

Ruby allows this, but only if the developer writes the program to allow it. If such functionality is provided in an application, it should be tested extensively. As Ruby is dynamically typed language, for dynamic testing Ruby has 7 which can crawl up the application and look for any break. Input validation should be done using an white box approach i.e. test those inputs which are allowed rather than testing those which are blacklisted because blacklist never ends. Ruby has very strong feature for input validation. See the Input validation section for this. Another mitigation is that Ruby is run in a virtual machine. This somewhat limits the damage that could be done (e.g. someone should not be able to format your C: drive (erase everything) from a remote site through a ruby application. There is still significant risk in allowing users to add their own code, and this functionality should be used sparingly, and tested thoroughly.

CWE-494: Download of Code Without Integrity Check

One way to fend off this attack is to digitally sign all binaries the programmer ship to customers with a private key and certificate issued by a trusted certification authority. Ruby also has features to prevent this attack 5. Sandboxes may be used to limit what damage the code can do, and parsers may be used to check the code before executing it.

CWE-404: Improper Resource Shutdown or Release

When system resources have reached their end-of-life, it is needed to dispose of them correctly. Otherwise, the environment may become heavily congested or contaminated. Attack can happen from memory leak, freeing invalid pointer, double-freeing etc. Attackers can exploit improper shutdown to maintain control over all those resources the programmer thinks he got rid of them. This can lead to significant resource consumption because nothing actually gets released back to the system.

Ruby has Memtrack API's to defend this attack. Patches MRI Ruby 1.8.7p72 can be used to add heap dumping, object reference finder, stack dumping or object allocation/deallocation tracking etc. 8 There are plugins available for Ruby to detect memory leak such as Bleakhouse. Detection is done by hammering ObjectSpace for information throughout the execution of the application and by producing pretty charts to show what's going on. 9

Another way to defend any attack due to memory leak is to log memory usage information before and after each request (but it is only for Linux). The following code is an example for this. 21

   #Put this in applictation_controller.rb
   before_filter :log_ram # or use after_filter
   def log_ram
      logger.warn 'RAM USAGE: ' + `pmap #{Process.pid} | tail -1`[10,40].strip
   end

CWE-665: Improper Initialization

Ruby has fuzzy crawler Tarantula to defend against this. Proper testing can reveal this kind of bug in the code. Ruby has Test unit and R-spec for efficient testing.

CWE-682: Incorrect Calculation

Test tools may be used to spot these errors. Test unit is provided with Rails, and R-spec is another test tool which may be used.

Category: Porous Defenses

CWE-327: Use of a Broken or Risky Cryptographic Algorithm

There are tools such as Clearance (a password utility), AES 128 encryption and SSL support in Ruby and Rails that provide secure cryptographic algorithims.

CWE-259: Hard-Coded Password

Rails has Clearance and Cucumber for this. Clearance is a tool for authentication with e-mail and password. Authentication check may be required as the application evolves and cucumber is used for that. 10

  • Example::
   def path_to(page_name)
   case page_name
   ...
   when /sign up page/i
   new_user_path
   when /sign in page/i
   new_session_path
   when /password reset request page/i
   new_password_path
   ...
   end

CWE-732: Insecure Permission Assignment for Critical Resource

Configuration store such as windows registry should be protected and permission given on all objects created in file system should be reviewed. This is mostly a manual effort.

CWE-330: Use of Insufficiently Random Values

Ruby provides the rand() function, but the default random functions are generally not sufficiently random. Other random number generators, such as these 12 have been developed in Ruby. It is tricky to determine if these, or the default rand() are sufficiently random for the particular application.

CWE-250: Execution with Unnecessary Privileges

Developers should use the minimum set of privileges required and reduce privileges when they are no longer needed.

CWE-602: Client-Side Enforcement of Server-Side Security

Active record (within rails) provides the attr_protected method which is used to protect records of the database. This allows the developer to specify which attributes to protect. Alternatively, attr_accessible can be used to protect everything except the values listed. Tarantula may detect this vulnerability through its fuzzed inputs test.

How Ruby and Rails security compares to other platforms

Ruby and Rails are fairly new. Security tools are currently being developed to combat many of the common security errors, but many of these tools have not reached maturity. Some are difficult to locate, install or use. Some are not yet well developed and are likely to miss common flaws. Most other languages have been around for longer so security tools have had more time for improvement.

One positive thing about Ruby and Rails is that they were built with security in mind. If security tools continue to be developed and incorporated into Ruby and Rails, the applications developed on them are likely to become more secure than those developed in other languages. Many languages were not originally developed with security in mind.

Appendix

Vulnerability: Susceptibility to attack. A detailed description can be found here

References

1. http://www.sans.org/top25errors/#s4 - Lists top 25 errors by category

2. http://guides.rubyonrails.org/security.html - Security features of Ruby

3. http://www.quarkruby.com/2007/9/20/ruby-on-rails-security-guide - Security features of Ruby

4. http://ieeexplore.ieee.org.www.lib.ncsu.edu:2048/stamp/stamp.jsp?tp=&arnumber=5054914&isnumber=5054895 - Top 25 errors

5. http://www.example-code.com/ruby/rubycerts.asp - Digital certificates examples

6. http://github.com/topfunky/ruby-hmac - An implementation of the HMAC message authentication code.

7. http://github.com/relevance/tarantula - A fuzzy spider for data validation

8. http://timetobleed.com/plugging-ruby-memory-leaks-heapstack-dump-patches-to-help-take-out-the-trash/ - Garbage collection in Ruby

9. http://www.rubyinside.com/bleakhouse-tool-to-find-memory-leaks-in-your-rails-applications-470.html - Ruby memory leak detector

10. http://github.com/thoughtbot/clearance/ - Password management using Clearance

11. http://www.ruby-doc.org/core/classes/Mutex.html - Explanation of the Mutex class for Ruby and how to use it

12. http://snippets.dzone.com/posts/show/4697 - Several random number generators written in Ruby

13. Thomas 2006, pp. 398 - 401

14. Ruby 2009, pp. 637 - 650

15. http://ar.rubyonrails.org/ - Input validation in Ruby

16. http://www.buildingwebapps.com/articles/6401-using-ssl-in-rails-applicati - Use of SSL

17. http://caboo.se/doc/classes/CGI/Session/ActiveRecordStore.html - Ruby ActiveRecordStore

18. http://www.rorsecurity.info/2007/11/20/rails-20-cookies/ - Rails CookieStore

19. http://www.rubycentral.com/pickaxe/taint.html - Securing application using Ruby SAFE

20. http://neworder.box.sk/news/18206 - Securing application using Ruby SAFE

21. http://stackoverflow.com/questions/161315/ruby-ruby-on-rails-memory-leak-detection - Ruby Memory Usage

Books referenced

  • Thomas, Dave (2006). Programming Ruby, The Pragmatic Programmers' Guide.
  • Ruby, Sam et al. (2009). Agile Web Development with Rails, Third Edition.

External Links