If a user encounters signed code, chances are that the code requires more than appropriate privileges to carry out its operations. It is in the interest of the users to verify the authenticity and integrity of the artifacts that they wish to deploy. Although it is usually a bad idea to sign code, some actions necessitate this step. For example, if the application needs to establish an http
connection with an external host to download plugins or extensions, a vendor may provide signed code instead of having the user deal with complex security policies. Sometimes the policies themselves reflect that only the code signed by the provider should execute with the granted privileges. Because executing signed code can be extremely dangerous, verifying authenticity of origin is of utmost importance. Users are most often not the best judges of what code is safe to execute and what constitutes malicious code. Therefore, it is necessary to programmatically verify signed code in the absence of a default security manager mechanism.
Java based technologies typically use the Java Archive (JAR) feature for packaging files to facilitate platform independent deployment. Be it desktop applications, Enterprise Java Beans (EJB), MIDlets (J2ME) or Weblogic Server J2EE applications, for example, JAR files are the preferred distribution mechanism. The point and click installation provided by Java Web Start also relies on the JAR file format for packaging. Vendors sign their JAR files when required, however, this should not be interpreted to be the case that the code cannot be misused.
...
If you are creating applet code that you will sign, it needs to be placed in a JAR file. The same is true if you are creating application code that may be similarly restricted by running it with a security manager. The reason you need the JAR file is that when a policy file specifies that code signed by a particular entity is permitted one or more operations, such as specific file reads or writes, the code is expected to come from a signed JAR file. (The term "signed code" is an abbreviated way of saying "code in a class file that appears in a JAR file that was signed.")
...
Depending on how the client code works, signatures may or may not be automatically checked programatically. For instanceexample, any instances of URLClassLoader
and its subclasses and java.util.jar
automatically verify a signature whenever the JAR file is signed. If however, the developer implements a custom classloader that goes on to subclass the java.lang.ClassLoader
, this step is not performed automatically. MoroeverMoreover, in the URLClassLoader
case, the automatic verification just involves an integrity check and does not authenticate the loaded class. This is because the check uses a public key that is contained within the JAR. The legit JAR file may be replaced with a malicious JAR file containing a different public key and hash values.
Noncompliant Code Example
This noncompliant code example demonstrates the JarRunner application that can be used to dynamically execute a particular class residing within a JAR file [Tutorials 08]. It creates a JarClassLoader
that loads an application update, plugin or patch over an untrusted network such as the Internet. The URL to fetch the code is specified as the first argument (for example, http://somewebsite.com/software-updates.jar) and any other arguments specify the arguments that are to be passed to the class to be loaded. Reflection is used to invoke the main
method of the loaded class.
...
Code Block | ||
---|---|---|
| ||
public class JarRunner { public static void main(String[] args) { if (args.length < 1) { usage(); } URL url = null; try { url = new URL(args[0]); } catch (MalformedURLException e) { fatal("Invalid URL: " + args[0]); } // Create the class loader for the application jar file JarClassLoader cl = new JarClassLoader(url); // Get the application's main class name String name = null; try { name = cl.getMainClassName(); } catch (IOException e) { System.err.println("I/O error while loading JAR file:"); System.exit(1); } if (name == null) { fatal("Specified jar file does not contain a 'Main-Class'" + " manifest attribute"); } // Get arguments for the application String[] newArgs = new String[args.length - 1]; System.arraycopy(args, 1, newArgs, 0, newArgs.length); // Invoke application's main class try { cl.invokeClass(name, newArgs); } catch (ClassNotFoundException e) { fatal("Class not found: " + name); } catch (NoSuchMethodException e) { fatal("Class does not define a 'main' method: " + name); } catch (InvocationTargetException e) { e.getTargetException().printStackTrace(); System.exit(1); } } private static void fatal(String s) { System.err.println(s); System.exit(1); } private static void usage() { fatal("Usage: java JarRunner url [args..]"); } } class JarClassLoader extends URLClassLoader { private URL url; public JarClassLoader(URL url) { super(new URL[] { url }); this.url = url; } public String getMainClassName() throws IOException { URL u = new URL("jar", "", url + "!/"); JarURLConnection uc = (JarURLConnection) u.openConnection(); Attributes attr = uc.getMainAttributes(); return attr != null ? attr.getValue(Attributes.Name.MAIN_CLASS) : null; } public void invokeClass(String name, String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException { Class c = loadClass(name); Method m = c.getMethod("main", new Class[] { args.getClass() }); m.setAccessible(true); int mods = m.getModifiers(); if (m.getReturnType() != void.class || !Modifier.isStatic(mods) || !Modifier.isPublic(mods)) { throw new NoSuchMethodException("main"); } try { m.invoke(null, new Object[] { args }); } catch (IllegalAccessException e) { System.out.println("Access denied"); } } } |
Compliant Solution
If the program expects the user to manually install the new JAR file, the user can explicitly check the signature from the command line. Any malicious tampering results in a SecurityException
when the jarsigner
tool is invoked with the -verify
option.
...
It is not always the case that arbitrary code gets executed. By default, the URLClassLoader
and all its subclasses are only given enough permissions to interact with the URL
that was specified when the URLClassLoader
object was created. This means that the program can interact with the specified host by default. However, this does not mitigate the risk completely as the loaded file may need to be granted appropriate privileges to perform more sensitive operations such as updating an existing local JAR file.
Risk Assessment
Not verifying the digital signature either manually or programmatically may lead to execution of malicious code.
Rule | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
SEC05-J | high | probable | medium | P12 | L1 |
Automated Detection
TODO
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
References
Wiki Markup |
---|
\[[API 06|AA. Java References#API 06]\] \[[Gong 03|AA. Java References#Gong 03]\] 12.8.3 jarsigner \[[Eclipse 08|AA. Java References#Eclipse 08]\] [JAR Signing|http://wiki.eclipse.org/JAR_Signing] and [Signed bundles and protecting against malicious code|http://help.eclipse.org/stable/index.jsp?topic=/org.eclipse.platform.doc.isv/guide] \[[Halloway 01|AA. Java References#Halloway 01]\] \[[Flanagan 05|AA. Java References#Flanagan 05]\] Chapter 24. The java.util.jar Package \[[Oaks 01|AA. Java References#Oaks 01]\] Chapter 12: Digital Signatures, Signed Classes \[[Tutorials 08|AA. Java References#Tutorials 08]\] [The JarRunner Class|http://java.sun.com/docs/books/tutorial/deployment/jar/jarrunner.html], [Lesson: API and Tools Use for Secure Code and File Exchanges|http://java.sun.com/docs/books/tutorial/security/sigcert/index.html] and [Verifying Signed JAR Files|http://java.sun.com/docs/books/tutorial/deployment/jar/verify.html] \[[JarSpec 08|AA. Java References#JarSpec 08]\] Signature Validation \[[Bea 08|AA. Java References#Bea 08]\] \[[Muchow 01|AA. Java References#Muchow 01]\] \[[MITRE 09|AA. Java References#MITRE 09]\] [CWE ID 300|http://cwe.mitre.org/data/definitions/300.html] "Channel Accessible by Non-Endpoint (aka 'Man-in-the-Middle')", [CWE ID 319|http://cwe.mitre.org/data/definitions/319.html] "Cleartext Transmission of Sensitive Information", [CWE ID 494|http://cwe.mitre.org/data/definitions/494.html] "Download of Code Without Integrity Check", [CWE ID 347|http://cwe.mitre.org/data/definitions/347.html] "Improperly Verified Signature" |
...