首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 安全模型演進與 AccessController 實戰:從沙箱到特權動作的完整解析

     編輯:Java 相關知識

Java 安全模型歷代演進

Java 誕生於網絡時代,安全是核心設計目標。其安全模型經歷三次重大演進:

版本模型特徵關鍵機制
JDK 1.0沙箱模型本地代碼全信任,遠程代碼嚴格限制在 JVM 沙箱內,無法訪問本地資源。
JDK 1.1安全策略 + 代碼簽名引入策略文件,用戶可授予遠程代碼特定權限;簽名代碼可獲更多信任。
JDK 1.2+保護域 + 權限集合所有代碼(本地/遠程)由類加載器分配到不同保護域,每域擁有權限集合;引入 doPrivileged 臨時提權。
現代域模型虛擬機劃分系統域(核心資源)與應用域(業務代碼),應用域通過系統域代理訪問資源,實現細粒度隔離。

JDK1.0 安全模型 JDK1.1 安全模型 JDK1.2 安全模型 最新安全模型

核心機制:AccessController 權限檢查算法

當調用鏈上某方法調用 AccessController.checkPermission(perm) 時,ACC 按以下邏輯決定是否授權:

  1. 若調用鏈任一調用者缺少該權限 → 拋出 AccessControlException。
  2. 若滿足以下任一條件 → 授權:
    • 調用者調用了擁有該權限域的方法,且該方法標記為 doPrivileged(特權動作)。
    • 調用鏈後續所有調用者均擁有該權限。

示例場景

  • Domain E、F 無權限 X。
  • Domain G(C.class 所在)擁有權限 X,且暴露方法 Y 為 doPrivileged 實現。
  • B.class、A.class 調用 Y → 擁有權限 X。
  • 若 Y 未標記 doPrivileged → 調用無權限 X。

線程上下文繼承與 AccessControlContext

問題:新線程不自動繼承父線程安全上下文,導致子線程權限檢查忽略父線程限制,可能造成安全漏洞。

解決:創建線程時保留父線程 AccessControlContext,或使用 AccessController.getContext() 獲取快照傳遞給子線程,子線程調用 acc.checkPermission(perm) 即在父上下文中檢查。

// 父線程捕獲上下文快照
AccessControlContext acc = AccessController.getContext();
// 傳遞給子線程,子線程執行:
acc.checkPermission(permission); // 等價於在父線程上下文中檢查

實戰演示:跨項目權限隔離與 doPrivileged 突破

場景設置

  • ProjectX:工具類 FileUtil,路徑 D:\workspace\projectX\bin,擁有該目錄寫權限。
  • ProjectY:調用方,無寫權限。
  • 策略文件 MyPolicy.txt 僅授予 ProjectX bin 目錄寫權限。

FileUtil 提供兩種訪問方式

public class FileUtil {
    private static final String FOLDER_PATH = "D:\\workspace\\projectX\\bin";

    // 普通方式:受調用者權限約束
    public static void makeFile(String fileName) {
        try { new File(FOLDER_PATH + "\\" + fileName).createNewFile(); }
        catch (AccessControlException | IOException e) { e.printStackTrace(); }
    }

    // 特權方式:臨時提權至 FileUtil 所在域權限
    public static void doPrivilegedAction(final String fileName) {
        AccessController.doPrivileged(new PrivilegedAction<String>() {
            public String run() { makeFile(fileName); return null; }
        });
    }
}

DemoDoPrivilege 測試三種調用

public class DemoDoPrivilege {
    public static void main(String[] args) {
        System.setSecurityManager(new SecurityManager()); // 開啟安全檢查

        // 1. 特權調用 → 成功
        FileUtil.doPrivilegedAction("temp1.txt");

        // 2. 直接 new File → 失敗(DemoDoPrivilege 無權限)
        new File("D:\\workspace\\projectX\\bin\\temp2.txt").createNewFile();

        // 3. 普通調用 FileUtil.makeFile → 失敗(調用鏈含無權限 DemoDoPrivilege)
        FileUtil.makeFile("temp3.txt");
    }
}

運行命令與結果

java -Djava.security.policy=.\\MyPolicy.txt -classpath D:\workspace\projectY\bin;D:\workspace\projectX\bin demo.security.DemoDoPrivilege
Create temp1.txt via privileged action ...  SUCCESS
Create temp2.txt via File ...  AccessControlException: Access denied (write)
Create temp3.txt via FileUtil ...  AccessControlException: Access denied (write)

核心結論與最佳實踐

  1. 權限檢查原則:調用鏈全程擁有權限,或關鍵環節使用 doPrivileged 突破。
  2. doPrivileged 是「後門」:必須將提權範圍最小化(僅包裹必要操作),防止權限濫用造成安全隱患。
  3. 線程安全上下文:多線程場景務必顯式傳遞 AccessControlContext,確保權限邊界不因線程切換而失效。
  4. 策略文件管理:生產環境應集中管理策略文件,避免硬編碼路徑,定期審計權限分配。

Java 安全模型通過保護域、權限集合與特權動作,構建了靈活且嚴格的訪問控制體系。深入理解 AccessController 檢查算法與上下文傳遞機制,是編寫安全健壯系統級代碼的關鍵。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved