The Silverlight 2.0 Security Model

Silverlight and the rich client browser


March 09, 2008
URL:http://www.drdobbs.com/security/the-silverlight-20-security-model/206902613


Traditional Web applications are consumed through a special breed of application -- the client browser. Overall, the behavior of the browser hasn't changed much in recent years -- the browser is mostly used to download some content and render it into its client area. When the content is HTML, any embedded JavaScript code will be interpreted and executed. Through JavaScript code, the page author can manipulate elements in the page's Document Object Model (DOM) and trigger remote operations using XMLHttpRequest. In other words, JavaScript is the programming language of the browser and it is used to code any task that the page author wants the page to accomplish.

Since the very early days of the Web, two things appeared as clear as facts:

However, JavaScript is not as powerful as required by modern Web pages. Implementing a good user experience is perhaps far beyond the reach of the JavaScript language -- today and in the foreseeable future. That's why new programming environments are emerging specifically designed to build Rich Internet Applications (RIA). Silverlight 2.0 has is just one of these.

Stung by the failure of the ActiveX platform, Microsoft put a lot of attention and effort in the development of Silverlight, especially from a security point of view. Since its first appearance 10 years ago, ActiveX wasn't well received for essentially two reasons -- lack of support for platform interoperability and a poor security model.

Today, Silverlight 2.0 revamps the same core idea of ActiveX -- running user-defined and compiled code within the client browser. However, today Silverlight 2.0 does that in a cross-platform way and using an adequate sandbox to protect the user machine. In this article, I examine the new security model of Silverlight 2.0.

Enter Silverlight 2.0

Shipped with a cross-platform (and obviously thinned down) version of the .NET Framework, Silverlight 2.0 lets developers build rich managed applications that run in virtually any client browsers. As a developer, you can write Silverlight applications using a variety of .NET languages, including C#, Visual Basic, Managed JScript, and also dynamic languages such as IronPython and IronRuby. Figure 1 provides an overview of the Silverlight architecture and breaks the supported .NET Framework into pieces.

[Click image to view at full size]
Figure 1: A view from the interior of the Silverlight 2.0 engine.

The Silverlight 2.0 plug-in is made of a core CLR environment and a brand new Dynamic Language Runtime (DLR) environment made to measure to process dynamic languages such as Python. (IronPython is a Microsoft .NET language with a Python-compatible syntax.) Any code that runs within the CoreCLR may target classes in the Silverlight supported subset of the .NET Framework. This subset includes collections, generics, as well as more specific application programming interfaces such as that for XML parsing, isolated storage, LINQ-to-Objects. Each instance of the Silverlight plug-in is bound to a URL that returns XAML with optional code-behind classes written in any supported language. In Silverlight 2.0, the XAML supports a compatible subset of the full WPF platform along with some specific common controls not available (yet) to the desktop platform.

It is essential to note that Silverlight 2.0 does not require any version of the full .NET Framework to be installed on the client machine. The Silverlight setup program downloads everything that is necessary to enable all the features in Figure 1 on a standard Windows, Mac OSX, or Linux machine. For more information about running Silverlight on Linux, see the Moonlight project, the plug-in's code-name for Linux. Currently, Moonlight is under development.

The Silverlight plug-in measures about 4 MB in size and normally won't take more than just a few seconds to install on a machine. You need to install it only once and you can then successfully navigate to any Web page that hosts Silverlight content using your browser of choice.

Silverlight applications can be deployed to any Web server including Apache on Linux, and always require some sort of host page. You can't just serve plain XAML data to the browser. Instead, you need a host page that sets up the plug-in and make it point to the URL for the XAML content. The host page can be a static HTML files or any server-side generated page: ASP.NET, ASP.NET AJAX, PHP, Java, Python, Ruby, and so forth.

From Script-Behind to Code-Behind

Any elements that appear in a XAML document can be scripted by the companion code that comes with the XAML resource. In Silverlight 1.0, XAML elements can only be scripted using JavaScript functions and their events can be handled exclusively through JavaScript handlers. A common naming convention entails that you name the JavaScript file that contains this code after the page that hosts the plug-in. For example, a page named default.aspx that incorporates Silverlight will be served by a script file named default.aspx.js. This is only a convention, however, and is sometimes referred to as "script-behind".

You typically create XAML documents using the new facilities in Visual Studio 2008 or Expression Studio tools. You then empower these documents using C# or Visual Basic code saved to a classic code-behind file, such as default.aspx.cs. Any code-behind class attached to a XAML document will be downloaded to the client and executed within the local machine. Here's how a XAML document links to a managed class:

<UserControl x:Class="Samples.MyPage"
   xmlns="http://schemas.microsoft.com/client/2007"
   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   Width="400" Height="300">
   7lt;Grid>
     :
   </Grid>
</UserControl>

The x:Class attribute on the UserControl XAML tag instructs the plug-in about the class to instantiate to start up the application. UserControl is generally the root tag of a Silverlight 2.0 page. Where does class Samples.MyPage come from? It is defined in the code-behind file of the XAML document and inherits from UserControl, as in the code snippet below:

namespace Samples
{
   public partial class MyPage : UserControl
   {
      public MyPage()
      {
          InitializeComponent();
      }
      // Event handlers and helpers go here
      :
   }
}

The x:Class attribute is the discriminating factor that enables the CoreCLR to run managed code. An XAML document that lacks the attribute can only use JavaScript to handle internal events and provide glue code.

If you use Visual Studio to develop your Silverlight 2.0 application, XAML markup and any related code are compiled into a standard .NET assembly and then packaged in a XAP file along with any required auxiliary resources such as images or perhaps script files. Additional assemblies, if necessary, are added to the XAP bundle as well. What would be the typical size of these packages? A XAP file made of a code-behind class with no external dependencies will hardly exceed 10 KB and often it is around the base size of a .NET assembly, which is 4 KB. If your code depends on external assemblies, all of them are added to the XAP. The overall size, in this case, grows up. Code reuse through assemblies is always a good practice; in Silverlight programming, though, you might want to keep an eye also on the size of the assemblies and thus organize your reusable code in relatively small and simple classes rather than compiled assemblies so that you can reuse just the pieces you need.

Is JavaScript Required to Run Silverlight 2.0 Applications?

Any Silverlight applications require a host page, be it a static HTML page or any flavors of server-side generated page. The host page includes the plug-in as an <object> tag. At least in Silverlight 1.0, it is common to rely on some boilerplate JavaScript code to create the <object> tag on-the-fly and configure it properly. As you can see, this creates a clear dependency: the browser must have JavaScript support enabled in order to run Silverlight applications. This dependency may sound reasonable in Silverlight 1.0 where JavaScript is anyway the only supported language, but is just out of place in the fully .NET-based version of Silverlight 2.0. So is JavaScript required? No, you can host and run a Silverlight application also without JavaScript. All that you have to do is adding manually an <object> tag into the page and make it point to a server-side XAP resource. The plug-in will then automatically download the XAP content, instantiate the related class, and generate any user interface in the browser.

The XAP file is a sort of zipped archive. In fact, it uses the standard ZIP compression algorithm to reduce the size of the files and minimize the client download.

The Silverlight plug-in enables .NET development across a variety of platforms including Windows, Mac and Linux and it brilliantly solves the issue of interoperability that held back the adoption of ActiveX 10 years ago. But what about security? Is it really safe to download and run compiled code over the Internet?

Secure Code By Design

In the .NET Framework, upon loading an assembly the CLR gets evidence for it and figures out the code group of the assembly. A code group defines the list of privileged actions that assemblies are allowed to perform. Whenever some code is about to execute a privileged action, the CLR verifies its permissions and throws if it finds out anything wrong. Permissions for code groups are determined by the machine administrator. The administrator is responsible for defining the security policy for a given machine. In theory, the administrator can also disable code access security altogether. This model of handling security is known as "code access security" (CAS).

At its core, with CAS enabled any method of a .NET Framework class can execute any action unless the assembly it belongs to lacks permissions for it. The Silverlight 2.0 implementation of the CLR (also known as CoreCLR) reverses this principle completely. Any code that goes through the CoreCLR is considered partial trust and is not allowed to call into methods that require higher privileges. The CAS model is not supported in Silverlight 2.0. Code access security in Silverlight 2.0 is guaranteed by a brand new security model.

Security in CoreCLR is based on attributes, as in Table 1.

Security Attribute

Security Attribute

Description

SecurityTransparent

Any code marked with this attribute runs as partial trust and is not allowed to perform any calls that would elevate the privileges of the call stack. The attribute is supported since version 2.0 of the .NET Framework.

SecuritySafeCritical

Any code marked with this attribute runs as full-trust and may be called by transparent code. The attribute is new to Silverlight 2.0.

SecurityCritical

Any code marked with this attribute will always run as full-trust. The attribute is supported since version 2.0 of the .NET Framework.

Table 1: Silverlight 2.0 security attributes.

Each attribute identifies a different level of security hazard associated with the code. The concept of security transparent code is nothing new in the .NET Framework. It refers to code that is marked as unable to call into full-trust code and perform any other action that would possibly elevate the permissions of the call stack. Within the fully-fledged CLR, transparent is only the code that belongs to assemblies explicitly decorated with the SecurityTransparent attribute. Likewise, transparent is also any method or class that is explicitly given the attribute, as below.

[SecurityCritical(SecurityCriticalScope.Everything)]
public class Foo
{
    public void DoSomething()
    {
      :
    }
}

Unlike the fully-fledged CLR, in Silverlight 2.0 the CoreCLR considers any code as transparent unless it is decorated with a different security attribute. In particular, this means that all the code in a Silverlight 2.0 application cannot directly execute any critical operations such as invoking unsafe or unverifiable code or attempting system-wide changes through the P/Invoke subsystem. Application code in the Silverlight 2.0 virtual machine runs as partial trust and can only invoke other transparent code or, at most, code marked with the SafeCritical attribute.

What kind of animal is a safe-critical method, class, or assembly? As in Table 1, this attribute doesn't exist in the .NET Framework and has been added just for implementing the Silverlight's security model. The SafeCritical attribute identifies code that sits in between the application code (what users download from the Internet) and the platform code (where some critical methods are defined).

Making Sense of Safe-Critical Code

There are legitimate situations in which the application code may need to execute some pieces of critical code. A fair number of interesting system features are based on critical code. So if you want to give more power to the client, then you must be ready to provide access to some of these APIs. Is this something that can be done securely?

For obvious security reasons, Silverlight doesn't allow application code to call directly into any critical API. The CoreCLR invariably throws a method access exception every time that the application code attempts to call into any critical code. Again, is there a safe way for application code to access critical parts of the operating system? This is exactly where safe-critical code fits in. Have a look at Figure 2.

[Click image to view at full size]
Figure 2: How Silverlight 2.0 processes application code.

Code marked as safe-critical acts a smart proxy towards critical code. Application code is only allowed to call into other transparent and safe code or into code explicitly marked as safe-critical. Safe-critical code is full-trust code that doesn't undergo any sort of limitations. Yet, it plays a key role as it takes the responsibility of enabling risky calls from within application code. Normally, a safe-critical function does a number of checks before passing control to a critical function. Security checks may include parameters validation and any sort of API-specific set of checks aimed at ensuring that the application state is acceptable for the call to continue. Safe-critical methods are a delicate element as they represent the gateway for downloaded application code to access a critical method. How safe is safe-critical code?

SecurityTreatAsSafe vs. SecuritySafeCritical

The SecuritySafeCritical attribute is new to Silverlight 2.0. The concept of code transparency, however, is nothing new in the .NET Framework as the long time existence of some other security attributes demonstrates. This is the case, for example, of the SecurityCritical, SecurityTransparent, and SecurityTreatAsSafe attributes. Why has SecurityTreatAsSafe not been ported to Silverlight and was replaced by SecuritySafeCritical instead?

In the desktop CLR transparency model, all public critical methods are automatically marked as SecurityTreatAsSafe. In the context of Silverlight, a similar setting would enable transparent code to call into any public critical methods, thus severely invalidating the whole security model. For this reason, a new attribute was introduced to instruct the CoreCLR to treat as safe only methods that have been explicitly marked with the attribute.

Application Code and Platform Code

In Figure 2, I assumed that users can only download transparent code. If this assumption is correct, then we can safely conclude that Silverlight 2.0 is a secure environment. In this case, developers can only write transparent code and call into critical methods only via a smart proxy represented by safe-critical methods. But who does provide safe-critical methods? Put another way, is it possible for a developer to inject its own set of safe-critical methods in a Silverlight application? As you understand, this is a decisive point to assess whether Silverlight 2.0 is safe or not.

Silverlight code is partitioned in two families -- application code and platform code. Application code is any custom code that developers write for an application and that users download to their machines. Platform code is all the system code that makes Silverlight run. Application code can only be transparent; any attempt to invoke directly a critical method results in a method access security exception. Platform code can be of any type: transparent, critical or safe-critical; see Figure 2. How do you distinguish between application and platform code?

For the CoreCLR, only code signed with a specific Microsoft public key, and downloaded from a secure location on Microsoft servers, can be considered as platform code and allowed to expose critical or safe-critical entry points. In no way can the CoreCLR be fooled into considering a safety-critical piece of application code. In fact, no code downloaded from a non-Microsoft Web site can be treated as safe-critical and only Microsoft can create safe gateways to access critical APIs within the .NET Framework.

What About Custom Assemblies?

The code of a Silverlight 2.0 application can have dependencies on custom, user-defined assemblies. Not just any assemblies, though. A Silverlight 2.0 project can only add references to other assemblies created as Silverlight class libraries. Existing assemblies that you want to reuse must be recompiled and, if necessary, modified.

The security model in the CoreCLR also enables you to derive new classes only from security transparent classes defined by the platform or your application. A class is considered security transparent if it has no security attribute. It is possible that a platform class is security transparent but contains some safe-critical or critical methods. In this case, you can derive from the class, but you can't override any virtual method that is marked critical. Only transparent or safe-critical virtual methods can be overridden. It should be noted that in a possible override of a safe-critical method, you can't certainly radically alter the implementation of the functionality; or, at least, if you do that, you have to use only security transparent code. Overriding a safe-critical method mostly means that you inject some safe code around the base method implementation. Finally, an application class can only implement security transparent interfaces that don't contain critical methods.

Conclusion

Silverlight 2.0 enables .NET developers to extend their existing skills and investments to build cross-platform rich Internet applications that work in a cross-platform manner and are secure at the root. This article just scratched the surface of code download and security implementation in Silverlight 2.0 applications. Note also that any information discussed in this article is based on a Beta version of the product.

Terms of Service | Privacy Statement | Copyright © 2024 UBM Tech, All rights reserved.