SecurityManager.checkPermission 遍歷當前執行緒呼叫堆疊,每幀的 ProtectionDomain 權限集必須 implies 所需權限。Client 執行緒將 Message 放入佇列,Server 執行緒稍後取出並寫入檔案。Server 執行緒堆疊不含 Client 代碼,直接檢查會因 Server 代碼未被授予檔案寫入權限而失敗(或相反,Client 無權但 Server 有權導致越權)。
// 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 所捕獲的堆疊幀,實現「以調用者身份執行特權操作」。
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
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 安全的基石。