CSC/ECE 517 Fall 2009/wiki1b 8 rubysecurity: Difference between revisions

From Expertiza_Wiki
Jump to navigation Jump to search
(Final)
 
(12 intermediate revisions by the same user not shown)
Line 3: Line 3:
==Introduction==
==Introduction==


Almost all real world data and transactions are now available as web services which are created in some web application framework. As the number of such services increase, so do the possibility that attackers might try to exploit new loopholes in the application that is developed. The consequences of such attacks are far reaching and destructive in terms of business and security perspective. The danger is so grave that during January this year that experts from more than 30 US and international cyber security organizations jointly released the consensus list of the 25 most dangerous programming errors that lead to security bugs and that enable cyber espionage and cyber crime. Ruby on Rails [http://rubyonrails.org/ [1]], a MVC based application framework architecture, is used for designing web applications using Ruby language, comes with some features which can handle some of the common programming errors cited. In the next section we will see how each of these errors are handled according to their classification and in the third section we will see how Rails compares with other application framework in handling these errors.
Almost all real world data and transactions are now available as web services which are created in some web application framework. As the number of such services increase, so do the possibility that attackers might try to exploit new loopholes in the application that is developed. The consequences of such attacks are far reaching and destructive in terms of business and security perspective. The danger is so grave that during January this year that experts from more than 30 US and international cyber security organizations jointly released the consensus list of the 25 most dangerous programming errors that lead to security bugs and that enable cyber espionage and cyber crime. Ruby on Rails [http://rubyonrails.org/], a [http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller MVC] based application framework architecture, is used for designing web applications using Ruby language, comes with some features which can handle some of the common programming errors cited. In the next section we will see how each of these errors are handled according to their classification and in the third section we will see how Rails compares with other application framework in handling these errors.


==Ruby on rails security measures against common programming errors==
==Ruby on rails security measures against common programming errors==


Synchronous to the classification of programming errors as cited in [http://www.sans.org/top25errors/ [2]], this section has three divisions or categories.
Synchronous to the classification of programming errors as cited in [http://www.sans.org/top25errors/], this section has three divisions or categories.


===CATEGORY: Insecure communication between components===
===CATEGORY: Insecure communication between components===
----
----
This section contains the programming errors such as Improper Input validation, improper encoding of output,SQL injection etc., and five more error types which we will see now.
These weaknesses are related to insecure ways in which data is sent and received between separate components, modules, programs, processes, threads, or systems.
This section contains the programming errors such as Improper Input validation, improper encoding of output,SQL injection etc., and five other error types.


====Improper Input Validation====
====Improper Input Validation====
Line 17: Line 18:
Authorization is the process of checking whether a user has access to do what he wants to do. This automatically brings the issue of handling roles in the web application. If roles are not properly defined and implemented, an attacker can login as a genuine user by registering with your application and can perform unwanted reads / write which can lead to loss of sensitive information.
Authorization is the process of checking whether a user has access to do what he wants to do. This automatically brings the issue of handling roles in the web application. If roles are not properly defined and implemented, an attacker can login as a genuine user by registering with your application and can perform unwanted reads / write which can lead to loss of sensitive information.


Validation in Rails is very simple and short. We have to use the function ''validates''. Validation can be done with ActiveRecord [http://ar.rubyonrails.org/ [3]] which is the ORM layer supplied with rails that relieves the programmer of dealing with the underlying database and is the solid model foundation of Rails MVC architecture. ActiveRecord comes with a number of helper classes for validation. Using these helper classes, to check that a variable in the model is not null, we use ''validates_presence_of:'' followed by the field names that need to be validated. To check the length of a variable we use ''validates.lengthof:'' function.
Validation in Rails is very simple and short. We have to use the function ''validates''. Validation can be done with ActiveRecord [http://ar.rubyonrails.org/] which is the ORM layer supplied with rails that relieves the programmer of dealing with the underlying database and is the solid model foundation of Rails MVC architecture. ActiveRecord comes with a number of helper classes for validation. Using these helper classes, to check that a variable in the model is not null, we use ''validates_presence_of:'' followed by the field names that need to be validated. To check the length of a variable we use ''validates.lengthof:'' function.
The below code uses the validation helper methods of ActiveRecords which checks if the name of the student is not null or no symbols are present. It also checks whether the user with the same name already exists in the database as a new user is being created. The rest of the code is self-explanatory.
The below code uses the validation helper methods of ActiveRecords which checks if the name of the student is not null or no symbols are present. It also checks whether the user with the same name already exists in the database as a new user is being created. The rest of the code is self-explanatory.
sample code for Input validation [http://biodegradablegeek.com/2008/02/introduction-to-validations-validation-error-handling-in-rails/ [4]].
 
sample code for Input validation [http://biodegradablegeek.com/2008/02/introduction-to-validations-validation-error-handling-in-rails/].
   class Student < ActiveRecord::Base
   class Student < ActiveRecord::Base
     validates_presence_of :name, :sex, :age, :weight
     validates_presence_of :name, :sex, :age, :weight
Line 32: Line 34:
     validates_length_of :name, :allow_blank => false, :allow_nil => false, :maximum => 30
     validates_length_of :name, :allow_blank => false, :allow_nil => false, :maximum => 30
   end
   end
Without the ''validates ''helper method, the check for the format of the name can be done as
Without the ''validates ''helper method, the check for the format of the name can be done as
   class Student < ActiveRecord:Base
   class Student < ActiveRecord:Base
Line 44: Line 47:
----
----
If not much attention is paid as to how SQL queries are handled in the application code, attackers can modify / supply appropriate parameters so that they can gain access to sensitive information in the database such as Account database, which is not good from the security viewpoint.
If not much attention is paid as to how SQL queries are handled in the application code, attackers can modify / supply appropriate parameters so that they can gain access to sensitive information in the database such as Account database, which is not good from the security viewpoint.
For example in Ruby, the following function poses a serious security threat if the value for the ''conditions'' method comes from an external source. The attacker can pass a SQL meta-character as the input to breach his/her privilege.[5]  
 
For example in Ruby, the following function poses a serious security threat if the value for the ''conditions'' method comes from an external source. The attacker can pass a SQL meta-character as the input to breach his/her privilege[http://en.wikipedia.org/wiki/Special:BookSources/97809776166335 [5]].
   Users.find(:all,  
   Users.find(:all,  
               :conditions => "name like '%#{session[:user].name}'")
               :conditions => "name like '%#{session[:user].name}'")
Rails recommends that in order to avoid SQL injections, never to substitute anything into an SQL statement using the ruby's ''#''mechanism. Rails comes with a facility called ''blind variable'' for using in place of ''#''. It is nothing but having a ''placeholder'' in place of ''#''. If more than one placeholder is present in the query, ActiveRecord uses the corresponding input from the input array to substitute in the placeholder.
Rails recommends that in order to avoid SQL injections, never to substitute anything into an SQL statement using the ruby's ''#''mechanism. Rails comes with a facility called ''blind variable'' for using in place of ''#''. It is nothing but having a ''placeholder'' in place of ''#''. If more than one placeholder is present in the query, ActiveRecord uses the corresponding input from the input array to substitute in the placeholder.
The function from the above example can be replaced by [5]
 
The function from the above example can be replaced by
   Users.find(:all,  
   Users.find(:all,  
               :conditions => "name like '%?%'")
               :conditions => "name like '%?%'")
Line 55: Line 60:
----
----
Attackers are known to write simple javascript code in to an application's page using session cookies so that whenever a cookie destined for another legitimate user of the application is sent to that user, the attacker can redirect the cookie to be sent his/her computer. In this way an attacker can steal a legitimate users' identity.
Attackers are known to write simple javascript code in to an application's page using session cookies so that whenever a cookie destined for another legitimate user of the application is sent to that user, the attacker can redirect the cookie to be sent his/her computer. In this way an attacker can steal a legitimate users' identity.
To prevent this Rails recommends that the application we create never blindly display any data coming from an external source to be blindly displayed on the application's page. It recommends the application to convert such HTML codes into plain texts before displaying.[5]
 
Rails also comes with a helper method ''h(string)''  which is an alias for HTML escape, which performs the above mentioned escaping in Rails views. Rails also recommends using this helper method for any variable that is rendered in the view. The below code snippet shows how to render a user comment on to the application's view.[5]
To prevent this Rails recommends that the application we create never blindly display any data coming from an external source to be blindly displayed on the application's page. It recommends the application to convert such HTML codes into plain texts before displaying.
 
Rails also comes with a helper method ''h(string)''  which is an alias for HTML escape, which performs the above mentioned escaping in Rails views. Rails also recommends using this helper method for any variable that is rendered in the view. The below code snippet shows how to render a user comment on to the application's view[http://en.wikipedia.org/wiki/Special:BookSources/9780977616633 [5]].
   <div class="comment">
   <div class="comment">
       <%= h(user.comment)%> #user is the model for the current user
       <%= h(user.comment)%> #user is the model for the current user
Line 64: Line 71:
----
----
An attacker will try and execute execute malicious code when an application uses data from the user as a parameter to execute system level commands resulting in breach of security. This is because an attacker can execute another command through the input to a first command by appending a semicolon(;) or a vertical bar (|).
An attacker will try and execute execute malicious code when an application uses data from the user as a parameter to execute system level commands resulting in breach of security. This is because an attacker can execute another command through the input to a first command by appending a semicolon(;) or a vertical bar (|).
Ruby's ''exec(command)'', ''syscall(command)'', ''system(command)'' and ''\command'' are all vulnerable to such attacks. In order to avoid this Rails recommends programmers to use the system(command, parameters) method which passes command line parameters safely. For example, [http://guides.rubyonrails.org/security.html [7]]
 
Ruby's ''exec(command)'', ''syscall(command)'', ''system(command)'' and ''\command'' are all vulnerable to such attacks. In order to avoid this Rails recommends programmers to use the system(command, parameters) method which passes command line parameters safely. For example,
         system("/bin/echo","hello; rm *") # prints "hello; rm *" and does not delete files
         system("/bin/echo","hello; rm *") # prints "hello; rm *" and does not delete files


Line 70: Line 78:
----
----
If our software sends sensitive information across a network, attackers can sniff this data right off the wire. Trying to obfuscate traffic using schemes like [http://en.wikipedia.org/wiki/Base64 Base64] and URL encoding doesn't offer any protection, either since those encodings are for normalizing communications, not scrambling data to make it unreadable.
If our software sends sensitive information across a network, attackers can sniff this data right off the wire. Trying to obfuscate traffic using schemes like [http://en.wikipedia.org/wiki/Base64 Base64] and URL encoding doesn't offer any protection, either since those encodings are for normalizing communications, not scrambling data to make it unreadable.
This can be overcome in Rails by using Secure Socket Layer (SSL)[http://www.buildingwebapps.com/articles/6401-using-ssl-in-rails-applicati [6]] for entire session.
 
Assuming the SSL keys and certificates are setup and the Web server has been configured to use SSL.
This can be overcome in Rails by using [http://en.wikipedia.org/wiki/Transport_Layer_Security Secure Socket Layer (SSL)] for entire session. Assuming the SSL keys and certificates are setup and the Web server has been configured to use SSL.
Rails provides the ssl_requirement plug-in to use SSL in a rails application. Include it at the top of application.rb file present in the directory app/controllers, which effectively includes it in every controller [http://www.buildingwebapps.com/articles/6401-using-ssl-in-rails-applicati [6]]:
Rails provides the ssl_requirement plug-in to use SSL in a rails application. Include it at the top of application.rb file present in the directory app/controllers, which effectively includes it in every controller [http://www.buildingwebapps.com/articles/6401-using-ssl-in-rails-applicati [6]]:
         include SslRequirement
         include SslRequirement
Line 82: Line 90:
This attack method works by including malicious code or a link in a page that accesses a web application that the user is believed to have authenticated. If the session for that web application has not timed out, an attacker may execute unauthorized commands.
This attack method works by including malicious code or a link in a page that accesses a web application that the user is believed to have authenticated. If the session for that web application has not timed out, an attacker may execute unauthorized commands.
Most Rails applications use cookie-based sessions. Either they store the session id in the cookie and have a server-side session hash, or the entire session hash is on the client-side. In either case the browser will automatically send along the cookie on every request to a domain, if it can find a cookie for that domain. The controversial point is, that it will also send the cookie, if the request comes from a site of a different domain.
Most Rails applications use cookie-based sessions. Either they store the session id in the cookie and have a server-side session hash, or the entire session hash is on the client-side. In either case the browser will automatically send along the cookie on every request to a domain, if it can find a cookie for that domain. The controversial point is, that it will also send the cookie, if the request comes from a site of a different domain.
Rails uses a hidden _method field to handle this barrier [http://guides.rubyonrails.org/security.html [7]].
Rails uses a hidden _method field to handle this barrier [http://guides.rubyonrails.org/security.html [7]].
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.
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.
Line 100: Line 109:
Improper error messages may leak out secrets to an attacker. The secrets could cover a wide range of valuable data, including personally identifiable information (PII), authentication credentials, and server configuration. Sometimes, they might seem like harmless secrets that are convenient for users and admins, such as the full installation path of the software.
Improper error messages may leak out secrets to an attacker. The secrets could cover a wide range of valuable data, including personally identifiable information (PII), authentication credentials, and server configuration. Sometimes, they might seem like harmless secrets that are convenient for users and admins, such as the full installation path of the software.
Rails offer complete customization of default validation error messages it provides. change the entire contents of any validation error message. Make the application secure by reducing error message information leaks by writing customized ''error_messages_for'' helper.
Rails offer complete customization of default validation error messages it provides. change the entire contents of any validation error message. Make the application secure by reducing error message information leaks by writing customized ''error_messages_for'' helper.
A scaffold generated code uses the ''error_messages_for'' helper method which will display a single box at the top of the form showing all errors in the form. This method takes the model object as a parameter. The following is an example syntax for this method.
       
          <%= error_messages_for(:student)%> # student is the model object under consideration


===CATEGORY: Risky Resource Management===
===CATEGORY: Risky Resource Management===
----
----
If the software within a web application does not properly manage the creation, usage, transfer, or destruction of important system resources, all the resources within an application are at risk of being exploited.
This category contains errors such as Code Injection, Improper Resource Shutdown or Release , Failure to Constrain Operations within the Bounds of a Memory Buffer etc., and six other errors which will be covered in this section.
This category contains errors such as Code Injection, Improper Resource Shutdown or Release , Failure to Constrain Operations within the Bounds of a Memory Buffer etc., and six other errors which will be covered in this section.


====Failure to Constrain Operations within the Bounds of a Memory Buffer====
====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. Out of bounds memory access will very likely result in the corruption of relevant memory, and perhaps instructions, possibly leading to a crash. Other attacks leading to lack of availability are possible, including putting the program into an infinite loop. Buffer overflow attacks generally rely upon two techniques (and usually the combination). One is writing data to particular memory addresses and the other is having the operating system mishandle data types .
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. Out of bounds memory access will very likely result in the corruption of relevant memory, and perhaps instructions, possibly leading to a crash. Other attacks leading to lack of availability are possible, including putting the program into an infinite loop. Buffer overflow attacks generally rely upon two techniques (and usually the combination). One is writing data to particular memory addresses and the other is having the operating system mishandle data types.
 
Rails automatically eliminates buffer overflow attacks since it is a strongly-typed programming language, meaning that it will disallow direct memory access and thereby usually prevent buffer overflows from happening [http://www.owasp.org/index.php/Buffer_Overflows [8]].
Rails automatically eliminates buffer overflow attacks since it is a strongly-typed programming language, meaning that it will disallow direct memory access and thereby usually prevent buffer overflows from happening [http://www.owasp.org/index.php/Buffer_Overflows [8]].


Line 113: Line 129:
----
----
If you store that data in a place where an attacker can modify it, this also reduces the overhead for a successful compromise. For example, the data could be stored in configuration files, profiles, cookies, hidden form fields, environment variables, registry keys, or other locations, all of which can be modified by an attacker. In stateless protocols such as HTTP, some form of user state information must be captured in each request, so it is exposed to an attacker out of necessity.
If you store that data in a place where an attacker can modify it, this also reduces the overhead for a successful compromise. For example, the data could be stored in configuration files, profiles, cookies, hidden form fields, environment variables, registry keys, or other locations, all of which can be modified by an attacker. In stateless protocols such as HTTP, some form of user state information must be captured in each request, so it is exposed to an attacker out of necessity.
Rails suggests that all model requests are properly scoped, and for internal security, we need to make sure that confidential information isn’t leaking out in our logs, exception reports, and backups.
 
The sessions which maintain the state for HTTP is maintained by the rails framework and  provides several storage mechanisms for the session hashes. The most important are ActiveRecordStore [http://caboo.se/doc/classes/CGI/Session/ActiveRecordStore.html [9]] and CookieStore [http://www.rorsecurity.info/2007/11/20/rails-20-cookies/ [10]].
Rails suggests that all model requests are properly scoped, and for internal security, we need to make sure that confidential information isn’t leaking out in our logs, exception reports, and backups. The sessions which maintain the state for HTTP is maintained by the rails framework and  provides several storage mechanisms for the session hashes. The most important are ActiveRecordStore [http://caboo.se/doc/classes/CGI/Session/ActiveRecordStore.html [9]] and CookieStore [http://www.rorsecurity.info/2007/11/20/rails-20-cookies/ [10]].
 
ActiveRecordStore keeps the session id and hash in a database table and saves and retrieves the hash on every request. Thus keeping it in a safe storage from the attacker.
ActiveRecordStore keeps the session id and hash in a database table and saves and retrieves the hash on every request. Thus keeping it in a safe storage from the attacker.
CookieStore saves the session hash directly in a cookie on the client-side. The server retrieves the session hash from the cookie and eliminates the need for a session id. Hence in this case the client can see everything you store in a session. To prevent session hash tampering, a digest is calculated from the session with a server-side secret and inserted into the end of the cookie.
CookieStore saves the session hash directly in a cookie on the client-side. The server retrieves the session hash from the cookie and eliminates the need for a session id. Hence in this case the client can see everything you store in a session. To prevent session hash tampering, a digest is calculated from the session with a server-side secret and inserted into the end of the cookie.
That means the security of this storage depends on this secret (and on the digest algorithm, which defaults to [http://en.wikipedia.org/wiki/SHA_hash_functions SHA]512, which has not been compromised, yet). So 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 [http://glu.ttono.us/articles/2006/05/22/guide-environments-in-rails-1-1 [11]]:
That means the security of this storage depends on this secret (and on the digest algorithm, which defaults to [http://en.wikipedia.org/wiki/SHA_hash_functions SHA]512, which has not been compromised, yet). So 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 [http://glu.ttono.us/articles/2006/05/22/guide-environments-in-rails-1-1 [11]]:
Line 126: Line 144:
----
----
When you 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 your application to read or modify files that the attacker can't access directly.
When you 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 your application to read or modify files that the attacker can't access directly.
This vulnerability can be overcome by using ''$SAFE'', which is a global security parameter that Ruby provides.
This vulnerability can be overcome by using ''$SAFE'', which is a global security parameter that Ruby provides.
$SAFE controls a number of security features in the Ruby programming language. The higher you raise ''$SAFE'', the more restrictions the Ruby interpreter puts on your program. The ''$SAFE'' level [http://neworder.box.sk/news/18206 [12]] can only be raised, not lowered; malicious code cannot lower the ''$SAFE'' level [http://neworder.box.sk/news/18206 [12]]to escalate privileges.
$SAFE controls a number of security features in the Ruby programming language. The higher you raise ''$SAFE'', the more restrictions the Ruby interpreter puts on your program. The ''$SAFE'' level [http://neworder.box.sk/news/18206 [12]] can only be raised, not lowered; malicious code cannot lower the ''$SAFE'' level to escalate privileges.
There are 5 ''$SAFE'' levels [http://neworder.box.sk/news/18206 [12]], 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. If, when you try to assign an integer to ''$SAFE'' that is less than the current value of ''$SAFE'', a SecurityError exception will be raised. In addition, you can run Ruby scripts with a higher ''$SAFE'' level by supplying the -T switch to the Ruby interpreter.
 
''$SAFE'' level 1 [http://neworder.box.sk/news/18206 [12]] introduces the concept of tainted objects. Objects that accept input from external sources (files, sockets, environment variables, etc) will have the tainted flag set. This flag will follow all copies of the object, no matter how many times you filter or copy this object, it will always remain tainted. There are two methods that will help you manage tainted ''objects; Object#tainted?'' returns true if an object has the tainted flag set, and ''Object#untaint'' untaints the object.
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. If, when you try to assign an integer to ''$SAFE'' that is less than the current value of ''$SAFE'', a SecurityError exception will be raised. In addition, you can run Ruby scripts with a higher ''$SAFE'' level by supplying the -T switch to the Ruby interpreter.
 
''$SAFE'' level 1 introduces the concept of tainted objects. Objects that accept input from external sources (files, sockets, environment variables, etc) will have the tainted flag set. This flag will follow all copies of the object, no matter how many times you filter or copy this object, it will always remain tainted. There are two methods that will help you manage tainted ''objects; Object#tainted?'' returns true if an object has the tainted flag set, and ''Object#untaint'' untaints the object.


Ruby will refuse to accept tainted objects as arguments to some "dangerous" methods. For example, you can't pass a tainted object to require or load, or open a file whose filename is a tainted object. This forces you to properly sanitize all input and explicitly untaint it before you can use it. It's also easy to add a tainted check to your methods; if any arguments you'd like to be untainted fail the tainted? check, raise a SecurityError exception.
Ruby will refuse to accept tainted objects as arguments to some "dangerous" methods. For example, you can't pass a tainted object to require or load, or open a file whose filename is a tainted object. This forces you to properly sanitize all input and explicitly untaint it before you can use it. It's also easy to add a tainted check to your methods; if any arguments you'd like to be untainted fail the tainted? check, raise a SecurityError exception.
Line 148: Line 169:
     path is tainted
     path is tainted
     Caught security exception: Insecure operation - initialize
     Caught security exception: Insecure operation - initialize
One cannot open files whose names are tainted strings.''$SAFE'' level [http://neworder.box.sk/news/18206 [12]] one alone can make your Ruby programs much more secure. It forces you to be vigilant with input validation.
 
One cannot open files whose names are tainted strings.''$SAFE'' level one alone can make your Ruby programs much more secure. It forces you to be vigilant with input validation.


====Untrusted Search Path====
====Untrusted Search Path====
Line 158: Line 180:
----
----
Attackers can hack the download site, impersonate it with DNS spoofing [http://www.securesphere.net/download/papers/dnsspoof.htm [13]] or cache poisoning, convince the system to redirect to a different site, or even modify the code in transit as it crosses the network. This scenario even applies to cases in which your own product downloads and installs its own updates.
Attackers can hack the download site, impersonate it with DNS spoofing [http://www.securesphere.net/download/papers/dnsspoof.htm [13]] or cache poisoning, convince the system to redirect to a different site, or even modify the code in transit as it crosses the network. This scenario even applies to cases in which your own product downloads and installs its own updates.
This can be prevented by encrypting the code with a reliable encryption scheme before transmitting or using proper forward and reverse DNS look-up to detect against DNS spoofing. Rails provides a simple way to confirm with file names before they are downloaded on to the client. For example, The ''send_file()'' method sends files from the server to the client. If you use a file name, that the user entered, without filtering, any file can be downloaded:
This can be prevented by encrypting the code with a reliable encryption scheme before transmitting or using proper forward and reverse DNS look-up to detect against DNS spoofing. Rails provides a simple way to confirm with file names before they are downloaded on to the client. For example, The ''send_file()'' method sends files from the server to the client. If you use a file name, that the user entered, without filtering, any file can be downloaded:
       send_file('/var/www/uploads/' +  
       send_file('/var/www/uploads/' +  
Line 172: Line 195:
System resources that have reached their end-of-life need to be dispose off correctly. Otherwise, your environment will become heavily congested or contaminated. This applies to memory, files, cookies, data structures, sessions, communication pipes, and so on. Attackers can exploit improper shutdown to maintain control over those resources well after you thought you got rid of them.  
System resources that have reached their end-of-life need to be dispose off correctly. Otherwise, your environment will become heavily congested or contaminated. This applies to memory, files, cookies, data structures, sessions, communication pipes, and so on. Attackers can exploit improper shutdown to maintain control over those resources well after you thought you got rid of them.  
Ruby uses automatic garbage collectors [http://www.meshplex.org/wiki/Ruby/Ruby_on_Rails_programming_tutorials [14]] which overcomes this problem.
Ruby uses automatic garbage collectors [http://www.meshplex.org/wiki/Ruby/Ruby_on_Rails_programming_tutorials [14]] which overcomes this problem.
Garbage collection is done through ''GC'' module as well as ''ObjectSpace'' module.
In case of ''GC'' module, the code snippet
      GC.start # => nil
initiates garbage collection unless manually disabled.
In case of ''ObjectSpace'' module, the line
      ObjectSpace.garbage_collect
initiates garbage collection.


====Improper Initialization====
====Improper Initialization====
Line 177: Line 210:
If you don't properly initialize your data and variables, an attacker might be able to do the initialization for you, or extract sensitive information that remains from previous sessions. When those variables are used in security-critical operations, such as making an authentication decision, then they could be modified to bypass your security. Incorrect initialization can occur anywhere.
If you don't properly initialize your data and variables, an attacker might be able to do the initialization for you, or extract sensitive information that remains from previous sessions. When those variables are used in security-critical operations, such as making an authentication decision, then they could be modified to bypass your security. Incorrect initialization can occur anywhere.
In ruby uninitialized instance variables have a default value of nil, the sole-instance of the ''NilClass'' class which, expresses nothing. Hence unlike some other languages like C they donot contain any garbage value or previous runtime values [http://rosettacode.org/wiki/Variables [15]].
In ruby uninitialized instance variables have a default value of nil, the sole-instance of the ''NilClass'' class which, expresses nothing. Hence unlike some other languages like C they donot contain any garbage value or previous runtime values [http://rosettacode.org/wiki/Variables [15]].
Moreover, referencing an undefined global or instance variable returns nil. Referencing an undefined local variable throws a ''NameError'' exception, which could be appropriately handled using the raise construct.
Moreover, referencing an undefined global or instance variable returns nil. Referencing an undefined local variable throws a ''NameError'' exception, which could be appropriately handled using the raise construct.


Line 182: Line 216:
----
----
There are instances when the numerical operations lead to exceptions like Integer overflow [http://www.ruby-forum.com/topic/195251 [16]] and divide by zero errors. When attackers have some control over the inputs that are used in numeric calculations, this weakness can actually have security consequences.
There are instances when the numerical operations lead to exceptions like Integer overflow [http://www.ruby-forum.com/topic/195251 [16]] and divide by zero errors. When attackers have some control over the inputs that are used in numeric calculations, this weakness can actually have security consequences.
Integer overflow exceptions also occur in ruby and they can be handled with the raise construct.  
Integer overflow exceptions also occur in ruby and they can be handled with the ''raise'' construct. Ruby uses the kernel method ''raise''  to raise exceptions and uses a ''rescue'' clause to handle these exceptions.
Integers overflow behavior of Ruby is as follows, the interpreter converts a Fixnums (30 bits) into a Bignums (unlimited precision integers).
 
Ruby has an integer overflow vulnerability in the rb_ary_fill() function(as on Dec. 2008)[http://lwn.net/Articles/288566/ [17]] . For more details about the vulnerability refer [http://lwn.net/Articles/288566/ [17]].
The following example to calculate the factorial of the number will raise an exception when a negative number is passed as the argument.
      def factorial(n)
          raise "bad argument" if n < 1 #raise an exception if n is lesser than 1
          return 1 if n==1
          n*factorial(n-1) 
      end   
 
The ''rescue'' clause can be used to handle the above exception as follows
    rescue => ex #store exception in variable ex
        puts "#{ex.class}: #{ex.message}" #Handle exception by printing message
    end
Integers overflow behavior of Ruby is as follows: the interpreter converts a Fixnums (30 bits) into a Bignums (unlimited precision integers).
 
Ruby has an integer overflow vulnerability in the ''rb_ary_fill()'' function(as on Dec. 2008). For more details about the vulnerability, refer [http://lwn.net/Articles/288566/ [17]].


===CATEGORY: Porous Defenses===
===CATEGORY: Porous Defenses===
----
----
A web application must have a proper authentication and authorization mechanism to host sensitive web services such as online banking, online bidding etc., When the application does not ensure safety while sending sensitive data to an outside connection, our application is said to be having Porous defenses.
This category contains errors such as improper access control, Use of a Broken or Risky Cryptographic Algorithm , Hard-Coded Password, Use of Insufficiently Random Values and three more errors which will be covered in this section.
This category contains errors such as improper access control, Use of a Broken or Risky Cryptographic Algorithm , Hard-Coded Password, Use of Insufficiently Random Values and three more errors which will be covered in this section.


Line 193: Line 242:
----
----
Programmers who try to invent their own cryptographic environment for securing transfer of sensitive information mostly end up writing a broken or risky cryptographic algorithms. Brilliant mathematicians and scientists worldwide have broken their minds trying to perfect an algorithm which will be difficult to break. So a programmer is not expected to come up with a brand new algorithm. The programmer may be just re inventing the wheel and it results in an unnecessary risk that may lead to the disclosure or modification of sensitive information.
Programmers who try to invent their own cryptographic environment for securing transfer of sensitive information mostly end up writing a broken or risky cryptographic algorithms. Brilliant mathematicians and scientists worldwide have broken their minds trying to perfect an algorithm which will be difficult to break. So a programmer is not expected to come up with a brand new algorithm. The programmer may be just re inventing the wheel and it results in an unnecessary risk that may lead to the disclosure or modification of sensitive information.
Ruby allows easy implementation of advanced 128 and 256 bit algorithms such as [http://en.wikipedia.org/wiki/Advanced_Encryption_Standard AES]. Ruby allows using Active record hooks to perform AES encryption and decryption. Ezcrypto and Sentry are two such hooks. EzCrypto is optimized for simple encryption and decryption of strings. There are encrypt/decrypt pairs for normal binary use as well as for [http://en.wikipedia.org/wiki/Base64 Base64]encoded use.  It also provides a key class to generate keys as random or initialized with binary / Base 64 encoded data.  
Ruby allows easy implementation of advanced 128 and 256 bit algorithms such as [http://en.wikipedia.org/wiki/Advanced_Encryption_Standard AES]. Ruby allows using Active record hooks to perform AES encryption and decryption. Ezcrypto and Sentry are two such hooks. EzCrypto is optimized for simple encryption and decryption of strings. There are encrypt/decrypt pairs for normal binary use as well as for [http://en.wikipedia.org/wiki/Base64 Base64]encoded use.  It also provides a key class to generate keys as random or initialized with binary / Base 64 encoded data.  
An example piece of code for generating a random key and encrypting data using the generated key [http://ezcrypto.rubyforge.org/ [20]]
An example piece of code for generating a random key and encrypting data using the generated key [http://ezcrypto.rubyforge.org/ [18]]
             @key=EzCrypto::Key.generate #to generate a random key
             @key=EzCrypto::Key.generate #to generate a random key
             @encrypted=@key.encrypt("clear text")  # encrypting using previous gen key
             @encrypted=@key.encrypt("clear text")  # encrypting using previous gen key
Line 201: Line 251:
====Hard-Coded Password====
====Hard-Coded Password====
----
----
Passwords are generally used in both inbound and outbound authentications.Having hard coded passwords in an application sounds naive and we do not expect any programmer to do it. But when the constraints in terms of cost become tight, programmers do hard code passwords, even for sensitive accounts, within their application as it will reduce testing and support budget. If hard-coded passwords are used, it is almost certain that malicious users will gain access through the account in question. The likelihood of the vulnerability being exploited is very high as mentioned in [http://cwe.mitre.org/data/definitions/259.html [21]].
Passwords are generally used in both inbound and outbound authentications.Having hard coded passwords in an application sounds naive and we do not expect any programmer to do it. But when the constraints in terms of cost become tight, programmers do hard code passwords, even for sensitive accounts, within their application as it will reduce testing and support budget. If hard-coded passwords are used, it is almost certain that malicious users will gain access through the account in question. The likelihood of the vulnerability being exploited is very high as mentioned in [http://cwe.mitre.org/data/definitions/259.html [19]].
 
Rails recommends handling passwords by generating a random but unique salt value for each password and hashing them using 160-bit [http://en.wikipedia.org/wiki/SHA_hash_functions SHA] hashing algorithm and then storing the hash in the database.
Rails recommends handling passwords by generating a random but unique salt value for each password and hashing them using 160-bit [http://en.wikipedia.org/wiki/SHA_hash_functions SHA] hashing algorithm and then storing the hash in the database.
The salt is created by concatenating a random number and the object id of the user object. The salt’s value is then stored in the model object’s salt attribute[5].
 
The salt is created by concatenating a random number and the object id of the user object. The salt’s value is then stored in the model object’s salt attribute [http://en.wikipedia.org/wiki/Special:BookSources/9780977616633 [5]].
               def create_new_salt
               def create_new_salt
                   self.salt=self.object_id.to_s + rand.to_s
                   self.salt=self.object_id.to_s + rand.to_s
               end
               end
Then the [http://en.wikipedia.org/wiki/SHA_hash_functions SHA]is computed with following piece of code [5]
Then the [http://en.wikipedia.org/wiki/SHA_hash_functions SHA]is computed with following piece of code
               private
               private
                  def self.encrypted_password(password, salt)
              def self.encrypted_password(password,salt)
          string_to_hash = password + “wibble” + salt
                  string_to_hash=password + "something" + salt
            Digest::SHA1.hexdigest(string_to_hash)
                  Digest::SHA1.hexdigest(string_to_hash)
               End
               end
             
When an incoming authentication request arrives, the entered password is appended with a salt and hashed using [http://en.wikipedia.org/wiki/SHA_hash_functions SHA] 1 and it is stored in the password attribute of the user object. This is then compared to the stored password for that user in the database to check whether it is correct or not.
When an incoming authentication request arrives, the entered password is appended with a salt and hashed using [http://en.wikipedia.org/wiki/SHA_hash_functions SHA] 1 and it is stored in the password attribute of the user object. This is then compared to the stored password for that user in the database to check whether it is correct or not.


Line 218: Line 271:
----
----
Good randomness is necessary for the security features implemented in our web application using cryptographic algorithms to be effective and useful. If our application is using a normal [http://en.wikipedia.org/wiki/Pseudo-random_number_generator Pseudo Random Number Generator] then it is easy for the attacker to guess the next random number after some number of trials.  
Good randomness is necessary for the security features implemented in our web application using cryptographic algorithms to be effective and useful. If our application is using a normal [http://en.wikipedia.org/wiki/Pseudo-random_number_generator Pseudo Random Number Generator] then it is easy for the attacker to guess the next random number after some number of trials.  
Randomness is needed to produce session IDs and for generating nonces to prevent replay attacks.  
Randomness is needed to produce session IDs and for generating nonces to prevent replay attacks.
 
Rails make sure that the random number generated is random enough so that the attacker has very less probability of guessing the random number. For example, for generating session IDs in Rails, first a random number is generated where the random string is the current time, a random number between 0 and 1, the process id number of the Ruby interpreter (also basically a random number) and a constant string. This random string is then hashed using [http://en.wikipedia.org/wiki/MD5 MD5] and the resulting value is stored as session ID. The method to produce a random string is rand.
Rails make sure that the random number generated is random enough so that the attacker has very less probability of guessing the random number. For example, for generating session IDs in Rails, first a random number is generated where the random string is the current time, a random number between 0 and 1, the process id number of the Ruby interpreter (also basically a random number) and a constant string. This random string is then hashed using [http://en.wikipedia.org/wiki/MD5 MD5] and the resulting value is stored as session ID. The method to produce a random string is rand.
If you needed a random integer to simulate a roll of a six-sided die, you'd use: 1 + rand(6). A roll in craps could be simulated with 2 + rand (6) + rand(6) [http://www.codeodor.com/index.cfm/2007/3/25/Ruby-random-numbers/1042 [25]].
 
If you needed a random integer to simulate a roll of a six-sided die, you'd use: 1 + rand(6). A roll in craps could be simulated with 2 + rand (6) + rand(6) [http://www.codeodor.com/index.cfm/2007/3/25/Ruby-random-numbers/1042 [20]].
 
Finally, if you just need a random float, just call rand with no arguments.
Finally, if you just need a random float, just call rand with no arguments.


Line 231: Line 287:


If proper authorization mechanism is not implemented in the web application then we are not making sure that the users do what they can do. Attackers exploit this loophole to gain access to protected and sensitive files which they modify or delete.
If proper authorization mechanism is not implemented in the web application then we are not making sure that the users do what they can do. Attackers exploit this loophole to gain access to protected and sensitive files which they modify or delete.
Rails provides ''filters'' to make sure that only administrators have access to admin files and no user of the application can modify these files. ''beforefilter'' is used to intercept all calls to the actions in the admin controller. Here this function acts as an interceptor and checks the user id stored in the session to check if it is really the administrator who has requested the action. If yes, the action is allowed to go through. Else, it is blocked. This method is included as a part of ''ApplicationController'', the parent class of all the controllers in our Ruby application. Also the ''beforefilter'' method is restricted as a private method so that it is not visible to the end user or else the attacker can modify this method also.
Rails provides ''filters'' to make sure that only administrators have access to admin files and no user of the application can modify these files. ''beforefilter'' is used to intercept all calls to the actions in the admin controller. Here this function acts as an interceptor and checks the user id stored in the session to check if it is really the administrator who has requested the action. If yes, the action is allowed to go through. Else, it is blocked. This method is included as a part of ''ApplicationController'', the parent class of all the controllers in our Ruby application. Also the ''beforefilter'' method is restricted as a private method so that it is not visible to the end user or else the attacker can modify this method also.
An example ''beforefilter'' method which checks for admin login for continuing the action and if not prompts the user to log in as an admin [5]
An example ''beforefilter'' method which checks for admin login for continuing the action and if not prompts the user to log in as an admin [http://en.wikipedia.org/wiki/Special:BookSources/9780977616633 [5]].


       class ApplicationController < ActionController::Base
       class ApplicationController < ActionController::Base
Line 257: Line 314:


==Security Features Comparison of Rails with other Application Frameworks==
==Security Features Comparison of Rails with other Application Frameworks==
 
In this section we compare some of the security features of Rails with two of the most common application frameworks, Springs and Struts.


{| class="wikitable" border="1"
{| class="wikitable" border="1"
Line 324: Line 381:
4. [http://biodegradablegeek.com/2008/02/introduction-to-validations-validation-error-handling-in-rails/ Introduction to validations and validation error handling in Rails]
4. [http://biodegradablegeek.com/2008/02/introduction-to-validations-validation-error-handling-in-rails/ Introduction to validations and validation error handling in Rails]


5. Dave Thomas; David Heinemeier Hansson(2006). Agile Web Development with Rails. ISBN: 978-0-9776-1663-3
5. Dave Thomas; David Heinemeier Hansson(2006). Agile Web Development with Rails. [http://en.wikipedia.org/wiki/Special:BookSources/9780977616633 ISBN: 978-0-9776-1663-3]


6. [http://www.buildingwebapps.com/articles/6401-using-ssl-in-rails-applicati Using SSL in Rails applications]
6. [http://www.buildingwebapps.com/articles/6401-using-ssl-in-rails-applicati Using SSL in Rails applications]
Line 350: Line 407:
17. [http://lwn.net/Articles/288566/ Ruby: integer overflow]
17. [http://lwn.net/Articles/288566/ Ruby: integer overflow]


18. [http://en.wikipedia.org/wiki/Advanced_Encryption_Standard Wikipedia AES]
18. [http://ezcrypto.rubyforge.org/ EzCrypto - Easy to use Crypto for Ruby]
 
19. [http://en.wikipedia.org/wiki/Base6 Wikipedia Base64]
 
20. [http://ezcrypto.rubyforge.org/ EzCrypto - Easy to use Crypto for Ruby]
 
21. [http://cwe.mitre.org/data/definitions/259.html Common Weakness Enumeration -259: Hard-Coded Password]
 
22. [http://en.wikipedia.org/wiki/SHA Wikipedia SHA]
 
23. [http://en.wikipedia.org/wiki/Pseudo-random_number_generator Wikipedia Pseudo Random Number Generator]
 
24. [http://en.wikipedia.org/wiki/MD5 Wikipedia MD5]
 
25. [http://www.codeodor.com/index.cfm/2007/3/25/Ruby-random-numbers/1042 Ruby random numbers]


26. [http://en.wikipedia.org/wiki/RBAC Wikipedia Role Based Access Control]
19. [http://cwe.mitre.org/data/definitions/259.html Common Weakness Enumeration -259: Hard-Coded Password]


27. [http://de.wikipedia.org/wiki/Shared_Nothing_Architecture Wikipedia Shared Nothing Architecture]
20. [http://www.codeodor.com/index.cfm/2007/3/25/Ruby-random-numbers/1042 Ruby random numbers]

Latest revision as of 01:30, 29 September 2009

This article explores how the Ruby on Rails framework handles common dangerous programming errors committed in the development of a web application and how it compares with other web application frameworks in terms of handling these common errors.

Introduction

Almost all real world data and transactions are now available as web services which are created in some web application framework. As the number of such services increase, so do the possibility that attackers might try to exploit new loopholes in the application that is developed. The consequences of such attacks are far reaching and destructive in terms of business and security perspective. The danger is so grave that during January this year that experts from more than 30 US and international cyber security organizations jointly released the consensus list of the 25 most dangerous programming errors that lead to security bugs and that enable cyber espionage and cyber crime. Ruby on Rails [1], a MVC based application framework architecture, is used for designing web applications using Ruby language, comes with some features which can handle some of the common programming errors cited. In the next section we will see how each of these errors are handled according to their classification and in the third section we will see how Rails compares with other application framework in handling these errors.

Ruby on rails security measures against common programming errors

Synchronous to the classification of programming errors as cited in [2], this section has three divisions or categories.

CATEGORY: Insecure communication between components


These weaknesses are related to insecure ways in which data is sent and received between separate components, modules, programs, processes, threads, or systems. This section contains the programming errors such as Improper Input validation, improper encoding of output,SQL injection etc., and five other error types.

Improper Input Validation


Authorization is the process of checking whether a user has access to do what he wants to do. This automatically brings the issue of handling roles in the web application. If roles are not properly defined and implemented, an attacker can login as a genuine user by registering with your application and can perform unwanted reads / write which can lead to loss of sensitive information.

Validation in Rails is very simple and short. We have to use the function validates. Validation can be done with ActiveRecord [3] which is the ORM layer supplied with rails that relieves the programmer of dealing with the underlying database and is the solid model foundation of Rails MVC architecture. ActiveRecord comes with a number of helper classes for validation. Using these helper classes, to check that a variable in the model is not null, we use validates_presence_of: followed by the field names that need to be validated. To check the length of a variable we use validates.lengthof: function. The below code uses the validation helper methods of ActiveRecords which checks if the name of the student is not null or no symbols are present. It also checks whether the user with the same name already exists in the database as a new user is being created. The rest of the code is self-explanatory.

sample code for Input validation [4].

 class Student < ActiveRecord::Base
   validates_presence_of :name, :sex, :age, :weight
   validates_format_of :name,
                       :with => /^\w+$/,
                       :message => "is missing or invalid"
   validates_uniqueness_of :name,
                           :on => :create,
                           :message => "is already present"
   validates_inclusion_of :sex, :in => %w(M F), :message => 'must be M or F'
   validates_inclusion_of :age, :within => 18..40
   validates_length_of :name, :allow_blank => false, :allow_nil => false, :maximum => 30
 end

Without the validates helper method, the check for the format of the name can be done as

  class Student < ActiveRecord:Base
      def validate
         unless name && name=~/^\w+$/
            errors.add(:name, "is missing or invalid")
         end
      end
  end

Failure to Preserve SQL Query Structure (aka 'SQL Injection')


If not much attention is paid as to how SQL queries are handled in the application code, attackers can modify / supply appropriate parameters so that they can gain access to sensitive information in the database such as Account database, which is not good from the security viewpoint.

For example in Ruby, the following function poses a serious security threat if the value for the conditions method comes from an external source. The attacker can pass a SQL meta-character as the input to breach his/her privilege[5].

  Users.find(:all, 
             :conditions => "name like '%#{session[:user].name}'")

Rails recommends that in order to avoid SQL injections, never to substitute anything into an SQL statement using the ruby's #mechanism. Rails comes with a facility called blind variable for using in place of #. It is nothing but having a placeholder in place of #. If more than one placeholder is present in the query, ActiveRecord uses the corresponding input from the input array to substitute in the placeholder.

The function from the above example can be replaced by

  Users.find(:all, 
             :conditions => "name like '%?%'")

Failure to Preserve Web Page Structure (aka 'Cross-site Scripting')


Attackers are known to write simple javascript code in to an application's page using session cookies so that whenever a cookie destined for another legitimate user of the application is sent to that user, the attacker can redirect the cookie to be sent his/her computer. In this way an attacker can steal a legitimate users' identity.

To prevent this Rails recommends that the application we create never blindly display any data coming from an external source to be blindly displayed on the application's page. It recommends the application to convert such HTML codes into plain texts before displaying.

Rails also comes with a helper method h(string) which is an alias for HTML escape, which performs the above mentioned escaping in Rails views. Rails also recommends using this helper method for any variable that is rendered in the view. The below code snippet shows how to render a user comment on to the application's view[5].

     <%= h(user.comment)%> #user is the model for the current user

Failure to Preserve OS Command Structure (aka 'OS Command Injection')


An attacker will try and execute execute malicious code when an application uses data from the user as a parameter to execute system level commands resulting in breach of security. This is because an attacker can execute another command through the input to a first command by appending a semicolon(;) or a vertical bar (|).

Ruby's exec(command), syscall(command), system(command) and \command are all vulnerable to such attacks. In order to avoid this Rails recommends programmers to use the system(command, parameters) method which passes command line parameters safely. For example,

       system("/bin/echo","hello; rm *") # prints "hello; rm *" and does not delete files

Cleartext Transmission of Sensitive Information


If our software sends sensitive information across a network, attackers can sniff this data right off the wire. Trying to obfuscate traffic using schemes like Base64 and URL encoding doesn't offer any protection, either since those encodings are for normalizing communications, not scrambling data to make it unreadable.

This can be overcome in Rails by using Secure Socket Layer (SSL) for entire session. Assuming the SSL keys and certificates are setup and the Web server has been configured to use SSL. Rails provides the ssl_requirement plug-in to use SSL in a rails application. Include it at the top of application.rb file present in the directory app/controllers, which effectively includes it in every controller [6]:

       include SslRequirement

Now all that is needed to be specified is, at the top of each controller, which controller actions require SSL. For example :

       ssl_required  :login, :account, :payment, :cart

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.

Cross-Site Request Forgery (CSRF)


This attack method works by including malicious code or a link in a page that accesses a web application that the user is believed to have authenticated. If the session for that web application has not timed out, an attacker may execute unauthorized commands. Most Rails applications use cookie-based sessions. Either they store the session id in the cookie and have a server-side session hash, or the entire session hash is on the client-side. In either case the browser will automatically send along the cookie on every request to a domain, if it can find a cookie for that domain. The controversial point is, that it will also send the cookie, if the request comes from a site of a different domain.

Rails uses a hidden _method field to handle this barrier [7]. 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. But this was only the first step, because POST requests can be sent automatically too. 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:

      protect_from_forgery :secret => 
      "123456789012345678901234567890..."

Race Condition


Race condition is the scenario where multiple processes attempt to use the exact same shared resource at exactly the same time. Rails framework follows the Shared nothing architecture, which describes a Distributed Computing-architecture, where each node independently and autonomously to carry out its task with its own processor and associated storage components such as hard disk and memory and not a specific, individual node to connect to a database is necessary. Hence this avoids the possibility of processes having to access a shared resource.Moreover the default ruby interpreter is also thread safe(correct functioning during simultaneous execution)

Error Message Information Leak


Improper error messages may leak out secrets to an attacker. The secrets could cover a wide range of valuable data, including personally identifiable information (PII), authentication credentials, and server configuration. Sometimes, they might seem like harmless secrets that are convenient for users and admins, such as the full installation path of the software. Rails offer complete customization of default validation error messages it provides. change the entire contents of any validation error message. Make the application secure by reducing error message information leaks by writing customized error_messages_for helper.

A scaffold generated code uses the error_messages_for helper method which will display a single box at the top of the form showing all errors in the form. This method takes the model object as a parameter. The following is an example syntax for this method.

          <%= error_messages_for(:student)%> # student is the model object under consideration

CATEGORY: Risky Resource Management


If the software within a web application does not properly manage the creation, usage, transfer, or destruction of important system resources, all the resources within an application are at risk of being exploited.

This category contains errors such as Code Injection, Improper Resource Shutdown or Release , Failure to Constrain Operations within the Bounds of a Memory Buffer etc., and six other errors which will be covered in this section.

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. Out of bounds memory access will very likely result in the corruption of relevant memory, and perhaps instructions, possibly leading to a crash. Other attacks leading to lack of availability are possible, including putting the program into an infinite loop. Buffer overflow attacks generally rely upon two techniques (and usually the combination). One is writing data to particular memory addresses and the other is having the operating system mishandle data types.

Rails automatically eliminates buffer overflow attacks since it is a strongly-typed programming language, meaning that it will disallow direct memory access and thereby usually prevent buffer overflows from happening [8].

External Control of Critical State Data


If you store that data in a place where an attacker can modify it, this also reduces the overhead for a successful compromise. For example, the data could be stored in configuration files, profiles, cookies, hidden form fields, environment variables, registry keys, or other locations, all of which can be modified by an attacker. In stateless protocols such as HTTP, some form of user state information must be captured in each request, so it is exposed to an attacker out of necessity.

Rails suggests that all model requests are properly scoped, and for internal security, we need to make sure that confidential information isn’t leaking out in our logs, exception reports, and backups. The sessions which maintain the state for HTTP is maintained by the rails framework and provides several storage mechanisms for the session hashes. The most important are ActiveRecordStore [9] and CookieStore [10].

ActiveRecordStore keeps the session id and hash in a database table and saves and retrieves the hash on every request. Thus keeping it in a safe storage from the attacker.

CookieStore saves the session hash directly in a cookie on the client-side. The server retrieves the session hash from the cookie and eliminates the need for a session id. Hence in this case the client can see everything you store in a session. To prevent session hash tampering, a digest is calculated from the session with a server-side secret and inserted into the end of the cookie. 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 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 [11]:

     config.action_controller.session = { 
     :key => '_app_session', :secret => '0x0dkfj3927dkc7djdh36rkckdfzsg...' } 

Rails also provides secure logging to protect log files. We can filter certain request parameters from your log files by the filter_parameter_logging method in a controller. These parameters will be marked [FILTERED] in the log.

     filter_parameter_logging :password

External Control of File Name or Path


When you 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 your application to read or modify files that the attacker can't access directly.

This vulnerability can be overcome by using $SAFE, which is a global security parameter that Ruby provides. $SAFE controls a number of security features in the Ruby programming language. The higher you raise $SAFE, the more restrictions the Ruby interpreter puts on your program. The $SAFE level [12] can only be raised, not lowered; malicious code cannot lower the $SAFE level to escalate privileges.

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. If, when you try to assign an integer to $SAFE that is less than the current value of $SAFE, a SecurityError exception will be raised. In addition, you can run Ruby scripts with a higher $SAFE level by supplying the -T switch to the Ruby interpreter.

$SAFE level 1 introduces the concept of tainted objects. Objects that accept input from external sources (files, sockets, environment variables, etc) will have the tainted flag set. This flag will follow all copies of the object, no matter how many times you filter or copy this object, it will always remain tainted. There are two methods that will help you manage tainted objects; Object#tainted? returns true if an object has the tainted flag set, and Object#untaint untaints the object.

Ruby will refuse to accept tainted objects as arguments to some "dangerous" methods. For example, you can't pass a tainted object to require or load, or open a file whose filename is a tainted object. This forces you to properly sanitize all input and explicitly untaint it before you can use it. It's also easy to add a tainted check to your methods; if any arguments you'd like to be untainted fail the tainted? check, raise a SecurityError exception.

   begin
       # Raise the security level
       $SAFE = 1
       # Read from $stdin, then try to open a file with a tainted object
       path = gets.strip
       puts "path is tainted" if path.tainted?
       f = File.open( path )
       rescue SecurityError => e
       puts "Caught security exception: #{e}"
   end


   % ./taint2.rb
   path is tainted
   Caught security exception: Insecure operation - initialize

One cannot open files whose names are tainted strings.$SAFE level one alone can make your Ruby programs much more secure. It forces you to be vigilant with input validation.

Untrusted Search Path


If a search path is under attacker control, then the attacker can modify it to point to resources of the attacker's choosing. The same risk exists if a single search path element could be under attacker control, such as the current working directory. Ruby’s $SAFE security parameter can be used to avoid this. Refer to the section External Control of File Name or Path for information on $SAFE.

Download of Code Without Integrity Check


Attackers can hack the download site, impersonate it with DNS spoofing [13] or cache poisoning, convince the system to redirect to a different site, or even modify the code in transit as it crosses the network. This scenario even applies to cases in which your own product downloads and installs its own updates.

This can be prevented by encrypting the code with a reliable encryption scheme before transmitting or using proper forward and reverse DNS look-up to detect against DNS spoofing. Rails provides a simple way to confirm with file names before they are downloaded on to the client. For example, The send_file() method sends files from the server to the client. If you use a file name, that the user entered, without filtering, any file can be downloaded:

      send_file('/var/www/uploads/' + 
      params[:filename]) 

Simply pass a file name like “../../../etc/passwd” to download the server’s login information. A simple solution against this, is to check that the requested file is in the expected directory:

      basename = 
      File.expand_path(File.join(File.dirname(__FILE__), '../../files')) filename = 
      File.expand_path(File.join(basename, @file.public_filename)) raise if basename 
      =! File.expand_path(File.join(File.dirname(filename), '../../../')) send_file 
      filename, :disposition => 'inline'

Improper Resource Shutdown or Release


System resources that have reached their end-of-life need to be dispose off correctly. Otherwise, your environment will become heavily congested or contaminated. This applies to memory, files, cookies, data structures, sessions, communication pipes, and so on. Attackers can exploit improper shutdown to maintain control over those resources well after you thought you got rid of them. Ruby uses automatic garbage collectors [14] which overcomes this problem.

Garbage collection is done through GC module as well as ObjectSpace module. In case of GC module, the code snippet

     GC.start # => nil

initiates garbage collection unless manually disabled. In case of ObjectSpace module, the line

     ObjectSpace.garbage_collect

initiates garbage collection.

Improper Initialization


If you don't properly initialize your data and variables, an attacker might be able to do the initialization for you, or extract sensitive information that remains from previous sessions. When those variables are used in security-critical operations, such as making an authentication decision, then they could be modified to bypass your security. Incorrect initialization can occur anywhere. In ruby uninitialized instance variables have a default value of nil, the sole-instance of the NilClass class which, expresses nothing. Hence unlike some other languages like C they donot contain any garbage value or previous runtime values [15].

Moreover, referencing an undefined global or instance variable returns nil. Referencing an undefined local variable throws a NameError exception, which could be appropriately handled using the raise construct.

Incorrect Calculation


There are instances when the numerical operations lead to exceptions like Integer overflow [16] and divide by zero errors. When attackers have some control over the inputs that are used in numeric calculations, this weakness can actually have security consequences. Integer overflow exceptions also occur in ruby and they can be handled with the raise construct. Ruby uses the kernel method raise to raise exceptions and uses a rescue clause to handle these exceptions.

The following example to calculate the factorial of the number will raise an exception when a negative number is passed as the argument.

     def factorial(n)
         raise "bad argument" if n < 1 #raise an exception if n is lesser than 1
         return 1 if n==1
         n*factorial(n-1)  
     end     

The rescue clause can be used to handle the above exception as follows

    rescue => ex #store exception in variable ex
       puts "#{ex.class}: #{ex.message}" #Handle exception by printing message
    end

Integers overflow behavior of Ruby is as follows: the interpreter converts a Fixnums (30 bits) into a Bignums (unlimited precision integers).

Ruby has an integer overflow vulnerability in the rb_ary_fill() function(as on Dec. 2008). For more details about the vulnerability, refer [17].

CATEGORY: Porous Defenses


A web application must have a proper authentication and authorization mechanism to host sensitive web services such as online banking, online bidding etc., When the application does not ensure safety while sending sensitive data to an outside connection, our application is said to be having Porous defenses.

This category contains errors such as improper access control, Use of a Broken or Risky Cryptographic Algorithm , Hard-Coded Password, Use of Insufficiently Random Values and three more errors which will be covered in this section.

Use of a Broken or Risky Cryptographic Algorithm


Programmers who try to invent their own cryptographic environment for securing transfer of sensitive information mostly end up writing a broken or risky cryptographic algorithms. Brilliant mathematicians and scientists worldwide have broken their minds trying to perfect an algorithm which will be difficult to break. So a programmer is not expected to come up with a brand new algorithm. The programmer may be just re inventing the wheel and it results in an unnecessary risk that may lead to the disclosure or modification of sensitive information.

Ruby allows easy implementation of advanced 128 and 256 bit algorithms such as AES. Ruby allows using Active record hooks to perform AES encryption and decryption. Ezcrypto and Sentry are two such hooks. EzCrypto is optimized for simple encryption and decryption of strings. There are encrypt/decrypt pairs for normal binary use as well as for Base64encoded use. It also provides a key class to generate keys as random or initialized with binary / Base 64 encoded data. An example piece of code for generating a random key and encrypting data using the generated key [18]

            @key=EzCrypto::Key.generate #to generate a random key
            @encrypted=@key.encrypt("clear text")  # encrypting using previous gen key
            @decrypted=@key.decrypt(@encrypted)

Hard-Coded Password


Passwords are generally used in both inbound and outbound authentications.Having hard coded passwords in an application sounds naive and we do not expect any programmer to do it. But when the constraints in terms of cost become tight, programmers do hard code passwords, even for sensitive accounts, within their application as it will reduce testing and support budget. If hard-coded passwords are used, it is almost certain that malicious users will gain access through the account in question. The likelihood of the vulnerability being exploited is very high as mentioned in [19].

Rails recommends handling passwords by generating a random but unique salt value for each password and hashing them using 160-bit SHA hashing algorithm and then storing the hash in the database.

The salt is created by concatenating a random number and the object id of the user object. The salt’s value is then stored in the model object’s salt attribute [5].

              def create_new_salt
                 self.salt=self.object_id.to_s + rand.to_s
              end

Then the SHAis computed with following piece of code

              private
              def self.encrypted_password(password,salt)
                 string_to_hash=password + "something" + salt
                 Digest::SHA1.hexdigest(string_to_hash)
              end 
              

When an incoming authentication request arrives, the entered password is appended with a salt and hashed using SHA 1 and it is stored in the password attribute of the user object. This is then compared to the stored password for that user in the database to check whether it is correct or not.

Use of Insufficiently Random Values


Good randomness is necessary for the security features implemented in our web application using cryptographic algorithms to be effective and useful. If our application is using a normal Pseudo Random Number Generator then it is easy for the attacker to guess the next random number after some number of trials. Randomness is needed to produce session IDs and for generating nonces to prevent replay attacks.

Rails make sure that the random number generated is random enough so that the attacker has very less probability of guessing the random number. For example, for generating session IDs in Rails, first a random number is generated where the random string is the current time, a random number between 0 and 1, the process id number of the Ruby interpreter (also basically a random number) and a constant string. This random string is then hashed using MD5 and the resulting value is stored as session ID. The method to produce a random string is rand.

If you needed a random integer to simulate a roll of a six-sided die, you'd use: 1 + rand(6). A roll in craps could be simulated with 2 + rand (6) + rand(6) [20].

Finally, if you just need a random float, just call rand with no arguments.

Client-Side Enforcement of Server-Side Security


Trusting clients to perform security checks on behalf of the server is not a good idea because the attackers can reverse engineer the client and can write their own custom clients to bypass authentication and authorization. To avoid this situation, Rails recommends that the authorization mechanism and input validation mechanism (refer to Improper Input validation from the section 2.1.1) be implemented properly.

Improper Access Control (Authorization)


If proper authorization mechanism is not implemented in the web application then we are not making sure that the users do what they can do. Attackers exploit this loophole to gain access to protected and sensitive files which they modify or delete.

Rails provides filters to make sure that only administrators have access to admin files and no user of the application can modify these files. beforefilter is used to intercept all calls to the actions in the admin controller. Here this function acts as an interceptor and checks the user id stored in the session to check if it is really the administrator who has requested the action. If yes, the action is allowed to go through. Else, it is blocked. This method is included as a part of ApplicationController, the parent class of all the controllers in our Ruby application. Also the beforefilter method is restricted as a private method so that it is not visible to the end user or else the attacker can modify this method also. An example beforefilter method which checks for admin login for continuing the action and if not prompts the user to log in as an admin [5].

     class ApplicationController < ActionController::Base
         private
         def authorize
            unless User.find_by_id(session[:user_id])
               flash[:notice]="log in as admin to proceed"
               redirect_to(:controller => "login", :action => "login") 
            end
         end
     end 

This method can be invoked before performing any actions in the administration controller by adding the line

      before_filter :authorize

Execution with Unnecessary Privileges


This error falls under the category of providing Role Based Access Control ]. Therefore we need to provide proper authorization mechanisms for avoiding this error. Refer to Improper Access Control (Authorization) to see how this can be achieved.

Insecure Permission Assignment for Critical Resource


This error too is as a result of improper handling of authorization. Refer to the section Improper Access Control (Authorization) to see how this can be achieved.


Security Features Comparison of Rails with other Application Frameworks

In this section we compare some of the security features of Rails with two of the most common application frameworks, Springs and Struts.

Security Feature Rails (Ruby) Spring (Java) Struts (Java)
Authorization a beforefilter is used to intercept all calls to the actions to check the user and his/her role before the action is processed a security manager level exists between the caller and service which intercepts the request and checks for access rights of the caller. implemented in the RequestProcessor portion of the "Controller" via the RequestProcessor.processRoles method
Input Validation uses the helper class validates of ActiveRecord Spring uses a validator interface to validate objects. A validation class is written implementing this interface so that its features can be used in the validation class. There is a validator plug-in and after it is loaded into the application, have to extend org.apache.struts.validator.action.ValidatorForm instead of org.apache.struts.action.ActionForm.Then when the validate method is called, the action's name attribute from the struts-config.xml is used to load the validations for the current form.


Race Condition Uses no shared architecture to avoid race condition, hence easy and elegant design to implement thread safe code. Uses Data access abstraction to prevent race condition. designing thread safe methods not as elegant as rails Methods accessing shard objects have to explicitly take care of cached values of objects(values cannot be stored in field but rather always passed as parameters) in order to make it thread safe.So not an elegant solution
SQL injection attack: could be still be performed if vulnerable sql statements are constructed by the programmer manually. Cannot be performed Cannot be performed
Storage of session data: On disk or database, inherently less secure since person with access to server can view private files on the server stores session data in memory, hence more secure for against this particular vulnerability stores session data in memory, hence more secure for against this particular vulnerability
CSRF attacks: provides good defense against CSRF by inclusion of tokens. Rails MVC has enough official clear documentations to prevent it Spring MVC documentation doesnt provide clear guidance in defending against these attacks Struts has enough documentation. Provides the tokenSessionInterpreter to prevent CSRF attacks
Validation Integration with Model Object A fundamental idea in object programming is to unite data with related actions. In rails, the Model Object should typically encapsulate both data and validations. Spring MVC takes validation out of your Model Objects (its proper home), and moves it into a separate class having a single method In Struts 1, data validation is completely separated from the Model Object.

Conclusion

Security in web applications is a very sensitive issue but they can be easily ignored by programmers. It is highly imperative that they go through all the possible attack methods which can be made on an application. It is also important that they understand the security features of the framework using which they develop the web application. As such, there is no framework which provides web security features as a plug and play tool. All frameworks come with some features which help attain the security levels needed. In the end it is the job of the programmer to implement them in the correct manner. Ruby on Rails also is one such framework. It comes with features which are easy to understand and implement by the programmer. Threats to web applications are always evolving and attackers are finding new ways to exploit the vulnerabilities in an application’s implementation. It may be said that it is not possible to prevent such attacks but with strong security features, programmers can be in a better position to reduce its effects on their application. In this article we have discussed ways in which Rails implements its security features in order to assist the programmer in repeating such mistakes.

References

1. Ruby on Rails

2. CWE/SANS TOP 25 Most Dangerous Programming Errors

3. Active Record — Object-relation mapping put on rails

4. Introduction to validations and validation error handling in Rails

5. Dave Thomas; David Heinemeier Hansson(2006). Agile Web Development with Rails. ISBN: 978-0-9776-1663-3

6. Using SSL in Rails applications

7. Ruby on Rails Security Guide

8. Buffer Overflows

9. RecordActiveStore

10. Ruby On Rails Secuirty Project- Rails 2.0 Cookies

11. Guide: Environments in Rails 1.1

12. NewOrder - Secure Programming With Ruby (Part 1)

13. DNS Spoofing techniques

14. Meshplex-Ruby/Ruby on Rails programming tutorials2

15. RosettaCode-Variables

16. RubyForum-Ruby Overflow behavior

17. Ruby: integer overflow

18. EzCrypto - Easy to use Crypto for Ruby

19. Common Weakness Enumeration -259: Hard-Coded Password

20. Ruby random numbers