why `java.lang.SecurityException: Prohibited package name: java` is required?
I created a class "String" and placed that in package "java" [ actually i wanted to create java.lang to see which class is loaded by classLoader as
Once a class is loaded into a JVM, the same class (I repeat, the same class) will not be loaded again
quoted from oreilly ] . But that thing later, why on running 开发者_StackOverflow社区this class i am getting
java.lang.SecurityException: Prohibited package name: javaFor which security reason java is not allowing me to have a class in java package? What one could do if there will not be no such check?
User code is never allowed to put classes into one of the standard Java packages. That way, user code cannot access any package-private classes/methods/fields in the Java implementation. Some of those package-private objects allow access to JVM internals. (I'm thinking of SharedSecrets
in particular.)
Firstly, these types of restrictions are in place to enforce the Java sandbox. That is, running untrusted code in a trusted environment. Such as running an applet from some site (that you don't necessarily trust), on your computer (the trusted environment) in your browser. The intent is to disallow untrusted code from gaining access to package-private stuff which could help it escape the sandbox.
Normally these restrictions are enforced by the SecurityManager, so they shouldn't happen when you run your own application on the command-line (unless you explicitly specify to use a SecurityManager). When you control the environment, you could just go and edit the String.class definition inside the rt.jar of your Java (and you can, technically anyway, not sure what licensing says). As I said the restrictions are normally in the SecurityManager, but this particular rule about java.* packages is in the ClassLoader class.
To answer your question: My guess is that java.* check is there because of a) historic reasons b) somewhere in the Java core there's a check on the name of the class, something like: All class that start with java.* get special treatment.
However, consider that even if you managed to create a class called java.lang.String, it would not be the same class as the java.lang.String defined by the Java core. It would just be a class with the exact same name. Class identity is more than just the name of the class, even though this can be tricky to perceive unless you really play with ClassLoaders.
So a class loaded by the application classloader in the package java.lang, would not have access to the core java.lang package-private stuff.
To illustrate this, try to create a class called javax.swing.JButton with a main method and execute it. You'll get a java.lang.NoSuchMethodError: main
. That's because java finds the "real" JButton before your class, and the real JButton doesn't have a main method.
In a Java standalone application you might be able to go around this restriction by calling one of the private native defineClassx methods directly via use of reflection and setAccessible.
BTW: The core java.lang.String is guaranteed to be loaded before your code ever executes because it's referenced everywhere, you would not get there first with your user code. The JVM gets set up to a degree before ever even trying to load your class, let alone execute it.
You cannot have "java.*" package names. This is actually hard-coded in the Java core so you cannot even grant a security manager permission to work around it (cf. ClassLoader::preDefineClass(...))
java
is a reserved package name. Only classes inside the JVM can reside in this package.
If anyone could write in the Java package, that could result in libraries arbitrarily replacing core Java classes by their own implementations. That could result in a lot of thinks, from breaking core Java features to execution of malicious code.
A program could bypass security measures if a program could override JVM core classes with trojan versions. For example, String is used practically everywhere.
From the ClassLoader.defineClass(..)
javadoc:
...The specified class name cannot begin with " java. ", since all classes in the " java.* packages can only be defined by the bootstrap class loader
and
Throws: ... SecurityException - If an attempt is made to add this class to a package that contains classes that were signed by a different set of certificates than this class, or if the class name begins with " java. ".
Probably during refactoring/patch applying/etc. you have added to package name word 'java', which is usually a folder that contains packages.
So you could end with the structure: src->main->java->java.com.yourpackage.name
It might also happens for test: src->main->test->java->java.com.yourpackage.name
Verify it in your IDE and remove "java." part
An excerpt from java.lang.ClassLoader
's preDefineClass
method:
/* Determine protection domain, and check that:
- not define java.* class,
- signer of this class matches signers for the rest of the classes in
package.
*/
private ProtectionDomain preDefineClass(String name,
ProtectionDomain pd)
{
...
// Note: Checking logic in java.lang.invoke.MemberName.checkForTypeAlias
// relies on the fact that spoofing is impossible if a class has a name
// of the form "java.*"
if ((name != null) && name.startsWith("java.")) {
throw new SecurityException
("Prohibited package name: " +
name.substring(0, name.lastIndexOf('.')));
}
...
}
Please note that java.lang.ClassLoader
is an abstract class, meaning that a subclass (say, SecureClassLoader
) will actually implement it. However, the preDefineClass
method is private
, so it cannot be overridden by a subclass.
preDefineClass
is called by the defineClass
method, which is protected final
. This means defineClass
is accessible to subclasses and they can call it, but they won't be able to change its implementation.
精彩评论