CSC/ECE 517 Fall 2009/wiki1b 8 rubysecurity: Difference between revisions
(sixth) |
(seventh) |
||
Line 5: | Line 5: | ||
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 [citation needed], 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 [citation needed], 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 | ==Ruby on rails security measures against common programming errors== | ||
Synchronous to the classifiation of programming errors as cited in [citation], this section has three sub divisions or categories. | Synchronous to the classifiation of programming errors as cited in [citation], this section has three sub divisions or categories. | ||
Line 14: | Line 14: | ||
====Improper Input Validation==== | ====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. | 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 [citation] which is the ORM layer supplied with rails that relieves the programmer of dealing with the underlying databse 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 [citation] which is the ORM layer supplied with rails that relieves the programmer of dealing with the underlying databse 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 | sample code for Input validation | ||
class Student < ActiveRecord::Base | class Student < ActiveRecord::Base | ||
validates_presence_of :name, :sex, :age, :weight | validates_presence_of :name, :sex, :age, :weight | ||
Line 34: | Line 31: | ||
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 | ||
def validate | def validate | ||
Line 45: | Line 40: | ||
end | end | ||
[citation for : http://biodegradablegeek.com/2008/02/introduction-to-validations-validation-error-handling-in-rails/] | [citation for : http://biodegradablegeek.com/2008/02/introduction-to-validations-validation-error-handling-in-rails/] | ||
====Improper Encoding or Escaping of Output==== | ====Improper Encoding or Escaping of Output==== | ||
---- | ---- | ||
Line 53: | 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 metacharacter as the input to breach his/her privilege.[citataion:book] | 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 metacharacter as the input to breach his/her privilege.[citataion:book] | ||
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 [citataion:book] | The function from the above example can be replaced by [citataion:book] | ||
Users.find(:all, | Users.find(:all, | ||
:conditions => "name like '%?%'") | :conditions => "name like '%?%'") | ||
====Failure to Preserve Web Page Structure (aka 'Cross-site Scripting')==== | ====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. | 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 berfore displaying.[citataion:book] | 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 berfore displaying.[citataion:book] | ||
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.[citataion:book] | 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.[citataion:book] | ||
<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 78: | Line 67: | ||
An attacker will try and execute execute malicious code when an appliaction 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 appliaction 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, [citation : http://guides.rubyonrails.org/security.html#command-line-injection] | 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, [citation : http://guides.rubyonrails.org/security.html#command-line-injection] | ||
system("/bin/echo","hello; rm *") # prints "hello; rm *" and does not delete files | |||
====Cleartext Transmission of Sensitive Information ==== | ====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[citation:] and URL encoding[citataion:] 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)[citation:] 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 plugin to use SSL in a rails application. Include it at the top of application.rb file present in the directory app/contollers, which effectively includes it in every controller: | |||
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) ==== | ====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. | |||
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 ==== | ||
---- | ---- | ||
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 (SN), 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 possibilty 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. | |||
==== | === CATEGORY: Risky Resource Management === | ||
---- | |||
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. | |||
====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 and CookieStore. | |||
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: | |||
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 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 [[Link title | External Control of File Name or Path]] for information on ''$SAFE''. | |||
=== CATEGORY: Porous Defenses === | === CATEGORY: Porous Defenses === |
Revision as of 01:09, 22 September 2009
This article explores how the Ruby on Rails framework handles common dangerous programming errors committed in a web application and how it compares with other web application frameworks in terms of handling of these 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 [citation needed], 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 classifiation of programming errors as cited in [citation], this section has three sub divisions or categories.
CATEGORY: Insecure communication between components
This section contains the programming errors such as Improper Input validation, improper encoding of output,SQL injection etc.,
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 [citation] which is the ORM layer supplied with rails that relieves the programmer of dealing with the underlying databse 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
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 presnt" 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
[citation for : http://biodegradablegeek.com/2008/02/introduction-to-validations-validation-error-handling-in-rails/]
Improper Encoding or Escaping of Output
According to [citation needed : http://cwe.mitre.org/top25/#CWE-116], improper output encoding is the root for all injection basd attacks. The attacker can modify the output intended for other components in such a way that he /she can cause harm to the application, if the control information and metadata carried in the output is not properly seperated from the real data.
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 metacharacter as the input to breach his/her privilege.[citataion:book]
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 [citataion:book]
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 berfore displaying.[citataion:book] 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.[citataion:book]
Failure to Preserve OS Command Structure (aka 'OS Command Injection')
An attacker will try and execute execute malicious code when an appliaction 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, [citation : http://guides.rubyonrails.org/security.html#command-line-injection]
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[citation:] and URL encoding[citataion:] 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)[citation:] 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 plugin to use SSL in a rails application. Include it at the top of application.rb file present in the directory app/contollers, which effectively includes it in every controller:
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. 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 (SN), 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 possibilty 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.
CATEGORY: Risky Resource Management
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.
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 and CookieStore. 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:
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 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.
CATEGORY: 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 disclosureor modifcation 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 Base64 [citation:http://en.wikipedia.org/wiki/Base6]) 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 [citation:http://ezcrypto.rubyforge.org/]
@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 naiive 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 likelyhood of the vulnerability being exploited is very high as mentioned in [citation:http://cwe.mitre.org/data/definitions/259.html]. Rails recommends handling passwords by generating a ramdom 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. [citation: book]
def create_new_salt self.salt=self.object_id.to_s + rand.to_s end
Then the SHA is computed with following piece of code [citation: book]
private def self.encrypted_password(password, salt)
string_to_hash = password + “wibble” + 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 SHA1 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 [citation:http://en.wikipedia.org/wiki/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). Finally, if you just need a random float, just call rand with no arguments. [citation : http://www.codeodor.com/index.cfm/2007/3/25/Ruby-random-numbers/1042]
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 appliaction 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 calsl to the actions in the admin contoller. 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 thorugh. 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 elkse 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 [citation: book]
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 adminisration controller by adding the line
before_filter :authorize
Execution with Unnecessary Privileges
This error falls under the category of providing Role Based Access Control[Citation:]. 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.