Chapter 7: Security

Fundamentals

I say security but I don’t mean passwords or encryption. The Ruby security feature is used for handling untrusted objects in a environment like CGI programming.

For example, when you want to convert a string representing a number into a integer, you can use the eval method. However. eval is a method that “runs a string as a Ruby program.” If you eval a string from a unknown person from the network, it is very dangerous. However for the programmer to fully differentiate between safe and unsafe things is very tiresome and cumbersome. Therefore, it is for certain that a mistake will be made. So, let us make it part of the language, was reasoning for this feature.

So then, how Ruby protect us from that sort of danger? Causes of dangerous operations, for example, opening unintended files, are roughly divided into two groups:

For the former, the code that handles these values is created by the programmers themselves, so therefore it is (pretty) safe. For the latter, the program code absolutely cannot be trusted.

Because for these causes the solution is vastly different, it is important to differentiate them by level. This are called security levels. The Ruby security level is represented by the $SAFE global variable. The value ranges from minimum value 0 to maximum value 4. When the variable is assigned, the level increases. Once the level is raised it can never be lowered. And for each level, the operations are limited.

I will not explain level 1 or 3. Level 0 is the normal program environment and the security system is not running. Level 2 handles dangerous values. Level 4 handles dangerous code. We can skip 0 and move on to explain in detail levels 2 and 4.

Level 2

This level is for dangerous data, for example, in normal CGI applications, etc.

A per-object “dirty mark” serves as the basis for the Level 2 implementation. All objects read in externally are marked dirty, and any attempt to eval or File.open with a dirty object will cause an exception to be raised and the attempt will be stopped.

This dirty mark is “infectious”. For example, when taking a part of a dirty string, that part is also dirty.

Level 4

This level is for dangerous programs, for example, running external (unknown) programs, etc.

At level 2, operations and the data it uses are checked, but at level 4, operations themselves are restricted. For example, exit, file I/O, thread manipulation, redefining methods, etc. Of course, the dirty mark information is used, but basically the operations are the criteria.

Unit of Security

$SAFE looks like a global variable but is in actuality a thread local variable. In other words, Ruby’s security system works on units of thread. In Java and .NET, rights can be set per component (object), but Ruby does not implement that. The assumed main target was probably CGI.

Therefore, if one wants to raise the security level of one part of the program, then it should be made into a different thread and have its security level raised. I haven’t yet explained how to create a thread, but I will show an example here:

# Raise the security level in a different thread
p($SAFE)   # 0 is the default
Thread.fork {    # Start a different thread
    $SAFE = 4    # Raise the level 
    eval(str)    # Run the dangerous program
}
p($SAFE)   # Outside of the block, the level is still 0

Reliability of $SAFE

Even with implementing the spreading of dirty marks, or restricting operations, ultimately it is still handled manually. In other words, internal libraries and external libraries must be completely compatible and if they don’t, then the partway the “dirty” operations will not spread and the security will be lost. And actually this kind of hole is often reported. For this reason, this writer does not wholly trust it.

That is not to say, of course, that all Ruby programs are dangerous. Even at $SAFE=0 it is possible to write a secure program, and even at $SAFE=4 it is possible to write a program that fits your whim. However, one cannot put too much confidence on $SAFE (yet).

In the first place, functionality and security do not go together. It is common sense that adding new features can make holes easier to open. Therefore it is prudent to think that ruby can probably be dangerous.

Mounting

It enters into mounting from here, but to catch the security system of ruby completely , from the mechanism the margin which is rubbed “checking where?” you must see. But the page which this time does that it is not and, it just lists up one by one it is not funny.In this chapter explaining just the use [wa] [re] [ru] mechanism to security check temporarily, we have decided to finish then.API for check is two below mainly.

SafeStringValue() Here you do not read.

Pollution mark

The pollution mark the flag which is remembered> concretely in basic- flags with FL_TAINT, those where you are infected that OBJ_INFECT () are the macro which is said.

OBJ_TAINT(obj)            /* obj FL_TAINT is attached */
OBJ_TAINTED(obj)          /* obj You inspect whether FL_TAINT has been attached, */
OBJ_INFECT(dest, src)     /* src It is contagious FL_TAINT to empty destination */

OBJ_TAINT()OBJ_TAINTED()Assuming that how it is good OBJ_INFECT()Just you will see swiftly

OBJ_INFECT
 441  #define OBJ_INFECT(x,s) do {                             \
          if (FL_ABLE(x) && FL_ABLE(s))                        \
              RBASIC(x)->flags |= RBASIC(s)->flags & FL_TAINT; \
      } while (0)

(ruby.h)

FL_ABLE () you inspect whether or not VALUE of argument is the pointer. If both object the pointer (to be plugged, if flags there is a member,), the flag it is spread.

$SAFE

ruby_safe_level
 124  int ruby_safe_level = 0;

7401  static void
7402  safe_setter(val)
7403      VALUE val;
7404  {
7405      int level = NUM2INT(val);
7406
7407      if (level < ruby_safe_level) {
7408          rb_raise(rb_eSecurityError, "tried to downgrade safe level from %d to %d",
7409                   ruby_safe_level, level);
7410      }
7411      ruby_safe_level = level;
7412      curr_thread->safe = level;
7413  }

(eval.c)

The substance of $SAFE is ruby_safe_level of eval.c.As written first, because $SAFE is specific to the thread, because it was necessary to write on eval.c which has mounting the thread. In other words with circumstances of C language there just is eval.c, originally it is possible to another place to be.

safe_setter () is setter of global variable $SAFE. In other words because from Ruby level it can access only by way of this function, it becomes impossible to reduce level.

However seeing, because sort static has not been attached to ruby_safe_level, ignoring interface from C level, it can modify security level.

rb_secure()

rb_secure()
 136  void
 137  rb_secure(level)
 138      int level;
 139  {
 140      if (level <= ruby_safe_level) {
 141          rb_raise(rb_eSecurityError, "Insecure operation `%s' at level %d",
 142                   rb_id2name(ruby_frame->last_func), ruby_safe_level);
 143      }
 144  }

(eval.c)

When present safe level is above level, generating exception SecurityError.It is simple.


The original work is Copyright © 2002 - 2004 Minero AOKI.
Translated by Clifford Escobar CAOILE
Translations and Additions by C.E. Thornton
Creative Commons License
This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike2.5 License.