Providing a Secure eXPerience

 

Andrew Clinick
Microsoft Corporation

October 8, 2001

**Note   **The code sample download originally included with this article is no longer available.

This month marks a major milestone in the evolution of Microsoft® Windows® with the launch of Microsoft® Windows® XP. To coincide with the launch, I thought I'd take the opportunity to show some of the new features in Windows Script Host (WSH) that ships in Windows XP, and in particular the new security capabilities that Windows XP provides. Providing a secure method of using WSH is vitally important given recent virus outbreaks, so we worked with the Windows security team to ensure that WSH fits into the new Software Restriction Policies introduced in Windows XP. Security is an important part of system scripting, and WSH also provides a security mechanism for older versions of Windows, which I will cover later in the article.

How Security Works in WSH

Scripts written in WSH typically require access to system capabilities, the file system, and so on. Thus the security system implemented in WSH had to take into account that most scripts are written for good reasons—and are not viruses. Since scripts are easy to write, however, and are just text files that can be easily distributed to the machines of end users (either by e-mail or by downloading from a Web site), WSH scripts have become a target for virus writers. Providing a mechanism for users to be able to determine who wrote the script they're about to run, and providing a mechanism for controlling access based on that identity, is a key feature for WSH 5.6. To achieve this capability, WSH now includes a mechanism to sign scripts.

Signing a script guarantees that you wrote the script, and that is hasn't been tampered with in any way since you signed it. The signing process uses your certificate, which you can get from a number of certificate authorities (you might even have an internal certificate authority), the hash of the script file, and your private key to create a signature in the script file. When WSH loads the file, it checks the certificate to ascertain whether the certificate is okay and whether the hash matches the contents of the file. If the hash is different, somebody has tampered with the file. WSH will tell you about this, and will ask whether you still want to run the file. If the script has been tampered with, you should proceed with extreme caution. Likewise, if the certificate is invalid, expired, has been revoked, or isn't trusted, then WSH will notify you and will refuse to run the code.

It's important that the signing mechanism cover all file formats supported by WSH, so .vbs, .vbe, .js, .jse and .wsf file types are covered. It is also important that previous versions of WSH be able to run signed files, so the script-signing mechanism puts the signature into comment blocks at the end of .vbs and .js files and into a <signature> element in wsf files. If the signed code is loaded by an older version of WSH, it will ignore the commented code or <signature>.

Signing the Script

Windows provides a standard mechanism for signing code via signcode.exe. Unfortunately, signcode.exe doesn't ship with Windows, but rather, with the Windows SDK. This presents a problem for the vast majority of Windows users: How do I sign a script if I don't have the tool? To address this issue, the Windows Script team developed an object model, Scripting.Signer, which makes writing a script to sign code very simple. There are 4 methods on the object that allow you to sign and verify any script code that you might have. To illustrate how to use this object, I've included a sample, signfile.wsf, which provides a simple command line tool to sign script code.

   var Signer, File, Cert
   if (!(WScript.Arguments.Named.Exists("cert"
) && WScript.Arguments.Named.Exists("file"))) 
   {
      WScript.Arguments.ShowUsage();
      WScript.Quit();
   }
   Signer = new ActiveXObject("Scripting.Signer");
   File  = WScript.Arguments.Named("file");
   Cert  = WScript.Arguments.Named("cert");
   Signer.SignFile(File, Cert,"my");

The script just takes a file name and certificate with which you want to sign the file, and passes it on to the SignFile method on the Signer, and the file is signed. The signature is added to the .wsf file within the <signature> element. Since the signature is encoded, it's pretty impossible (for a normal human at least) to decipher anything about the signature. Luckily, Windows XP does know how to decipher the signature, and displays it in a new property sheet in the properties dialog of the file.

Figure 1. Windows XP digital signature property sheet

From the property sheet, you can see that the signcode.wsf is signed by the Fabrikam IT Department. To find out more about the Fabrikam IT Department, you can click the details button and take a look at the certificate of the signed code:

Figure 2. Fabrikam certificate

Implementing a Security Scheme

Once you've got all your script signed, it's important to be able to define a security scheme for running scripts in your organization. Though the schemes that I will illustrate here won't be the definitive approach for your organization, hopefully they will give you an idea of what's possible, and you can tailor them to your needs. I'll cover 2 main security mechanisms: one using Windows XP exclusively, and one that works on both Windows XP and on previous versions of Windows.

Windows XP Software Restriction Policies

Windows XP introduces a new mechanism, Software Restriction Policies, for controlling what software can run on your machine, and whether or not to allow that software's full range of functionality. Software Restriction Policies allow for control over all executable code, not just script, on a Windows XP machine. The control is built directly into the operating system. Software Restriction Policies are controlled through the Local and Group Policy feature in Windows, which makes it easier to apply the policies (and any changes) to all computers on a network. Software Restriction Policies operate on a set of rules that apply to all executable code running on your machine. For example, they allow you to set a rule specifying that no executable code can be run from a specific folder, or that only script signed with a particular certificate can run.

To illustrate the use of Software Restriction Policies, let's take the mythical fabrikam.com as an example. Let's say that fabrikam.com wants to ensure that users on the network don't fall prey to a virus such as ILOVEYOU. fabrikam.com uses WSH files for logon scripts and software installation, so it's vitally important to be able to distribute and run WSH Scripts written by the IT Dept on users machines.

Setting Up the Rules

Windows XP provides a Microsoft Management Console (MMC) snap-in that offers an easy way to manage the Software Restriction Policies on the local machine. Since certificates and Software Restrictions Policies are so closely linked, I created a management console configuration that includes both certificate manager and the Software Restrictions Policies snap-ins. (I've included it in the .exe file that accompanies this article.)

The first rule that needs to be set up for this example is to ensure that all .vbs, .js, .wsf, .vbe, and .jse files are disallowed whenever a user logs onto a machine. This is achieved by creating a new path rule for each of the file types. Software Restriction Policies provides 3 ways to control access to paths: the actual path of the file, the hash of a file (a hash uniquely identifies a file no matter where it is located), and by Internet zone. To control access to the WSH file types, a path rule needs to be created by selecting the New Path Rule context menu item in the additional rules section of Software Restriction Policies.

Figure 3. Creating a new path rule

Once the New Path Rule dialog appears, all that remains is to enter the path of the file to which you want to restrict access. In this example, we want to disallow access to all WSH files, irrespective of their physical location, so all that is needed is *.js, *.vbs, *.wsf, *.vbe and *.jse. If you wanted to restrict access to all WSH files in a particular folder, then you would add the folder name as well as the *.vbs. This could be useful if you wanted to restrict access to any WSH files run from within the Web browser or mail client. All you would need to do, is to specify the temporary Internet folder; Software Restriction Policies would stop any WSH file from running in that folder.

Figure 4. New Path Rule dialog box

Adding the path rules have essentially removed access to WSH for users on the machine, but it's important that scripts written by the Fabrikam IT Department can be run. This is accomplished by establishing a certificate rule that will override the path rules already set up. Whenever WSH tries to run a script signed by the Fabrikam IT Department, it will check with the Software Restriction Policies to see if any certificate rule has been created. Adding a certificate rule is achieved by selecting the Add Certificate Rule context menu in the MMC snap-in.

In order to use the certificate rule, you need to export the certificate you used to sign your script to a file. This is pretty simple to do using the certificate manager snap-in (which is included in the WSH Settings.msc file with this article). Just select the export context menu on the certificate and follow the wizard. I found it easiest just to accept the defaults, but it is important that you select a DER-encoded binary X.509 certificate. To help out, I've included the fabrikam.com certificate with the download that accompanies this article, so you can use that to test out the certificate rule.

**Note   **The certificate doesn't include the private key, so you can't use it to sign code—you'll need your own certificate to do that.

Figure 5. Certificate Export Wizard

Once the .cer file has been exported, all you need to do is to provide the file to the certificate rule dialog, and select unrestricted for the security level.

Figure 6. Fabrikam IT Department New Certificate Rule

Getting Your Own Certificate

Code signing is great, but sometimes it's not entirely obvious where you can get your own certificate for code signing. There are a number of options available to you, but typically people get a code-signing certificate from a Certificate Authority (such as Verisign), or your organization might have a certificate server (Microsoft® Windows® 2000 server provides a certificate server for example). If you want to experiment with code signing, but don't want to buy a certificate or go to the trouble of setting up a certificate server, then I recommend using the selfcert.exe tool that comes with the Windows SDK and Office. Selfcert lets you create a certificate for code signing, but it doesn't have any root certificate authority. This makes it pretty useless as far as real code signing goes, because most applications require a trusted certificate authority before allowing code to run. Still, it does allow you to create a certificate for your own use that you can use to sign code for testing.

Figure 7. Selfcert.exe in action

If you have Office installed, then selfcert.exe will be in the office directory under program files. If it's not there, go to the add/remove programs applet in control panel, select Microsoft Office, and then make sure that the VBA security option is selected.

Applying the Rule

Using the MMC snap in to set the rules ensures that the policy database for the machine (or machines if you're using the Group Policy Editor) has been updated but it hasn't been applied to the machine. To apply the new policy to your machine you can either log off and log back in again or run the command line tool gpupdate which forces a policy refresh on your machine.

Testing the Rules

I've included some sample scripts in the code that comes with this article to illustrate the policy:

  • bad.vbs—This script has been signed by Dr. Evil (so obviously it can't be trusted!), and while it could do something bad, it just echos that it's going to FDISK your hard disk. I promise that it doesn't do anything else!
  • good.vbs—This is signed by the Fabrikam IT Department. This script would do something interesting in real life, but again it just echos that it's a good script.
  • test.vbs—This isn't signed by anyone, and just echos "hi."

Running test.vbs and bad.vbs will fail because of the path rule that disallowed any .vbs files. When a user attempts to run either of these, WSH provides an error message telling the user that Software Restriction Policies have stopped the script from running. This error message is displayed without any of the script being loaded and run by WSH.

Figure 8. Software Restriction Policies in action

Because it's signed by the IT Department, and we added a certificate rule for the IT Department, good.vbs will run normally.

Figure 9. Software Restriction Policies in action

Providing a Security Scheme for Older Versions of Windows

Software Restriction Policies provide an extensive and easy-to-use way to implement security on Windows XP. We felt, however, that it was important to provide some security measures for older versions of Windows as well. To achieve this, WSH 5.6 provides the ability to use code signing to control access to scripts. While it doesn't provide the same breadth and depth of security access as Software Restriction Policies, it does provide a robust if somewhat simple mechanism.

Setting Up the Trust Policy

WSH 5.6 uses a registry setting (which requires administrative privileges to change) to determine the Trust Policy. The registry key, TrustPolicy, is stored in the Windows Script Host/settings hive under HKEY_Current_User and HKEY_LOCAL_MACHINE. The setting has 3 values:

  1. Run all scripts regardless of whether they're signed or not. This is the default setting, since it ensures that all scripts that run today will continue running.
  2. Prompt the user if a script isn't signed with a trusted certificate. This provides some security, but can be very confusing for average users, since it's unlikely that they will understand what code signing is all about. More often than not, they will probably just choose the button on the dialog box that makes it go away. This is useful for people developing scripts, since it allows you to run your scripts during development without having to sign them every time.
  3. Only run scripts that are signed with a trusted certificate. This is the safest way to run scripts, since you can control which certificates you trust. Anything not signed, or signed by a certificate that is not trusted, won't run.

To implement the same security policy for fabrikam.com (only run scripts signed by the fabrikam.com IT Department) the Trust Policy needs to be set to 2, and the certificate trust policy for fabrikam.com needs to ensure that only the fabrikam.com IT Department certificate is trusted. Managing the trust relationship for certificates is pretty simple thanks to the certificate management console snap-in. To do this, simply add the certificate into the Trusted Publishers store, either by copying the certificate from another store on the machine, or by importing the .cer file from the file system.

Figure 10. Trusted Publishers store

Once the certificate has been added, the security policy is in place. Running good.vbs (signed by the Fabrikam IT Department) will work just fine, since it's a trusted publisher. Whereas bad.vbs (signed by Dr. Evil) won't work because Dr. Evil isn't trusted, and test.vbs (which isn't signed) won't run because it's not signed.

Figure 11. Results of new Trust Policy

Summary

Providing a mechanism for controlling the way that your users can use WSH was of vital importance to us when developing Windows Script Host 5.6. The Software Restrictions Policies in Windows XP provide considerable flexibility and scope for developing security policies for Windows XP machines. I've only touched on what is possible, and I certainly recommend that you look further into the capabilities they provide. A good place to start is What's New in Security for Windows XP Professional and Windows XP Home Edition, which includes white papers covering the capabilities in more depth.

I hope that the new security features in Windows Script Host 5.6 will provide your organizations with a mechanism to continue to use the great capabilities that WSH provides, while maintaining more control over what type of code is run, and make ILOVEYOU viruses a thing of the past. As always, we're very keen to get your feedback on this, so please feel free to contact us at msscript@microsoft.com, or on the WSH newsgroup at Microsoft.public.scripting.wsh on msnews.microsoft.com.

 

Scripting Clinic

Andrew Clinick is a senior program manager in the Microsoft Programmability group, so chances are, if there's script involved, he's probably had something to do with it.