You are on page 1of 9

Applying

extension is a general-purpose one, it has


significant benefits in the realm of security.
The aspect-oriented technique allows secu-

Aspect-Oriented rity policies to be separate from the code,


enabling developers to write the main appli-
cation and a security expert to specify secu-

Programming to rity properties. Also, this technique can


abstract away much of the expert knowl-
edge currently required for writing secure

Security code, allowing developers to reasonably


secure their software even if a security
expert is not available to assist.

Our approach is general enough to be


applied to any language, and in the future
we anticipate experimenting with extensions
by John Viega, J.T. Bloch, and Pravir Chandra for several different languages. At present,

A spect-oriented programming (AOP) is a new programming paradigm


that explicitly promotes separation of concerns. In the context of secu-
rity, this would mean that the main program should not need to encode
we focus on C because there are several
classes of common security vulnerabilities
in that language. Further, despite any draw-
security information; instead, it should be moved into a separate, indepen- backs of C, it is still widely used to write
dent piece of code. The object-oriented paradigm can sometimes separate security-critical applications.
concerns in an intuitive manner by grouping
concerns into objects. However, the object-
oriented paradigm is only good at sepa- MOTIVATION
rating out concepts that map easily to Experience has shown that developers
concrete objects. It does not map well to aren’t very good at writing secure software.
abstract notions. For example, it is difficult Part of the problem is a lack of education;
to model security in the object-oriented few classes cover this material, and no
paradigm. While one could write a central books cover it well. However, education
SecurityManager class for an application, isn’t the entire issue, as evidenced by the
calls to this class and important checks will fact that buffer overflow exploits in C code
necessarily be spread throughout the code are quite common, even in software written
base. Unfortunately, if a critical check is by developers who know a lot about this
forgotten in an important spot in the code, problem.
the central class will not have the opportu-
nity to recover. This problem exists because We think it should be easier to design secu-
security is a concern that affects the entire rity into an application, instead of relying
system in a broad way. Aspect-oriented on the “penetrate-and-patch” approach to
programming can solve this problem by security, where problems are addressed in
allowing security concerns to be specified an ad hoc manner, generally as flaws are
modularly and applied to the main program revealed in the field. Unfortunately, the
in a uniform way. penetrate-and-patch approach to security is
widespread, as opposed to the alternative
All work described in this article
1 We have built an aspect-oriented extension of designing software with security in mind.
was done at Cigital, Inc. to the C programming language.1 While this

Vol. 14, No. 2 February 2001 31


There are two primary reasons why this PRINCIPLES
problem is so prevalent. The first is that no In talking with many developers about
coherent design time methodologies or security, we have noticed that even security-
tools are widely available. In fact, there are aware people find it much easier to write
no comprehensive resources available to their program and then later go back and try
help write secure programs; developers to “bolt on” security as an afterthought. In
do not know what the problems are. As a our experience, this approach doesn’t work;
result, developers continue to write insecure Currently, security generally needs to be
code and to fix security problems when designed into an application from the begin-
someone happens to notice them. The ning. There is a fundamental conflict here
second problem is that designing and between what works well in practice and
implementing secure systems currently the way developers work, even when they
Developers continue to requires a lot of expert knowledge. Even are well educated on security matters.
with good methodologies, good tools are
write insecure code and to All tools we have encountered to help
still critical to alleviating this problem, as
fix security problems when the average developer is likely to be either prevent security vulnerabilities in general-
unwilling or unable to use the methodology purpose programming languages are after-
someone happens to the-fact tools, such as vulnerability analysis
effectively if no tools are available.
notice them. tools that look for common programming
Another large part of the problem is the and configuration errors. They do not
state of programming languages from a address how a developer should design and
security point of view. A few languages implement software in a security-conscious
have given significant thought to security manner. Our aspect-oriented extension
primitives that should be present to help provides a more proactive approach to this
programmers write better code. However, problem. We designed the language with
two of the most widely used programming the following principles in mind:
languages, C and C++, present significant
security risks. This is because many of their n The amount of expert knowledge neces-
standard features can easily be used in such sary to secure source code should be
minimized. It should not be easy for a
a way as to inadvertently leave a security
developer to accidentally introduce
flaw in a program. Even languages with
security problems into a program just
significant security architectures, such as
because the language and the concepts
Java, leave something to be desired. While
of secure programming haven’t been
looking at many commercial products, we
mastered. Common language pitfalls
have found that a large percentage of appli-
should be averted, and the programmer
cations have significant security problems
should be protected from common
that are present in the design phase and
classes of mistakes that are not language
persist through to implementation despite
specific.
the language used. Some of the more
common problems include misuse of secu- n The security-related elements in a
rity protocols and an unrealistic view of program should be abstracted out of the
what a system should consider “trusted.” program proper, for the sake of clarity,
Languages have yet to make significant maintainability, and reuse.
inroads in these areas. n Security policies should be defined using
a language general enough that it is

32 February 2001 Vol. 14, No. 2 ©2001 Cutter Information Corp.


possible to create new policies to deal 1. Insert code before points of interest
with application-specific issues or previ-
2. Insert code after points of interest
ously unknown security vulnerabilities.
3. Replace the code at the point of interest
n An emphasis should be placed on “secu-
rity by default,” so that the level of effort There are several types of locations we can
for developing secure applications is operate upon:
minimized. This is a bigger challenge for
C than for most other languages, since 1. Calls to functions. For example, we can
the language and standard libraries replace all calls to functions prone to
contain so many unsafe operations. buffer overflows with safe alternatives.

n Currently, if a security consideration is 2. Function definitions. Inserting code


omitted in just one place, it can easily around a function definition will ensure
If a security consideration
lead to a flaw. It should be easy to the code runs every time the function
express policies about the program that runs. Just operating on calls to functions is omitted in
apply generically to a consideration, and will not catch calls from third-party
just one place,
then have the policy be applied through libraries.
the program automatically. For example, it can easily lead to a flaw.
3. Pieces of functions. If a function uses
it should be possible to say that no
jump labels, we can operate on a line of
secret information is ever sent over the
code following a label, or we can operate
network unencrypted (perhaps the
on a block of code between two labels.
actual implementation may choose to
encrypt all data to satisfy this property). In our language, an aspect is a program-
ming construct that lives in its own file. It
n Legacy source code with known or
specifies points of interest and operations to
potential security problems should be
be applied on those points of interest.
able to benefit from such a tool; the
amount of new code necessary should Here is an example aspect that allows us
be minimized. It should also be possible to replace all calls to the rand() call with
to avoid modifying the original program, a secure replacement. The rand() call is
since doing so tends to introduce errors. undesirable because its output is completely
predictable and reproducible.
n When it makes sense to do so, security
policies should be reusable across aspect secure_random {
different applications. int secure_rand(void) {
/**
* Secure call to random defined here.
LANGUAGE */
The purpose of our aspect language is to }
specify structured transformations on a
funcCall<int rand(void)> {
program. Usually this involves inserting code
replace {
at well-defined points. However, it may
secure_rand();
occasionally involve removing code. Once }
we have specified points of interest in our }
code, there are three things we can do: }

Get the Cutter Edge free: www.cutter.com/consortium/ Vol. 14, No. 2 February 2001 33
The function secure_rand is like any other C such functionality, our language has an any
function. In this example, it will implement keyword, which can be used in place of any
a secure random number generation algo- type specifier. For example, we could say
rithm. The “funcCall” keyword specifies that any ?(any) to match all functions taking one
we wish to match calls to functions. The parameter, or any ?(any *) to specify all
function we wish to match is specified functions with one parameter that is a
between the angle brackets. In this case, we pointer.
wish to match calls to rand. We specify the
In order to match variable argument
function by its signature, noting that rand
functions, we support a “…” operator.
takes no arguments and returns an integer.
For example, to match calls to the fprintf
The “replace” keyword specifies that we
function, we can specify fprintf(FILE*,
wish to run code instead of calling rand().
char *, ...).
The code inside the replace block will run
instead.
Context Gathering
At compile time, our language takes any The code constituting a transformation will
aspects, along with the regular C program, often depend on the site matching the
and “weaves” them into a single C program, aspect model. Our language provides vari-
which is then compiled. ables containing useful contextual informa-
tion. For instance, a transformation may
Wildcarding need information about the function
Allowing the programmer to easily specify containing the matching site, or the module
patterns describing interesting constructs containing that function, or even the file
makes the aspect language significantly currently undergoing transformation. Just as
more powerful, but it also introduces impor- the preprocessor variable __FILE__ provides
tant subtleties into the language. We support the fully qualified file name, the aspect
three types of matching facilities: name, language variables __FUNCTION__,
type, and argument matching. __MODULE__, and __ASPECT__ provide
information about the function, module, and
Name matching allows the programmer to
aspect related to the current transformation.
indicate an interest in functions, files, or
We expect this set of context-gathering vari-
modules whose names match a pattern.
ables to expand in future versions of the
We use the ? (question mark) construct to
language.
specify wildcards in names. The wildcard
construct stands for zero or more charac- Order and Precedence Concerns
ters. For instance, foo? matches foo, foobar, The order in which transformations are
and foofoofoo, but it would not match applied and how conflicts between transfor-
barfoo. mations are arbitrated represent an area
Using name matching, the programmer can remaining open to inquiry. To see that appli-
focus on the functions int foo(char), and int cation order is an issue and conflicts are
foobar(char) by specifying the pattern int possible, consider transformations A and B,
foo?(char). However, additional facilities are where A removes all calls to the insecure
required to specify an interest in functions function exec(...) and B logs information
that take a single argument, where we don’t about all such invocations. If the transforma-
care what type of argument it is. To support tions are applied in order AB, we would not

34 February 2001 Vol. 14, No. 2 ©2001 Cutter Information Corp.


expect information about exec calls in the language independent. In general, a security
log file, since they are all removed. If trans- concern such as secure random generation
formations are applied in order BA, the log is independent of the language in which the
file would remain empty, but the logging application is written. A small exception to
code will never get executed. Which of this is the case in which a security concern
these alternatives is desirable? We currently does not exist with the language being
ignore this problem, disallowing all conflicts. used; for example, buffer overflows don’t
One promising option is to provide guidance exist in applications written in pure Java. In
to the compile-time “weaver” by specifying cases such as this, the security concern can
aspects that govern the order in which other be thought of as being addressed by a null
aspects transform the source code. aspect — one with no transforms. In any
case, we can assemble a list of our security
concerns in some meta-language such as a
APPLYING AOP TO SECURITY simple configuration file that lists all the
This general-purpose programming security concerns we have, along with any
language has many applications to security. special language-independent parameters
We previously gave an example of replacing for them (e.g., specify “secure random
insecure function calls with secure replace- numbers” as a security concern and specify
ments, but there are plenty of other uses in “my-secure-algorithm” as a parameter to
this domain: the aspect that will address this problem).
Given a common interface for the aspects
n It can be used to automatically perform
that address the same concerns regardless
error checking on security-critical calls.
of the language the aspect was written for,
n We can use it to implement the we can create a configuration file that, given
StackGuard technique of buffer overflow a weaver for the language in which our
protection, inserting special code at source is written and a suite of security
function entry and exit. aspects for that language, can be applied to
n It can automatically log data that may be any program source and assure it is secure
relevant to security. against the concerns noted within. This
meta-language provides a powerful tool for
n It can be used to replace generic socket people to automate the securing of their
code with SSL socket code. applications.
n It can automatically insert code at
startup that goes through a set of “lock-
Example
down” procedures that most program- The following example shows a more prac-
mers would not add to their programs. tical example of how our technique applies
to real programs. First, we build a library of
n It can be used to specify privileged security aspects that we wish to apply to our
sections of a program and to automati- program. For example, we might wish to
cally request and return privileges when replace calls to rand and perform automatic
appropriate. error checking on calls to malloc (though
An aspect weaver with a suite of aspects this is only rarely a security problem and is
that address security concerns is generally more a reliability problem):

Get the Cutter Edge free: www.cutter.com/consortium/ Vol. 14, No. 2 February 2001 35
aspect secure_random {
int secure_rand(void) {
/**
* Secure call to random defined here. Any other accompanying
* functions can be defined in the same scope as this function.
*/
return 0;
}

void support_function(void) {
}

funcCall<int rand(void)> {
replace {
secure_rand();
}
}
}

aspect malloc_check {
funcCall<void * malloc(size_t x)> {
after {
if(__RETVAL__ == NULL) {
printf(“malloc(%i) failed in function %s(). exiting...\n”,
x, __FUNCTION__);
exit(-1);
}
}
}
}

Now, we take the C program to which we want to apply our aspects:


int init_msg(char *[], int);

int main(void) {
char * msg[4];
int i;

init_msg(msg, 4);
i = rand() % 4;
printf(“%s”,msg[i]);
return 0;
}

int init_msg(char * arg[], int size) {


int i;
for(i=0 ; i<size ; ++i) {
arg[i] = (char *) malloc(20);
sprintf(arg[i], “Message Number %d\n”, i);
}
return 0;
}
36 February 2001 Vol. 14, No. 2 ©2001 Cutter Information Corp.
We may wish to add our own aspects for debugging purposes at this point:
aspect debug {
/* Notify when init_msg starts and stops. */
funcDef<void init_msg(any)> {
before {
printf(“Entering init_msg.\n”);
}
after {
printf(“Leaving init_msg.\n”);
}
}
}

Our compiler takes all of the above code and conceptually generates the following C program:
int secure_rand(void);
void support_function(void);
int rand_wrap(void);
void * malloc_wrap(char *, size_t);
int init_msg(char *[], int);

int main(void) {
char * msg[4];
int i;

init_msg(msg, 4);
i = rand_wrap() % 4;
printf(“%s”,msg[i]);
return 0;
}

int init_msg(char * arg[], int size) {


int i;

printf(“Entering init_msg.\n”);
for(i=0 ; i<size ; ++i) {
arg[i] = (char *) malloc_wrap(“init_msg”, 20);
sprintf(arg[i], “Message Number %d\n”, i);
}
printf(“Leaving init_msg.\n”);
return 0;
}

int secure_rand(void) {
return 0;
}

void support_function(void) {
}

int rand_wrap(void) {
int retval;

Get the Cutter Edge free: www.cutter.com/consortium/ Vol. 14, No. 2 February 2001 37
retval = secure_rand();
return retval;
The space of available }
software security
void * malloc_wrap(char * FILENAME, size_t arg1) {
assurance is currently void * retval;
retval = malloc(arg1);
inhabited primarily
if(retval == NULL) {
by small, open-source printf(“malloc(%i) failed in function %s(). exiting...\n”,
arg1, FILENAME);
tools that address only exit(-1);
}
a fraction of the
return retval;
actual problem. }

RELATED WORK All of the capabilities of the above tools


The aspect-oriented programming paradigm could be described in a security specifica-
was first introduced by Gregor Kiczales [7]. tion and woven into a program using our
Xerox PARC developed the first aspect- aspect-oriented security approach. We hope
oriented programming language, AspectJ,1 to incorporate existing tools as off-the-shelf
which is an extension to the Java program- technology whenever possible. For example,
ming language. the aforementioned tools for preventing
buffer overflows can potentially be lever-
The space of available software security aged in the implementation of our approach.
assurance is currently inhabited primarily We hope to provide a uniform and general-
by small, open-source tools that address purpose interface to these tools, while
only a fraction of the actual problem. There adding a large amount of flexibility and
are multiple patches for the gcc compiler extensibility; only a few of the many prob-
that implement array bounds checking. lems we seek to handle are addressed by
There are several tools that provide some current tools.
sort of security against buffer overflow
attacks, including StackGuard [2] and FIST Commercial tools in the security assurance
[5]. However, most of these tools are solely space are almost universally general
interested in buffer overflows. purpose and not security specific. For
example, there are many tools such as
Another type of tool in the security assur- Rational’s Purify that can help find and fix
ance domain is the “secure data flow” tool. buffer overflow problems, even though the
Examples of this tool are the “taint” version tool is not specifically a security tool [6].
of Perl and the JFlow programming
language (a Java extension) [8]. In such Another class of tools is the after-the-fact
tools, data is labeled either “untrusted” or tools that support the penetrate-and-patch
“trusted.” “Untrusted” data cannot be model. These tools generally are concerned
passed to trusted items without the with taking preexisting source code and
programmer explicitly allowing it. Similarly, identifying potentially dangerous constructs
“trusted” data cannot be passed to based on a database and some static
“untrusted” items for fear of leaking secret analysis. Currently, the only publicly avail-
information (unless it has been explicitly able tool for source code analysis is ITS4,
1
See www.aspectj.org. declassified by the programmer). which scans C and C++ code for over 100

38 February 2001 Vol. 14, No. 2 ©2001 Cutter Information Corp.


potential problems [10]. Wagner has a Symposium on the Foundations of Software John Viega is a senior developer
and researcher at Widevine
buffer-overflow scanner that performs a Engineering. ACM, 1994. Technologies. He is the coauthor
more sophisticated analysis; however, it is of two upcoming books, Building
4. Evans, D., and A. Twyman. “Flexible
not publicly available and is limited in scope Secure Software (Addison-Wesley)
Policy-Directed Code Safety.” In Proceedings and Java Enterprise Architecture
[11]. There are similar general-purpose tools
of the 1999 IEEE Symposium on Security and (O’Reilly). He also writes a regular
that may catch some security bugs, column on software security for
Privacy. IEEE, 1999.
including lint tools such as LCLint [3]. IBM’s developerWorks.
5. Ghosh, A., T. O’Connor, and G. McGraw.
Previous work has also been done in policy J.T. Bloch is a developer at
“An Automated Approach for Identifying Widevine Technologies and a
languages for security. Most such languages
Potential Vulnerabilities in Software.” In researcher in computer security.
specify file access control, allowing the He is one of the developers of the
Proceedings of the 1998 IEEE Symposium on
programmer to give explicit policies stating ITS4 tool for auditing C and C++
Security and Privacy. IEEE, 1988.
what a program can and cannot do to files. source code. He is currently
Examples of such systems include Naccio working on software security
6. Hastings, R., and B. Joyce. “Purify: Fast issues in untrusted environments.
[4], Ariel [9], and PolicyMaker [1]. We antic- Detection of Memory Leaks and Access
ipate incorporating this sort of tool as a Errors.” In Proceedings of the Winter USENIX Pravir Chandra is a developer at
Widevine Technologies and a
small part of our total functionality. Conference. USENIX Association, 1992. researcher in computer security.
He is currently working on soft-
7. Kiczales, G., et al. “Aspect-Oriented ware security issues in untrusted
SUMMARY Programming.” In Proceedings of the environments.
We have identified some of the major prob- European Conference on Object-Oriented
The authors can be reached at
lems plaguing software security and Programming (ECOOP) ‘97. Springer-Verlag, Widevine Technologies, 11951
discussed how separating security from a 1997. Freedom Sq., Suite 1333, Reston,
program itself might help alleviate these VA 20190, USA. Tel: +1 206 254
8. Myers, A. “Practical Mostly-Static 3000; Fax: +1 206 254 3000; E-
problems. We have built an extension to the
Information Flow Control.” In Proceedings of mail: johnv@widevine.com, jt@
C programming language for defining secu- widevine.com, and pchandra@
the 26th ACM SIGPLAN-SIGACT Symposium
rity concerns and implementing a weaver widevine.com.
on Principles of Programming Languages.
that generates and integrates code into C
ACM, 1999.
programs.
9. Pandey, R., and B. Hashii. “Providing Fine-
REFERENCES Grained Access Control for Mobile Programs
Through Binary Editing,” Technical Report
1. Blaze, M., J. Feigenbaum, and J. Lacy. CSE-98-8. University of California, Davis,
“Decentralized Trust Management.” In 1998.
Proceedings of the 17th IEEE Symposium on
Security and Privacy. IEEE, 1996. 10. Viega, J., J.T. Bloch, T. Kohno, and G.
McGraw. ITS4: A Static Vulnerability Scanner
2. Cowan, C., et. al. “StackGuard: Automatic for C and C++ Code. In Proceedings of the
Adaptive Detection and Prevention of Buffer- 16th Annual Computer Security Applications
Overflow Attacks.” In Proceedings of the Conference (ACSAC 2000). IEEE, 2000.
Seventh USENIX Security Symposium.
USENIX Association, 1998. 11. Wagner, D., J. Foster, E. Brewer, and A.
Aiken. “A First Step Towards Automated
3. Evans, D., J. Guttag, J. Horning, and Y. Detection of Buffer Overrun Vulnerabilities.”
Meng Tan. “LCLint: A Tool for Using In Proceedings of the Year 2000 Network
Specifications to Check Code.” In and Distributed System Security Symposium
Proceedings of the ACM SIGSOFT (NDSS). Internet Society (ISOC), 2000.

Get the Cutter Edge free: www.cutter.com/consortium/ Vol. 14, No. 2 February 2001 39

You might also like