1.定义
当类被加载到虚拟机中,校验器检查通过,Java平台的第二种安全机制就会启动,这个机制就是安全管理器,它是控制具体操作是否允许执行的操作。它的安全策略建立了代码来源和访问权限集之间的映射关系。
jdk8中的权限类(直接或者间接实现Permission抽象类)
下图显示了jdk8中Permission的继承关系,图片内容较多,放大观看。
2.Java平台安全性
java安全管理器这里主要涉及到两个概念一个是代码来源另一个就是权限集。代码来源是由代码位置和一个证书集指定的。代码位置指定了代码的来源。权限指由安全管理器负责检查的任何属性,如上展示的jdk8中的权限类,这里的每个权限类都封装了相应的权限详细信息。例如:
FilePermission filePermission=new FilePermission("/tmp/*","read,write");//允许在/tmp/*下进行读写操作 SocketPermission socketPermission=new SocketPermission("192.168.0.1:8080","listen");//监听192.168.0.1机器8080端口
每个类都有一个保护域,保护域中封装了代码来源和权限集合对象。当SecurityManager需要检查某个权限时,它要获取堆栈上所有方法对应类的保护域,并且判断保护域中是否允许当前正在被检查的操作。若允许则通过检测,否则将会抛出SecurityException异常。在jdk中所有系统类的代码来源都是null,权限都是AllPermission类的实例组成的。
关键方法介绍:
1.java.lang.SecurityManager中的checkPermission方法
/** * Throws a <code>SecurityException</code> if the requested * access, specified by the given permission, is not permitted based * on the security policy currently in effect. * <p> * This method calls <code>AccessController.checkPermission</code> * with the given permission. * * @param perm the requested permission. * @exception SecurityException if access is not permitted based on * the current security policy. * @exception NullPointerException if the permission argument is * <code>null</code>. * @since 1.2 */ public void checkPermission(Permission perm) {//检查当前安全管理器是否授予指定的权限 java.security.AccessController.checkPermission(perm); }2.java.lang.Class 的ProtectionDomain getProtectionDomain()
public ProtectionDomain getProtectionDomain() {//获取某个类的保护域,若类被加载时没有保护域,则返回null SecurityManager var1 = System.getSecurityManager(); if (var1 != null) { var1.checkPermission(SecurityConstants.GET_PD_PERMISSION); } ProtectionDomain var2 = this.getProtectionDomain0(); if (var2 == null) { if (allPermDomain == null) { Permissions var3 = new Permissions(); var3.add(SecurityConstants.ALL_PERMISSION); allPermDomain = new ProtectionDomain((CodeSource)null, var3); } var2 = allPermDomain; } return var2; }
3.java.Security.ProtectionDomain
public ProtectionDomain(CodeSource var1, PermissionCollection var2) {//通过代码来源和权限集合构建保护域 this.codesource = var1; if (var2 != null) { this.permissions = var2; this.permissions.setReadOnly(); if (var2 instanceof Permissions && ((Permissions)var2).allPermission != null) { this.hasAllPerm = true; } } this.classloader = null; this.principals = new Principal[0]; this.staticPermissions = true; }
public final CodeSource getCodeSource() {//获取保护域代码来源 return this.codesource; }
public boolean implies(Permission var1) {//如果该保护域允许给定的权限,则返回true if (this.hasAllPerm) { return true; } else if (!this.staticPermissions && Policy.getPolicyNoCheck().implies(this, var1)) { return true; } else { return this.permissions != null ? this.permissions.implies(var1) : false; } }
implies方法:这个方法是为了决定由传递给AccessController的checkPermission()方法的Permission对象锁代表的操作,是否包含在(或隐含在)和调用栈中的代码相关联的权限中,AccessController利用了一个名为implies()的重要方法。
4.java.security.CodeSource
public final Certificate[] getCertificates() {//获取与该代码来源相关联的用于类文件签名的证书链 if (this.certs != null) { return (Certificate[])this.certs.clone(); } else if (this.signers == null) { return null; } else { ArrayList var1 = new ArrayList(); for(int var2 = 0; var2 < this.signers.length; ++var2) { var1.addAll(this.signers[var2].getSignerCertPath().getCertificates()); } this.certs = (Certificate[])var1.toArray(new Certificate[var1.size()]); return (Certificate[])this.certs.clone(); } }
public final URL getLocation() {//获取与该代码来源相关联的类文件代码位置 return this.location; }
3.安全策略文件
策略管理器要读取相应的策略文件(包含了将代码来源映射为权限的指令)
java.policy内容如下主要是配置了java.ext.dirs下所有文件的所有权限
// Standard extensions get all permissions by default grant codeBase "file:${{java.ext.dirs}}/*" { permission java.security.AllPermission; }; // default permissions granted to all domains grant { // Allows any thread to stop itself using the java.lang.Thread.stop() // method that takes no argument. // Note that this permission is granted by default only to remain // backwards compatible. // It is strongly recommended that you either remove this permission // from this policy file or further restrict it to code sources // that you specify, because Thread.stop() is potentially unsafe. // See the API specification of java.lang.Thread.stop() for more // information. permission java.lang.RuntimePermission "stopThread"; // allows anyone to listen on dynamic ports permission java.net.SocketPermission "localhost:0", "listen"; // "standard" properies that can be read by anyone permission java.util.PropertyPermission "java.version", "read"; permission java.util.PropertyPermission "java.vendor", "read"; permission java.util.PropertyPermission "java.vendor.url", "read"; permission java.util.PropertyPermission "java.class.version", "read"; permission java.util.PropertyPermission "os.name", "read"; permission java.util.PropertyPermission "os.version", "read"; permission java.util.PropertyPermission "os.arch", "read"; permission java.util.PropertyPermission "file.separator", "read"; permission java.util.PropertyPermission "path.separator", "read"; permission java.util.PropertyPermission "line.separator", "read"; permission java.util.PropertyPermission "java.specification.version", "read"; permission java.util.PropertyPermission "java.specification.vendor", "read"; permission java.util.PropertyPermission "java.specification.name", "read"; permission java.util.PropertyPermission "java.vm.specification.version", "read"; permission java.util.PropertyPermission "java.vm.specification.vendor", "read"; permission java.util.PropertyPermission "java.vm.specification.name", "read"; permission java.util.PropertyPermission "java.vm.version", "read"; permission java.util.PropertyPermission "java.vm.vendor", "read"; permission java.util.PropertyPermission "java.vm.name", "read"; };
安全策略文件默认位置是${java.home}/lib/security/java.policy和${user.home}/.java.policy
默认位置可以通过修改java.security文件进行更改。在自己的应用程序中可以显示的配置策略文件(注:java应用程序默认不安装安全管理器,所有看不到策略文件的作用)。两种方法:
一、在main方法内部设置系统属性System.setProperty("java.security.policy","MyApp.policy");
二、通过java -Djava.security.policy=MyApp.policy MyApp 方式启动虚拟机
正如java.policy文件所展示的一样。策略文件中授权方式
grant codeBase "file:${{java.ext.dirs}}/*" {//典型的策略文件(codeBase后面跟的是url url以“/”结尾则代表目录,否则为jar文件)
permission java.security.AllPermission;
};
grant {//一系列的grant项(这里省略了codeBase 是因为下面的授权使用于所有的代码来源)
// Allows any thread to stop itself using the java.lang.Thread.stop()
// method that takes no argument.
// Note that this permission is granted by default only to remain
// backwards compatible.
// It is strongly recommended that you either remove this permission
// from this policy file or further restrict it to code sources
// that you specify, because Thread.stop() is potentially unsafe.
// See the API specification of java.lang.Thread.stop() for more
// information.
permission java.lang.RuntimePermission "stopThread";
// allows anyone to listen on dynamic ports
permission java.net.SocketPermission "localhost:0", "listen";
// "standard" properies that can be read by anyone
permission java.util.PropertyPermission "java.version", "read";
permission java.util.PropertyPermission "java.vendor", "read";
permission java.util.PropertyPermission "java.vendor.url", "read";
permission java.util.PropertyPermission "java.class.version", "read";
permission java.util.PropertyPermission "os.name", "read";
permission java.util.PropertyPermission "os.version", "read";
permission java.util.PropertyPermission "os.arch", "read";
permission java.util.PropertyPermission "file.separator", "read";
permission java.util.PropertyPermission "path.separator", "read";
permission java.util.PropertyPermission "line.separator", "read";
permission java.util.PropertyPermission "java.specification.version", "read";
permission java.util.PropertyPermission "java.specification.vendor", "read";
permission java.util.PropertyPermission "java.specification.name", "read";
permission java.util.PropertyPermission "java.vm.specification.version", "read";
permission java.util.PropertyPermission "java.vm.specification.vendor", "read";
permission java.util.PropertyPermission "java.vm.specification.name", "read";
permission java.util.PropertyPermission "java.vm.version", "read";
permission java.util.PropertyPermission "java.vm.vendor", "read";
permission java.util.PropertyPermission "java.vm.name", "read";
};
授权(grant)中的格式为 grant codeBase "url"{permission1 权限1全类名 目标1 操作1;permission2 权限2 目标2 操作2;}
下表是所有的权限和相应的操作:
权限 | 目标 | 操作 |
Java.io.FilePermission | File 文件 Directory 目录 Directory/* 目录中的所有文件 *当前目录中的所有文件 Directory/-目录和其子目录中的所有文件 -当前目录和其子目录中所有文件 <<ALL FILES>>文件系统中的所有文件 |
Read,write,execute,delete |
Java.net.SocketPermission | 由主机和端口范围组成 Hostname或IPaddress 单个主机 Localhost或空字符串 本地主机 *.domainSuffix 以给定后缀结尾的域中所有的主机 * 所有主机 端口范围是可选,具有以下几种形式: :n 单个端口 :n-编号大于等于n的所有端口 :-n编号小于等于n的所有端口 :n1-n2位于给定范围内的所有端口。 |
Accept,connect,listen,resolve |
Java.util.PropertyPermission | Property 一个具体的属性 PropertyPrefix.*带有给定前缀的所有属性 |
Read,write |
Java.lang.RuntimePermission | createClassLoader getClassLoader setContextClassLoader enableContextClassLoaderOverride createSecurityManager setSecurityManager exitVM getenv.variableName shutdownHooks setFactory setIO modifyThread stopThread modifyThreadGroup getProtectionDomain readFileDescriptor writeFileDescriptor loadLibrary.libraryName accessClassInPackage.packageName defineClassInPackage.packageName accessDeclaredMembers.className queuePrintJob getStackTrace setDefaultUncaughtExceptionHandler preferences usePolicy |
无 |
Java.awt.AWTPermission | showWindowWithoutWarningBanner accessClipboard accessEventQueue createRobot fullScreenExclusive listenToAllAWTEvents readDisplayPixels replaceKeyboardFocusManager watchMousePointer setWindowAlwaysOnTop setAppletStub |
无 |
Java.net.NetPermission | setDefaultAuthenticator specifyStreamHandler requestPasswordAuthentication setProxySelector getProxySelector setCookieHandler getCookieHandler setResponseCache getResponseCache |
无 |
Java.lang.reflect.ReflectPermission | suppressAccessChecks | 无 |
Java.io.SerializablePermission | enableSubclassImplementation enableSubstitutioon |
无 |
Java.security.SecurityPermission | CreateAccessControlContext getdomainCominer getPolicy setPolicy getProperty.keyName setProperty.keyName insertProvider.providerName removeProvider.providerName setSystemScope setIdentityPublicKey setIdentityInfo addIdentityCertificate removeIdentityCertificate printIdentity clearProviderProperties.providerName putProvideProperty.ProviderName removeProviderProperty.providerName getSignerPrivateKey setSignerKeyPair |
无 |
Java.security.AllPermission | 无 | 无 |
Javax.audio.AudioPermission | 运行记录 | 无 |
Javax.security.auth.AuthPermission | doAs doAsPrivileged getSubject getSubjectFromDomainCombiner setReadOnly modifyPrincipals modifyPublicCredentials modifyPrivateCredentials refreshCredential destroyCredential createLoginContext.contextName getLoginConfiguration setLoginConfiguration refreshLoginCOnfiguration |
无 |
Java.util.lgging.LogginPermission | Control | 无 |
Java.sql.SQLPermission | setLog | 无 |