CSC/ECE 517 Fall 2009/wiki1a 10 wolf27-Manhattan: Difference between revisions

From Expertiza_Wiki
Jump to navigation Jump to search
No edit summary
Line 103: Line 103:
The official Ruby site [3] contains a security section that list a number of current and past security vulnerabilities found.
The official Ruby site [3] contains a security section that list a number of current and past security vulnerabilities found.


<b>Java Security Features</b><br>


<b>Programs are not allowed to access arbitrary memory locations.<br></b>
== Java Security Features ==
 
'''''Programs are not allowed to access arbitrary memory locations'''''<br>
For example, casting between an
For example, casting between an
int and an Object is strictly illegal in Java.<br>
int and an Object is strictly illegal in Java.<br>


<b>Variables may not be used before they are initialized.<br></b>
'''''Variables may not be used before they are initialized'''''<br>
If a program were able to read the value of an uninitialized variable, the effect would be the same as if
If a program were able to read the value of an uninitialized variable, the effect would be the same as if
it were able to read random memory locations. A Java class wishing to exploit this defect might then
it were able to read random memory locations. A Java class wishing to exploit this defect might then
Line 116: Line 117:
they are used, and all instance variables in Java are automatically initialized to a default value.
they are used, and all instance variables in Java are automatically initialized to a default value.


<b>Objects cannot be arbitrarily cast into other objects.<br></b>
'''''Objects cannot be arbitrarily cast into other objects'''''<br>
Consider the below example.
Consider the below example.


public class CreditCard {<br>
public class CreditCard {<br>
private String acctNo;<br>
      private String acctNo;<br>
}<br>
}<br>


public class CreditCardSnoop {<br>
public class CreditCardSnoop {<br>
public String acctNo;<br>
      public String acctNo;<br>
}<br>
}<br>


Then the following code will not be allowed execute:
Then the following code will not be allowed execute:


CreditCard cc = Wallet.getCreditCard( );<br>
CreditCard cc = Wallet.getCreditCard( );<br>
CreditCardSnoop snoop = (CreditCardSnoop) cc;<br>
CreditCardSnoop snoop = (CreditCardSnoop) cc;<br>
System.out.println("Ha! Your account number is " + snoop.acctNo);<br><br>
System.out.println("Ha! Your account number is " + snoop.acctNo);<br><br>


Java does not allow arbitrary casting between objects; an object can only be cast to one of its
Java does not allow arbitrary casting between objects; an object can only be cast to one of its
Line 137: Line 138:


To satisfy the compiler code can be changed as follows:<br>
To satisfy the compiler code can be changed as follows:<br>
Object cc = Wallet.getCreditCard( );<br>
Object cc = Wallet.getCreditCard( );<br>
CreditCardSnoop snoop = (CreditCardSnoop) cc;<br>
CreditCardSnoop snoop = (CreditCardSnoop) cc;<br>


In this case, the virtual machine will throw a ClassCastException when the
In this case, the virtual machine will throw a ClassCastException when the
Line 144: Line 145:




<b>The Bytecode Verifier</b><br>
'''''The Bytecode Verifier'''''<br>
This is used to check whether the code compiled by the compiler is a legal java code. The Java verifier examines all such application byte code and, using a fancy set of heuristics, identifies code that doesn't play by the rules. Once byte code is verified, the virtual machine knows that it's safe to execute.  
This is used to check whether the code compiled by the compiler is a legal java code. The Java verifier examines all such application byte code and, using a fancy set of heuristics, identifies code that doesn't play by the rules. Once byte code is verified, the virtual machine knows that it's safe to execute.  
   
   
For example, consider the following classes
For example, consider the following classes


public class CreditCard {<br>
public class CreditCard {<br>
public String acctNo = "0001 0002 0003 0004";<br>
      public String acctNo = "0001 0002 0003 0004";<br>
}<br>
}<br>


public class Test {<br>
public class Test {<br>
public static void main(String args[]) {<br>
      public static void main(String args[]) {<br>
CreditCard cc = new CreditCard( );<br>
      CreditCard cc = new CreditCard( );<br>
System.out.println("Your account number is " + cc.acctNo);<br>
      System.out.println("Your account number is " + cc.acctNo);<br>
}<br>
      }<br>
}<br>
}<br>


If we run this code, we'll create a CreditCard object and print out its account number. If we change the definition of
If we run this code, we'll create a CreditCard object and print out its account number. If we change the definition of

Revision as of 13:58, 5 September 2009

Ruby and Java from a Security Perspective
Students: wolf 27 and Manhattan


Introduction

It is widely held that the three “pillars” of a secure system are confidentiality, availability, and integrity. That is, is a users data safe from unauthorized viewing/disclosure; is the users data available when they want it; and is the data the same as what they expected. There are many techniques, algorithms, and methods available to ensure these three pillars. The language used to develop the software on a secure system can play a major role in how effective in how algorithms, etc. help protect the confidentiality, availability, and integrity of secure data. This article compares two popular languages, Ruby and Java with respect to some of features of each language that aid in developing a secure software system.


In Java, Security can be considered in three contexts : 1) Virtual Machine Security 2) Application Security 3) Network Security

Ruby

“Safe Levels” in Ruby
Arguable one of Ruby’s features with respect to security is its “Safe Levels”. Ruby implements five levels of data checking to help prevent what its calls “tainted” variables from being used in other parts of the code where the system could be exploited.

All objects in Ruby are marked as “tainted” if they are derived from some external source. For example, an object is tainted if it read using ‘gets’, read from a file, is an environment variable, etc. Each Ruby object contains a method named, ‘tainted?’ as well as methods named ‘taint’ and ‘untaint’.

The ‘tainted?’ method is used to return a boolean value to indicate if the variable is tainted or not. Likewise, the ‘taint’ method is used to taint an untainted object and ‘untaint’ is used to remove a tainted label from an object. The code below shows a simple example of a String object becoming tainted.


#Tainted vs. Untainted
>> my_string = String.new             # A new string is created
=> ""
>> my_string.tainted?	              # The string is not tainted; there has been no external influence
=> false
>> my_string = "Hello"	              # Still no external influence
=> "Hello"
>> my_string.tainted?
=> false
>> my_string = my_string + gets       #Since part of the string now came from the console, it is tainted
World!
=> "Hello World!\n"
>> my_string.tainted?
=> true


To help manage tainted and untainted objects, Ruby define a built in constant named $SAFE that allows the user to define what “safe level”. The $SAFE variable is simply set at the beginning of the program in the way any other variable would be. For example,

$SAFE = 3

sets Ruby’s “safe level” to 3.

Each safe level allows (or disallows) certain actions, primarily based on whether an object is tainted or untainted. There are a few other operations that are also disallowed by Ruby at the various safe levels. Note that Ruby’s default safe level is 0, which means there all operates are allowed regardless of the the tainted status of the object. The books “Programming Ruby” [1] provides an excellent table to use as reference for the actives allowed and disallows at each safe level. Below are some highlight of each safe level.

$SAFE = 0
   Default “Safe Level”
   No additional security features
   All operations allowed on all untainted and tainted variables
$SAFE >= 1
   Calling the ‘glob’ or ‘eval’ methods on tainted strings is disallowed.
   Loading a file using a string that is tainted is disallowed.
   Executing system commands using a tainted string is disallowed.
$SAFE >= 2
   Loading a file from a source that is writable by ‘world’ is disallowed.
$SAFE >= 3
   All object created are tainted and no object may not be untainted using the untaint method.
$SAFE >= 4
   Essentially creates a Sandbox (an isolated, safe, place to run untrused code)
   Writing to files is disallowed
   Modifying global variable is disallowed.


Ruby’s Unbounded Polymorphism (a.k.a. Duck Typing) and Security
Ruby’s unbounded polymorphism functionally is arguably very powerful. However this power functionally could also create a potential problem with code developed. Since Ruby is a dynamically typed language, it is not possible to check and ensure that objects being used are of the expected type. If that object looks like another object, it can be treated as that object.

If not managed properly, an adversary or malicious piece of code could be executed unintentionally because of Ruby’s unbounded polymorphism. Consider the code below.

Class Good_code
     def good_method
          ... # some good code
     end
def another_good_method ... # some more good code end end

Class Bad_code def good_method ... #some BAD code, that looks good end
def another_good_method ... #some more bad code end end

def my_method(good_code) good_code.good_method good_code.another_good_method end
my_method(Bad_code.new)

In the example above, the malicious code will run, even though the developer of my_method thought and intended to only run code from the ‘good_code’ object. The developer must take greater caution when implementing code that takes another objects as to unintentionally execute a different object.

Automatic Bounds Checking
Ruby automatically checks bounds of data structures such as arrays. Bounds checking is very important to creating a secure system. If a user, intentionally or unintentionally, is able cause code to access an array index outside of the array, the system may crash, other data in memory may be overwritten, or unexpected (possibly private) data may be returned.

Cryptographic Libraries
The ability to perform basic cryptographic functions is necessary to help ensure the confidentially of data stored on a system (thought encryption) and the integrity of data (by cryptographic signature/hash). Ruby provides, built in, only a very limited set of cryptographic functionally. One such function is the String classes crypt method.

There are several open source library for performing cryptographic functions on objects available for Ruby such as crypt [2]. The crypt library provides access to such encryption algorithms AES, Blowfish, and IDEA.

Survey of Current and Past Publish Security Vulnerabilities
The official Ruby site [3] contains a security section that list a number of current and past security vulnerabilities found.


Java Security Features

Programs are not allowed to access arbitrary memory locations
For example, casting between an int and an Object is strictly illegal in Java.

Variables may not be used before they are initialized
If a program were able to read the value of an uninitialized variable, the effect would be the same as if it were able to read random memory locations. A Java class wishing to exploit this defect might then declare a huge uninitialized section of variables in an attempt to snoop the memory contents of the user's machine. To prevent this type of attack, all local variables in Java must be initialized before they are used, and all instance variables in Java are automatically initialized to a default value.

Objects cannot be arbitrarily cast into other objects
Consider the below example.

public class CreditCard {
private String acctNo;
}
public class CreditCardSnoop {
public String acctNo;
}

Then the following code will not be allowed execute:

CreditCard cc = Wallet.getCreditCard( );
CreditCardSnoop snoop = (CreditCardSnoop) cc;
System.out.println("Ha! Your account number is " + snoop.acctNo);

Java does not allow arbitrary casting between objects; an object can only be cast to one of its superclasses or its subclasses.

To satisfy the compiler code can be changed as follows:

Object cc = Wallet.getCreditCard( );
CreditCardSnoop snoop = (CreditCardSnoop) cc;

In this case, the virtual machine will throw a ClassCastException when the snoop variable is assigned to thwart the attack.


The Bytecode Verifier
This is used to check whether the code compiled by the compiler is a legal java code. The Java verifier examines all such application byte code and, using a fancy set of heuristics, identifies code that doesn't play by the rules. Once byte code is verified, the virtual machine knows that it's safe to execute.

For example, consider the following classes

public class CreditCard {
public String acctNo = "0001 0002 0003 0004";
}
public class Test {
public static void main(String args[]) {
CreditCard cc = new CreditCard( );
System.out.println("Your account number is " + cc.acctNo);
}
}

If we run this code, we'll create a CreditCard object and print out its account number. If we change the definition of acctNo to be private and recompile only the CreditCard class. We then have two class files and the Test class file contains Java code that illegally accesses the private instance variable acctNo of the CreditCard class and hence will not be allowed to execute.

References

[1] Hunt, Andrew and Thomas David. "Programming Ruby, The Pragmatic Programmer's Guide".
[2] "Crypt" Library Website: http://crypt[dot]rubyforge[dot]org/
[3] Ruby Website, Security Sections: http://www[dot]ruby-lang[dot]org/en/security/