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

Java 2 安全模型下的執行緒協作:AccessControlContext 跨執行緒權限傳遞實戰

     編輯:Java 相關知識

Java 2 安全模型回顧

  • 基於堆疊檢查:SecurityManager.checkPermission 遍歷當前執行緒呼叫堆疊,每幀的 ProtectionDomain 權限集必須 implies 所需權限。
  • 保護域:同樣權限集的類歸為一域,由 Policy 文件根據 CodeSource(位置+簽名者)授予權限。
  • doPrivileged:截斷堆疊遍歷,讓特權代碼以自身權限執行敏感操作。
  • 執行緒繼承:子執行緒建立時捕獲父執行緒的 AccessControlContext,權限檢查包含父執行緒堆疊幀。

問題場景:異步生產者-消費者

Client 執行緒將 Message 放入佇列,Server 執行緒稍後取出並寫入檔案。Server 執行緒堆疊不含 Client 代碼,直接檢查會因 Server 代碼未被授予檔案寫入權限而失敗(或相反,Client 無權但 Server 有權導致越權)。

解決方案:AccessControlContext 傳遞

// Message 類新增欄位
class Message {
    String destination, info;
    AccessControlContext acc; // 捕獲生產者執行緒權限上下文
}

// Server 端 LogService
public class LogService implements Runnable {
    private final List<Message> queue = new ArrayList<>();

    // 生產者呼叫(Client 執行緒)
    public synchronized void log(Message msg) {
        msg.acc = AccessController.getContext(); // 捕獲當前上下文
        queue.add(msg);
        notifyAll();
    }

    // 消費者執行緒
    public void run() {
        while (true) {
            Message msg = retrieveMessage(); // 從 queue 取出
            final String dest = msg.destination;
            final String content = msg.info;

            AccessController.doPrivileged(
                new PrivilegedAction<Void>() {
                    public Void run() {
                        try (FileWriter fw = new FileWriter(dest, true)) {
                            fw.write(content);
                        } catch (IOException e) { e.printStackTrace(); }
                        return null;
                    }
                },
                msg.acc // 使用生產者的 AccessControlContext 進行權限檢查
            );
        }
    }
}

權限檢查路徑圖解

Server Thread Stack          Client Thread Stack (captured in msg.acc)
┌─────────────────────┐      ┌─────────────────────┐
│ LogService.run()    │      │ Client.main()       │
│   doPrivileged(acc) │─────▶│   LogService.log()  │  ← 權限檢查在此停止
│     FileWriter      │      │     (signed by server│
└─────────────────────┘      │      has AllPermission)│
                             └─────────────────────┘

關鍵:doPrivileged(action, acc) 會將檢查跳轉到 acc 所捕獲的堆疊幀,實現「以調用者身份執行特權操作」。

部署配置範例

Keystore 與簽名

keytool -genkey -alias client -keyalg RSA -keystore .keystore
keytool -genkey -alias server -keyalg RSA -keystore .keystore
jarsigner -keystore .keystore client.jar client
jarsigner -keystore .keystore server.jar server

Policy 文件

keystore "file:///C:/paper/.keystore";

grant signedBy "client" {
    permission java.io.FilePermission "c:\\paper\\client\\*", "read,write";
};

grant signedBy "server" {
    permission java.security.AllPermission;
};

啟動參數

java -Djava.security.manager -Djava.security.policy=my.policy \
     -classpath client.jar;server.jar sample.permtest.thread.client.Client

效能考量與優化

  • 堆疊遍歷有開銷,高頻敏感操作請用 doPrivileged 縮短檢查路徑。
  • 跨執行緒傳遞 AccessControlContext 本身輕量(不可變快照),但頻繁捕獲仍有分配壓力。
  • 可自訂 SecurityManager 子類別,針對特定權限類別快速判斷。

現代替代方案

Java 9+ 模組系統 + java.security.Policy 擴展;微服務架構下,授權通常下沉至 API Gateway / Service Mesh (OAuth2, RBAC),進程內 Java 安全管理器較少見。但理解「堆疊檢查、特權動作、上下文傳遞」三大核心機制,對排查沙箱逃逸、權限提升等安全漏洞仍具參考價值。

總結

Java 2 安全模型提供細粒度、基於堆疊的存取控制。異步執行緒協作時,透過 AccessController.getContext() 捕獲調用者上下文,並在特權動作中傳入 doPrivileged(action, acc),即可實現「以調用者權限執行敏感操作」的安全委派模式。此機制是早期 Java EE 容器、Applet 沙箱、RMI 安全的基石。

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