日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 >

Java安全机制之一——SecurityManager和AccessController

發(fā)布時間:2023/11/16 92 coder
生活随笔 收集整理的這篇文章主要介紹了 Java安全机制之一——SecurityManager和AccessController 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

前言:

在看socket相關(guān)代碼的時候,AbstractPlainSocketImpl中的一段代碼吸引了我,其實之前見過很多次類似的代碼,但一直不想去看,只知道肯定和權(quán)限什么的相關(guān),這次既然又碰到了就研究一下,畢竟也不能對java基本代碼一無所知。

static {
    java.security.AccessController.doPrivileged(
        new java.security.PrivilegedAction<Void>() {
            public Void run() {
                System.loadLibrary("net");
                return null;
            }
        });
}

一些概念:

在jdk1.0的時代,applet依然是前端的一種可用的技術(shù)方案,比如可以嵌入在網(wǎng)頁里運行。那個時候jdk的設(shè)計者們認為本地代碼是安全的、遠端代碼是有風(fēng)險的,而applet就是屬于遠端代碼。因此,為了保證用戶主機的安全和隱私,設(shè)計者參考了沙箱的思想,依托于當(dāng)時jdk的體量很小,使用SecurityManager來分隔本地代碼和遠程代碼,一個有權(quán)限,一個沒有權(quán)限。

當(dāng)時還出現(xiàn)了簽名相關(guān)的機制(本文不關(guān)心,所以沒做了解),隨著java發(fā)展,1.1的時候出現(xiàn)了JAVABEAN、JDBC、反射等新概念,于是有了更多的新權(quán)限。設(shè)計者發(fā)現(xiàn)完全授予本地代碼所有權(quán)限變得不合理,在1.2的時候重構(gòu)了SecurityManager,變成了現(xiàn)在這樣以最小粒度控制權(quán)限。這個時候的SecurityManager有兩個功能,一是防御遠程代碼、二是防御本地代碼的漏洞。

不知道是什么時候起,安全機制引入了域(ProtectDomain)的概念,也可以視作將一個大沙箱拆分為多個小沙箱。一個域?qū)?yīng)一個沙箱,不同的代碼(Codesource)被劃分到不同域中,不同的域有著不同的權(quán)限(Permission),就像下圖一樣。同時可以給不同的域配置不同的權(quán)限,靜態(tài)和動態(tài)均可,這個配置被稱為策略(Policy)。

注意!

在JDK20和JDK21的security-guide中都提到了,和SecurityManager與之相關(guān)的api已被棄用,并將在未來的版本中刪除。SecurityManager沒有替代者。有關(guān)討論和備選方案,請參閱JEP 411: Deprecate the Security Manager for Removal。

AccessController

AccessController主要有兩個功能,對應(yīng)的核心方法也是兩類

checkPermission(校驗是否存在權(quán)限)

public static void checkPermission(Permission perm)
    throws AccessControlException
{
    AccessControlContext stack = getStackAccessControlContext();
    // if context is null, we had privileged system code on the stack.
    //...其他獲取context方法
    AccessControlContext acc = stack.optimize();
    acc.checkPermission(perm);
}

調(diào)用該方法時,一般會new一個期望的權(quán)限,然后作為入?yún)魅隿heckPermission方法。

FilePermission perm = new FilePermission("C:\\Users\\Administrator\\Desktop\\liveController.txt", "read");
AccessController.checkPermission(perm);

注意,校驗權(quán)限的時候會校驗調(diào)用鏈路徑上所有類的權(quán)限;假如調(diào)用鏈?zhǔn)菑膇開始,一直調(diào)用到m,校驗邏輯如下

 for (int i = m; i > 0; i--) {
     if (caller i's domain does not have the permission)
         throw AccessControlException
     else if (caller i is marked as privileged) {
         if (a context was specified in the call to doPrivileged)
             context.checkPermission(permission)
         if (limited permissions were specified in the call to doPrivileged) {
             for (each limited permission) {
                 if (the limited permission implies the requested permission)
                     return;
             }
         } else
             return;
     }
 }

代碼執(zhí)行的時候,每一次方法的調(diào)用都代表著一次入棧,而權(quán)限校驗的時候則正好是從棧頂開始,依次判斷每個棧幀是否具有權(quán)限,一直到棧底。

doPrivileged(臨時授權(quán))

public static native <T> T doPrivileged(PrivilegedAction<T> action);

這個方法的功能是將當(dāng)前類所擁有的權(quán)限,能且僅能臨時賦予其上游調(diào)用方。
在這個場景下,必然存在多個域,且只有某些域擁有權(quán)限A,但是其他域并沒有這個權(quán)限。在java語言中很容易出現(xiàn)這個情況,比如我們調(diào)用一些第三方j(luò)ar包的方法,三方j(luò)ar包還能調(diào)用別的三方j(luò)ar包,這種場景很有可能只有最底層的方法所對應(yīng)的域擁有權(quán)限。此時為了方法的成功,就可以使用該方法。
使用的時候就是將代碼邏輯放入AccessController.doPrivileged中即可,如下述代碼一般。

//項目B,會打成security-demo.jar
public class PermissionDemo {
    /**
     * 使用特權(quán)訪問機制
     * @param file
     */
    public void runWithOutPermission(String file){
        AccessController.doPrivileged((PrivilegedAction<String>) () -> {
            //hutool的FileUtil
            String s = FileUtil.readString(file, "utf-8");
            System.out.println(s);
            return s;
        });
    }
}
//項目A,引入security-demo.jar
public class Aperson {
    public static void main(String[] args) {
        new PermissionDemo().runWithOutPermission("C:\\Users\\Administrator\\Desktop\\test.txt");
    }
}

這里需要注意的是,AccessController.doPrivileged所在的當(dāng)前類也需要擁有權(quán)限。以這個例子為例,文件讀寫是在hutool的FileUtil中執(zhí)行,hutool對應(yīng)的是域C;PermissionDemo對應(yīng)的是域B,且會將自身權(quán)限向上傳遞;而Aperson對應(yīng)的是域A。這個例子中,想要Aperson執(zhí)行成功,必須是域C和域B都擁有test.txt的read權(quán)限。
對應(yīng)的policy如下

grant codeBase  "file:/C:/Users/Administrator/.m2/repository/cn/hutool/hutool-all/5.7.11/-"{
    permission java.io.FilePermission "C:\\Users\\Administrator\\Desktop\\*", "read";
};
grant codeBase  "file:/C:/Users/Administrator/.m2/repository/xxx/xxx/security-demo/-"{
    permission java.io.FilePermission "C:\\Users\\Administrator\\Desktop\\*", "read";
};

從棧幀的角度來看的話,判斷到doPrivilege對應(yīng)的那層之后,校驗就直接返回了,不校驗下面層是否存在權(quán)限。

ProtectDomain

protectDomain類由codeSource和permission構(gòu)成

CodeSource

類的來源,一般為jar包路徑或者classpath路徑(target/classes)
因為所有類在通過ClassLoader引入的,所以ClassLoader知道類的基本信息,在defineClass時,將CodeSource和Permission進行了綁定。同理,由于類必須通過ClassLoader加載,對于使用自定義ClassLoader加載的類,就只有那個類加載器知道對應(yīng)的CodeSource和permission。因此,不同的類加載器本身就屬于不同的域。

Permission

Java抽象出的頂層的類,核心方法是implies,該方法用來判斷當(dāng)前線程是否隱含指定權(quán)限,由各自的子類實現(xiàn)。子類實現(xiàn)過多,這里就不列舉了。
PermissionCollection本質(zhì)是個list,里面是某一類權(quán)限的多個實例,比如文件夾A-讀權(quán)限,文件夾B-寫權(quán)限,文件夾C-讀寫權(quán)限。
Permissions核心是一個map,key是Permissoin子類,value是PermissionCollection

SecurityManager

SecurityManage里有一堆check方法,調(diào)用的是AccessController.checkPermission方法,入?yún)⒕褪荘ermission各個子類的實例化。

開啟方式:

隱性:啟動時添加-Djava.security.manager
顯性:System.setSecurityManager

public class NoShowTest {
     static class CustomManager extends SecurityManager{
         @Override
         public void checkRead(String file) {
             throw new AccessControlException("無權(quán)限訪問");
         }
     }
    public static void main(String[] args) {
       System.setSecurityManager(new CustomManager());
       System.getSecurityManager().checkRead("C:\\Users\\Administrator\\Desktop\\liveController.txt");
    }
}

Policy

啟動時通過 -Djava.security.policy=xxxx\custom.policy,如果沒有指定,則默認使用jdk路徑下\jre\lib\security\java.policy
參考:
Java安全:SecurityManager與AccessController - 掘金
Java沙箱機制的實現(xiàn)——安全管理器、訪問控制器 - 掘金
第21章-再談類的加載器
https://openjdk.org/jeps/411
https://docs.oracle.com/en/java/javase/20/security/java-security-overview1.html#GUID-BBEC2DC8-BA00-42B1-B52A-A49488FCF8FE
AccessController.doPrivileged - 山河已無恙 - 博客園

總結(jié)

以上是生活随笔為你收集整理的Java安全机制之一——SecurityManager和AccessController的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。