Fact of the weekRPC (Remote Procedure Call) is about the execution of functions on a remote host. RPC began with Sun Microsystems' (ONC) infra-structure for NFS, supported by Novell and AT&T. Apollo/Hewlett-Packard built a rival system (NCS) supported by IBM, DEC(Compaq) and Microsoft. Recently RPC systems have come to include the Java RMI, Microsoft's DCOM and CORBA. |
In last week's lecture we ended with a discussion of the Clark-Wilson model and the way in which it attempts to ensure data integrity by demanding that users employ specific programs, with limited functionality, in order to access data. This idea has an important parallel in object oriented programming techniques. All kinds of philosphical claims are made about the value of object orientation in programming, but perhaps the least controversial interpretation of object orientation is simply as a security framework for software integrity. It makes program data accessible on a need to know basis.
Roughly speaking, object orientation is a synthesis of two ideas: the classification or taxonomy of data into abstract types, and access control based on scope. Even in non-object based languages we have the idea of access control based on scope. e.g. in Algol, Pascal, C etc, we can define local variables within any set of brackets/* begin */ { int localvar; } /* end */When we pass parameters to functions and subroutines, the values of those parameters are copied into local storage. For instance, if we callfunction(i,j);in a program at one point, with the functional definition,function (int a, int b) { int localvar; a = 6; b = 7; }elsewhere, the change of a,b in the function has no effect on the value of the actual parameters i,j, unless we specifically ask for the access by passing a reference to the original variable (essentially by pointer).Semantic quibblers will not doubt argue about what object orientation means. For the purposes of this lecture we shall call anything which is not a linear, global language (GOTO languages with global variables) at least partially object oriented. Scope is a partial admission of objects. Atomic data types are primitive objects. Compound objects are present in Pascal (record) and C (struct). Simula, C++ and Java generalize data types to form classes which can contain not only primitive data objects but also specialized programs or methods which manipulate the data. Java goes even further by removing pointers, and insisting that users go through the compiler to access memeory.
Object orientation involves:
With nesting, we find a decrease in scope with increasing depth, but an increase in privacy.
- Scope controls or encapsulation (private,protected,public): Object data are hidden from general view (privacy).
- Actual and formal parameters (prevents sub-ordinate functions from altering higher level objects)
- Strong data types (identifies a very specific interpretation to data).
- Function prototyping (denies access to coding errors at compile time)
- Method invocation is restricted by access to a type (virtual functions/polymorphism). This makes processes/threads into objects with type.
- Comprehensibility make programs easier to secure.
- Inheritance/templates: well-defined defaults, less code means less scope for errors
- Message passing can be used to send data from an object, up to a higher level of the program (covert channel).
Like many other security systems, object orientation places demands on programmers. For some, the price is too high and programmers will work around object protection mechanisms. Constructing water-tight object models in non-trivial programs is very hard work. The investment of time is often a huge burden on programmers, since many new (experimental) programs cannot be specified accurately at the design state. Strong security is not conducive to prototyping of program concepts.
We find a decrease in security scope with increasing depth, but an increase in privacy. Encapsulation and inheritance work by the following rules:Global variables, pointers and reference passing act as covert channels, punching a hole in these security mechanisms.
- The security level of an object must be higher than the security level of its class object. (Higher means more secure)
- The security level of a virtual function/method (subject) must be greater than the security of the function which called it, and of the home or defining object. (This is the scope property)
- A virtual method can (execute,read,write) only members of its defining object.
- A virtual method can write into its defining object only if its security level is equal to that of the home object (i.e. recursion is protected).
- A virtual method can send a return value to the method which invoked it, only if it is at the same security level (as above).
- The security level of a newly created object is greater than the level of the object which creates it (objects do not leak).
Generalization is the enemy of security. Specialization is security's friend.Classes in C++ and Java not only classify data for building a private environment for their manipulation, there is a fair amount of supplementary technology which helps avoid programming errors. Let us examine an example from C++. (The only important difference between C++ and Java, in this context is that member functions are not defined within class braces {...} in C++.)
class Box : public Containers { public: // These can be used by any function Box(); // If properly written should avoid ~Box(); // memory leaks virtual void Empty(); // Can be overridden by subclasses. Overrides // parent class Containers with a more specialized // (more secure) function. static void Explode(); const void Examine(); // This function can be used as a covert channel to reveal private members to other objects. protected: // Can be used by member functions, // and dervived classes int careful1; float careful2; private: // Can only be used by member functions // or friends int secret1; char secret2; }Constructors/destructors and garbage collection
A problem which occurs in long running server processes is that they gradually use more and more memory, gradually choking the machine on which they are running (this has been a major problem for NT in its early versions). This occurs in programs which allocate memory but never free it again. Such an error is called a memory leak.Memory leaks are a security issue because programs which eat up a machine's memory can be used as the basis of a denial of service attack. Use of constructors and destructors does two things for us. It hands the problem of memory allocation to the compiler for local instantiations, so that the compiler performs the garbage collection automatically. It also ensures that new objects are initialized. Variables which are not initialised can also cause careless errors, as we saw in last week's exercises.
Java's memory allocation and garbage collection model is one of its main defenses against exploitation.
Static and const methods
- Methods which are declared static (silly name, acquired from its C background) are, in a sense, global to a class. Static methods are invoked from the (public) root class rather than from a local (private) instance of an object within the class. That means that they can break through internal class security barriers.
- Methods which are declared const do not change the state of the object on which they act. This is a security declaration which enables to compiler to check the truth of our intention.
Inheritance and virtual functions
The class hierarchy acts like an access control lattice. Multiple inheritance means that we might be able to access a function by several routes! Suppose we have classesclass alpha { public: int A; void functionA(); void printme(); }; class beta { public: int B; void functionB(); void printme(); }; class alphabet: public alpha, public beta { public: int *letter; void words(); }A call toalphabet *ptr; ptr->printme();is ambiguous, but not dangerous, since the compiler will complain, at least in C++ (it might be a problem in an interpreted language). The main problem with (multiple) inheritance is that it increases the burden on the programmer. Objects become available to a program, without necessarily becoming visible. The programmer might not be aware of the knock-on effects. In contrast to scope, inheritenance moves us upwards in a hierachy. It is possible that an object will inherit information which was not intented if the inheritance depth becomes too big.^ -------- | | | | U -------- | p / \ | w -------- -------- | a | | | | | r -------- -------- | d / \ / \ more more more moreMultiple inheritance is disallowed in Java. Instead, we have interfaces.Structures and unions
A struct datatype is like a class in which all of the members are public. It is only a conceptual and practical container for related data objects which makes some program syntax more transparent.A union on the other hand is something quite different. Unions were introduced in C in order to avoid the problem of memory fragmentation, which we discussed in the operating systems course. Unions have nothing to do with security, they have to do with efficiency.
Since the wave of adoration for structured programming languages brainwashed programmers into thinking that object orientation is the panacea of programming paradigms, it has become popular to say that the use of global variables is bad. This has now become dogma.Any arguments which apply to global variables also apply to public class members, since public members are global within their defining class. The purpose of global variables is to
Here are the arguments for and against global variables:
- Provide a line of covert communication between different parts of the program.
- Save memory and simplify coding.
Note that the argument that global variables make code difficult to read is just propaganda. It is easy to keep track of global variables by adopting a naming convention for variables, e.g. using UPPERCASE variable names for globals, or adding a suffix variable_glb etc.
- FOR: Global variables use less memory and accessing them is faster because there is no need to establish a new stack frame in each function. For example, an input buffer ought to be a global object. Global buffers are more secure than local ones, since global variables are stored in a different address space, away from the stack, i.e. buffer overflows in a global variable can not lead to stack corruption. In deep nesting of functinons, passing local parameters to each new level incurs a performance overhead and makes code messy.
- AGAINST: When access is free, it is too easy to lose track of which part of a program has changed the value of a global variable. Global variables do not mix with recursion, or multithreading.
One of the purposes of procedural languages is that a procedural structure allows code to be reused in libraries. Unix introduced shared libraries in order to make library access more efficient. Instead of copying an entire library onto every program, every program shares a library built of relocatable code. In order for a program to access a library function, it goes through a function broker or dynamic link loader (ld.so) which loads just the functions required by the process. Windows later adopted there own standard of DLL's (dynamically loadable library).Imagine now that shared libraries could be shared, not only between the programs on one machine, but across the network itself. This would be a distributed shared library. In an object oriented language, one can go one step further and define objects and object-methods, like the standard libraries of functions in C++, or Java which could be downloaded by any host. Of course, the problem then is that operating systems are not compatible or interoperable.
CORBA (The Common Object Request Broker Architecture) is a solution to this problem. It provides an infra-structure which is standardized, and which conceals the differences between operating systems and programming languages. It is a generic library service for objects. An Object Request Broker (ORB) is a `software bus' between clients (user programs ) and servers. It handles requests from clients and makes sure that they are executed on a server. Objects and methods are thus remotely executed and stored (CORBA is an RPC system). The user program becomes like a stub.
CORBA claims to be a secure architecture, suitable for multiuser environments. The CORBA security includes
Since CORBA is a service, it is able to restrict the operations carried out by clients and is thus able to ensure security. However, the security of the server must be assured in order for this to be true.
- Authentication.
- Security context establishment (session keys).
- Authorization and access control with ACLs and role based access control.
- Message protection (privacy).
- Auditing.
- Non-repudiation (unforgeable proof of transactions).
Thought for the weekCompiled languages perform many checks and provide warnings about potentially dangerous code. Does this make compiled languages more secure than script languages like, say, Perl or Visual Basic? |