How-To's for the Holidays - Java Whitelisting using AD Group Policy
When Java 7 Update 21 came out in March ( https://isc.sans.edu/forums/diary/Java+7+Update+21+is+available+-+Watch+for+Behaviour+Changes/15620 ), there was a fair amount of discussion about Java Whitelisting. This is a valuable feature, allowing you to permit execution of specific business applications based on Java, right down to nailing down specific Java versions for each app, and deny all other Java applications (from untrusted internet sites for instance). However, making this happen in a corporate environment (which in many cases means Active Directory) is not as straightforward as you might think - folks seem to think this is just too complex to tackle, and as a result we're not seeing a lot of folks using this feature.
Let's cover this challenge from beginning to end. If you find a step that I describe that might be done better or differently, please let us know in the comment form at the bottom of this page.
The first step of course is to define the business applications require Java, so that we know what to whitelist. I'll pick administration of my home firewall - the GUI admin for Cisco ASA firewalls is a java app.
So for me, that app is https://192.168.122.1. In a real corporate setting this would generally use DNS and possibly a more complete URL. I still trip over business apps accessed by IP address, but we try to kill them off as we find them.
Optionally you can also use the hash of the public certificate for the Java app. This is a better definition for the application, as this will remain consistent if you migrate to a different host or if you place the app on a load balanced farm of servers.
Given that this is for my home firewall, I have a self-signed cert, but hashing it still works. Generally you can get the public certificate from the server (or load balancer) admins, or you can pull it off the server directly. We'll use the keytool app distributed with Java:
C:\work>"\Program Files (x86)\Java\jre7\bin\keytool.exe" -printcert -sslserver 192.168.122.1:443
Certificate #0
====================================
Owner: CN=ASA Temporary Self Signed Certificate
Issuer: CN=ASA Temporary Self Signed Certificate
Serial number: 23e1af52
Valid from: Tue Dec 17 00:29:07 EST 2013 until: Fri Dec 15 00:29:07 EST 2023
Certificate fingerprints:
MD5: 26:56:67:AB:FC:97:B7:41:45:79:99:E2:4E:32:4F:35
SHA1: 12:D5:FC:89:EF:5D:24:CE:42:4B:63:76:1E:A3:22:C7:F9:AC:87:55
SHA256: 4D:F7:47:31:BD:35:F6:99:64:3B:11:C5:EE:35:DB:FF:90:71:CB:2F:EC:
0A:35:AA:E9:5F:19:F5:87:90:11:82
Signature algorithm name: SHA1withRSA
Version: 3
We want the SHA256 hash, with the separators removed: 4DF74731BD35F699643B11C5EE35DBFF9071CB2FEC0A35AAE95F19F587901182
With that in hand, we're ready to create a ruleset.xml file to hold the rules that make up our policy. In a corporate setting you'll likely have several whitelisted apps in this file, they all go in the file. There are a few shown in this file (based on Java's example):
<!-- Based on the Example Deployment Rule Set that allow a desktop administrator to control end-user's execution of browser applets.
See http://docs.oracle.com/javase/7/docs/technotes/guides/jweb/deployment_rules.html
Firewall administration for defaultroute.ca -->
<ruleset version="1.0+">
<rule>
<id location="https://192.168.122.1" />
<certificate algorithm="SHA-256"
hash="4DF74731BD35F699643B11C5EE35DBFF9071CB2FEC0A35AAE95F19F587901182"
<action permission="run" />
</rule>
<rule>
<id location="https://someother.permittedapplication.com/program" />
<action permission="run" version="SECURE-1.6" /><!-- For example if an application is known not to work on Java 1.7 -->
</rule>
<rule>
<id location="http://localhost" />
<action permission="run" />
</rule>
<rule>
<id>
<certificate algorithm="SHA-256"
hash="794F53C746E2AA77D84B843BE942CAB4309F258FD946D62A6C4CCEAB8E1DB2C6" /><!-- Oracle's public certificate hash. Having this will allow things like the Java.com
secure version check applet. -->
</id>
<action permission="run" />
<rule>
<id /><!-- Because this is both blank and shown last, it will be the default policy. -->
<action permission="block">
<message>Blocked by corporate. Contact myemail@mycompany.com if you need to run this app.</message>
<message locale="fr">Bloqué par l'entreprise. Contacter myemail@mycompany.com si vous avez besoin d'exécuter cette application.</message>
</action>
</rule>
</ruleset>
Full docs for this file can be found here: http://docs.oracle.com/javase/7/docs/technotes/guides/jweb/deployment_rules.html
We now take this file and package it in a JAR file using a trusted certificate. This prevents your users from editing this file after it's distributed to bypass your defined policies. You'll need the full JDK for this (jar.exe is not in the JRE distribution).
C:\work>"\Program Files\Java\jdk1.7.0_45\bin\jar.exe" -cvf deploymentruleset.jar ruleset.xml
added manifest
adding: ruleset.xml(in = 341) (out= 185)(deflated 45%)
C:\work>"\Program Files\Java\jdk1.7.0_45\bin\jarsigner.exe -verbose -keystore "c:\work\javakeystore_keepsecret.jks" -signedjar DeploymentRuleSet.jar DeploymentRuleSet.jar defaultroute-ca
Enter Passphrase for keystore:
updating: META-INF/MANIFEST.MF
adding: META-INF/COSTLOW-CA.SF
adding: META-INF/COSTLOW-CA.RSA
signing: ruleset.xml
Finally, we need to copy the final file to the corporate workstations, to specific locations:
Windows: C:\Windows\Sun\Java\Deployment
Mac, Linux, Unix: /etc/.java/deployment
In a typical organizaation, you might have 7 or 10 different rulesets to whitelist various combinations of applications. How do we get these various combinations to the desktop? Note that the location is NOT in the specific user directories. So what happens when someone governed by a different policy logs into the host?
You could copy your file in the login script, maybe using the IFMMEMBER command (from the Windows Server Resource Kit)? Something like:
ifmember Marketing then GOTO MKTLOGIN
ifmember Engineering then GOTO ENGLOGIN
....
:MKTLOGIN
xcopy \\servername\sharename\wljava.jar c:\windows\sun\java\deployment /y
However, as time goes on the lengthy and convoluted login scripts we had in the '90's are dwindling, and in many cases are now empty - people are using Group Policy for many of the things we used to get done in login scripts.
So how do we do this in AD?
========= Group Policy Method #1 =========
We'll use User Configuration \ Preferences \ Windows Settings \ Files (there's a matching setting under Computer Configuration, but that's not so applicable to User Groups).
Choose "New / File", and change the default to "Replace" - remember that there might be a file in the destination location, copied there for another user who might have different policy requirements. Update the source and destination paths.
Save it, apply it as you would any other Group Policy ,and you're done!
========= Group Policy Method #2 =========
If you've got other Group Policy functions that you need to combine with this, you can use User Configuration \ Policies \ Windows Settings \ Scripts (Logon/Logff) \ Logon. Consider this Group Policy setting to be today's version of yesterday's login scripts.
Be sure to store the script files in the Domain Policy directory:
c:\SysVol\defaultroute.ca\Policies\{Policy GUID}\Machine\Scripts\Startup, so on my server, that's in:
C:\Windows\SYSVOL\sysvol\defaultroute.ca\Policies\{CD37CDDF-8486-41DE-81A7-62F596F1BCFD}\User\Scripts\Logon
The file copy line in the script might look like:
xcopy \\%LOGONSERVER%\NETLOGON\javawl.mktg.jar c:\windows\sun\java\deploymentruleset.jar /y
If you use this second file copy approach, you'll likely want the files to reside in the NETLOGON directory so that AD replication will copy it to all DC's. The NETLOGON directory is at:
c:\windows\sysvol\sysvol\domainname\scripts, in my domain's case:
c:\windows\sysvol\sysvol\defaultroute.ca\scripts
This second method is quite a bit more complex - there's a number of file locations that need to be exactly right, and scripts that need to match them, but if you need more scripting done in your Group Policy than just copying the JAR files or other things that you can accomplish in other Group Policy settings, it's a good way to go.
======================================
Either way you copy your JAR files, Group Policies are a central place to administer almost everything - if you can bolt on generic file copies to that, and can keep everything in one place, that's a HUGE win for simplified administration!
And speaking of a "win" - once this is in place, your user community will have access to "blessed" java apps, but will not be able to execute any other java applications. Which means that when the next Java zero day is announced, you'll likely be able to sleep that night and not worry about what the next day will bring you at work!
Again, if you've got a simpler or alternative way to get this job done, I'm certainly interested and so are our readers - please use our comment form to share!
==========================
Rob VandenBrink
Metafore
Comments
Anonymous
Dec 25th 2013
1 decade ago
If the end-user is running as an administrator or permissions are relaxed then a creative end-user will be able to work around this restriction. If the typical end-user is an administrator AND you are running outdated Java, then you are at considerable risk.
The per-user script will not work without administrator privileges or at least enough privileges to overwrite the file.
I would suggest that there are two approaches that could be taken:
1. Build A Shim using the Microsoft Application Compatibility Toolkit (This could allow a per-user file).
2. Stick to a per-computer GPO so that the copy can occur under the system context. This file would then be re-applied at reboot.
Regards
Jason.
Anonymous
Jan 20th 2014
1 decade ago