1. 程式人生 > >Java安全--安全管理器與訪問許可權(一)

Java安全--安全管理器與訪問許可權(一)

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.ReflectPermissionsuppressAccessChecks

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.LogginPermissionControl
Java.sql.SQLPermissionsetLog