July 02, 2002
Unsafe At Any Speed?C#'s relaxed security model may not be the best fit for your businessAl Williams
While Sun prides itself on Java's secure sandbox programming model, Microsoft takes a looser approach. Its C# language incorporates C-like concepts, including pointers and memory management. But is unsafe code really a boon to programmers, or is it a step backward?
I'm an old-school assembly language programmer. Although I understand the need for security, I've often chafed under restrictions imposed by modern languages like Java. Java tries to protect users from programmers, and in some cases, it even tries to protect programmers from themselves. In some instances you can relax Java's security restrictions, but in practice it's often more trouble than it's worth. This presents a tricky question: Shouldn't I, as a developer, be able to write programs that deliberately violate the language's built-in security measures? Don't get me wrong. I'm not talking about writing viruses, cracks, or other harmful programs. I'm talking about writing programs that legitimately interact with the user's system. For example, I might want to write an image to the user's hard disk, scan a system for viruses, or make a network connection from the client to send email. I've seen applications written in traditional languages that do all of these things, yet by default, all of these features are forbidden for a normal Web application. Signatures And TrustObviously, there has to be a measure of trust between the user and the developer when using network-distributed code. A program that can scan your hard drive can also read your private information. Allowing connections to the local network would open the door for a malicious program to broadcast embarrassingor even incriminatingmessages, which would be seen as originating from your computer. Browser and operating system vendors understand this, and have made it possible for users to selectively grant access to trusted programs. For example, browsers that execute Java applets can refuse to let untrusted applets access certain resources (like the local file system). Typically, any applet that arrives from the public Internet isn't trusted. But what happens if you want to write an applet that does something that's normally forbidden? The workaround most browsers provide is to sign the applet with a digital certificate. Once the signature has been verified and the origin of the applet is known, brave users can configure their systems to allow the applet free reign. Signing applets solves the problem for fairly benign operations, like local disk and network access. But suppose I want to go even further. Many modern language security features are really designed to protect methe developerfrom myself. Java is particularly restrictive in this area. Pointers are often misused, so Java doesn't allow direct access to them. Memory management is often a troublesome area, so Java takes control of it. All of this is just fine, until you want to bend the rules.
A New Language In TownAnother new-style language, Microsoft's C#, has a slightly different way of handling securityone that might appeal to you if you're an old-fashioned C programmer like me. Some analysts dismiss C# as Microsoft's attempt to replace Java out of spite for Sun. Certainly, Microsoft's reluctance to use Java must have played a major part in the decision to develop C#. Still, it's natural for new languages to imitate older languages to some extent. The real test isn't how much a language borrows; rather, it's how much it adds. I've often said that Java by itself isn't such a spectacular language. Its main strength is its well-designed standard library. I've often thought that someone could clone the Java library for C++ and have a winning product. C# manages this to some extent, and it goes even further. It not only has libraries that compete with Java's, but it also imitates many Java language features. One of the most interesting qualities of C# is the compromise it makes between the freewheeling style of C and the rigorous restrictions of Java. Sun could even learn something from Microsoft in this area. When it comes to signing code, Microsoft's .Net uses a similar architecture to that of Java. The .Net Common Language Runtime (CLR) expands on the idea a bit by replacing the idea of a certificate with the concept of evidence. Evidence might be a certificate, or credentials established by some other authentication method. Based on the evidence provided by a piece of code, the system grants or denies rights.
Fast And LooseC# differs sharply (pardon the pun) from Java in the amount of self-protection it affords programmers. C# derives much from C, and true to its heritage, it lets you use pointers and control memory management. C#'s developers realized that while not including these capabilities might be acceptable in a perfect world, things aren't always so simple. If you have to interface your code with other programs, those programs (or their data structures) might require pointers, however error-prone they might be. Likewise, high-performance software might require pointers to squeeze out that last microsecond of performance. All the same, it's easy to see how pointers can interfere with other modern language features, like memory management. After all, the garbage collection process can move an object at any time. If an object might contain a pointer to something, the garbage collector can't safely move it. System security is also affected. Pointers might be modified to access objects in memory that should be off-limits. This can happen as a result of a programming error, or it could be a malicious attempt to sabotage the system. So does this mean that C# and .Net programs aren't safe? Not at all. Though C# allows access to pointers and memory management, it does so for a price. To use these untrusted features, you have to mark your code as unsafe. Any code that is accepted as safe won't have access to C#'s pointer features. Conversely, you may configure the CLR on a given machine not to execute code that is marked unsafe (but relax that restriction for programs that offer the correct evidence, like a trusted certificate). In addition, objects that will be referenced by pointers must be pinned, meaning that the garbage collector will be unable to move them. You do this by using the fixed keyword. For example, here is some C# code that uses a pointer:
unsafe static int
AnArrayFunc(float [] inarray)
{
fixed (float* workp =
inarray)
{
// use workp here...
}
}
What To Do?Its support for unsafe code gives C# a very real advantage over Java, especially in the area of legacy application integration. True, Java lets you relax certain security restrictions. If you need to read or write from the hard drive, or perform other typically forbidden operations, code signing is an option. In a completely customized system, you can even rewrite the SecurityManager to change the way Java implements security. However, working with pointers simply isn't an option. In a pure Java environment, you shouldn't need them. But, if you're calling external interfaces (for a database, for example) that expect to talk to a C or C++ program, you'll find the lack of pointers in Java a grave difficulty. Even when your code needs to perform operations that are only slightly out of the ordinary, Java's security model can be difficult due to its reliance on digital signaturesa problem that not even C# avoids completely. Digital signatures are well standardized, but problems arise in the method used to transmit signatures to the client software. Each browser has a different idea about how they should work. Internet Explorer requires signatures to be sent in CAB files, while Netscape expects JAR files. To further complicate matters, the Sun Java Plug-In uses its own certificate-handling system. Thus, IE or Netscape users who install the plug-in will require yet another signing method. There are other problems, as well. A certificate must be issued by a trusted signing authority like VeriSign or Thawte. You must renew it when it expires. You must sign your applets again if the certificate changes. Worst of all, there is no guarantee that any given user will actually let a signed applet do what you want it to do. With ActiveX controls, the problem is even worse, because the presence of a signature can determine whether the user will load the control at all. A better, more universal system for signing code could really help out here. Code signing should be handled by the operating system for all programs. That way, you would only need to implement one method per platform. An even more idealistic dream would be to have a standard, signature-signing format (based on XML, perhaps) that's recognized by all operating systems, so that you could sign your code once and be done with it. I suspect that's too much to ask for, however. While it's true that .Net provides a variety of evidentiary methods for proving your trustworthiness, if these methods are operating systemspecific, or controlled by Microsoft, they won't be widely applicable to the Internet. A universal certification standard would benefit email users too. Currently, several email programs support signed emails, but few people use this feature. I suspect this is because some mail clients have trouble processing signatures from other programs. Who would lead this standardization effort? You'd think the companies that issue certificates would be at the forefront. After all, they'd benefit if more developers wanted to sign code and users wanted to sign email. Assuming they can get the kinks worked out, I applaud C#'s willingness to treat programmers like adults. Of course, as Spider-Man's uncle said, with great power comes great responsibility. You shouldn't expect everyone to execute your dangerous code. However, if users trust you and want the service that your code provides, C# lets them take a chance on you. It's your responsibility not to disappoint them. Al is the author of many popular programming books including Java 2 Network Protocols Black Book (Coriolis). You can find him on the Web at www.al-williams.com.
|
|
||||||||||||||||||||||||||||
|
|
|
|