2020-03-25-Java安全模型(AccessController)(轉(zhuǎn))


layout: post
title: Java安全模型(AccessController)(轉(zhuǎn))
categories: [Java]
description: Java安全模型(AccessController)
keywords: Java, AccessController


轉(zhuǎn)載自 Java 安全模型介紹

Java 安全模型

在 Java 中將執(zhí)行程序分成本地和遠(yuǎn)程兩種占遥,本地代碼默認(rèn)視為可信任的柏腻,而遠(yuǎn)程代碼則被看作是不受信的榴鼎。對于授信的本地代碼,可以訪問一切本地資源。而對于非授信的遠(yuǎn)程代碼在早期的 Java 實(shí)現(xiàn)中放仗,安全依賴于沙箱 (Sandbox) 機(jī)制砂竖。沙箱機(jī)制就是將 Java 代碼限定在虛擬機(jī) (JVM) 特定的運(yùn)行范圍中,并且嚴(yán)格限制代碼對本地系統(tǒng)的資源訪問娜遵,通過這樣的措施來保證對遠(yuǎn)程代碼的有效隔離,防止對本地系統(tǒng)造成破壞壤短。如圖所示

image-20200325150232862.png

但如此嚴(yán)格的安全機(jī)制也給程序的功能擴(kuò)展帶來障礙设拟,比如當(dāng)用戶希望遠(yuǎn)程代碼訪問本地系統(tǒng)的文件時(shí)候,就無法實(shí)現(xiàn)久脯。因此在后續(xù)的 Java1.1 版本中纳胧,針對安全機(jī)制做了改進(jìn),增加了安全策略桶现,允許用戶指定代碼對本地資源的訪問權(quán)限躲雅。如圖所示

image-20200325150307744.png

在 Java1.2 版本中,再次改進(jìn)了安全機(jī)制骡和,增加了代碼簽名相赁。不論本地代碼或是遠(yuǎn)程代碼,都會(huì)按照用戶的安全策略設(shè)定慰于,由類加載器加載到虛擬機(jī)中權(quán)限不同的運(yùn)行空間钮科,來實(shí)現(xiàn)差異化的代碼執(zhí)行權(quán)限控制。如圖所示

image-20200325150337220.png

當(dāng)前最新的安全機(jī)制實(shí)現(xiàn)婆赠,則引入了域 (Domain) 的概念绵脯。虛擬機(jī)會(huì)把所有代碼加載到不同的系統(tǒng)域和應(yīng)用域,系統(tǒng)域部分專門負(fù)責(zé)與關(guān)鍵資源進(jìn)行交互休里,而各個(gè)應(yīng)用域部分則通過系統(tǒng)域的部分代理來對各種需要的資源進(jìn)行訪問蛆挫。虛擬機(jī)中不同的受保護(hù)域 (Protected Domain),對應(yīng)不一樣的權(quán)限 (Permission)妙黍。存在于不同域中的類文件就具有了當(dāng)前域的全部權(quán)限悴侵,如圖所示

image-20200325150409427.png

以上提到的都是基本的 Java 安全模型概念,在應(yīng)用開發(fā)中還有一些關(guān)于安全的復(fù)雜用法拭嫁,其中最常用到的 API 就是 doPrivileged可免。doPrivileged 方法能夠使一段受信任代碼獲得更大的權(quán)限,甚至比調(diào)用它的應(yīng)用程序還要多做粤,可做到臨時(shí)訪問更多的資源浇借。有時(shí)候這是非常必要的,可以應(yīng)付一些特殊的應(yīng)用場景怕品。例如妇垢,應(yīng)用程序可能無法直接訪問某些系統(tǒng)資源,但這樣的應(yīng)用程序必須得到這些資源才能夠完成功能。針對這種情況修己,Java SDK 給域提供了 doPrivileged 方法恢总,讓程序突破當(dāng)前域權(quán)限限制,臨時(shí)擴(kuò)大訪問權(quán)限睬愤。下面內(nèi)容會(huì)詳細(xì)講解一下安全相關(guān)的方法使用。

Java 安全控制實(shí)現(xiàn)

Java SDK 中與安全相關(guān)的類和接口都放在 java.security 包中纹安,其中既包括訪問控制配置及細(xì)粒度訪問控制框架的實(shí)現(xiàn)尤辱,還包括簽名和加解密的實(shí)現(xiàn)。本文中涉及到的安全訪問控制主要與安全包中訪問控制框架相關(guān)厢岂,這里面最常用的就是 AccessController 類光督。通過下圖的描述,您可以了解 ACC(Access Contorller) 機(jī)制是如何運(yùn)作的塔粒。

在某一個(gè)線程的調(diào)用棧中结借,當(dāng) AccessController 的 checkPermission 方法被最近的調(diào)用程序(例如 A 類中的方法)調(diào)用時(shí),對于程序要求的所有訪問權(quán)限卒茬,ACC 決定是否授權(quán)的基本算法如下:

  1. 如果調(diào)用鏈中的某個(gè)調(diào)用程序沒有所需的權(quán)限船老,將拋出 AccessControlException;
  2. 若是滿足以下情況即被授予權(quán)限:
    • 調(diào)用程序訪問另一個(gè)有該權(quán)限域里程序的方法圃酵,并且此方法標(biāo)記為有訪問“特權(quán)”柳畔;
    • 調(diào)用程序所調(diào)用(直接或間接)的后續(xù)對象都有上述權(quán)限。

在上面例子的調(diào)用鏈中郭赐,假定 E 域和 F 域不具備 X 權(quán)限 (permission)薪韩,而在 C.class 對應(yīng)的 G 域具有 X 權(quán)限,同時(shí) C 使用 X 權(quán)限的對外接口 Y 方法是通過 doPrivilege 方式實(shí)現(xiàn)捌锭。那么俘陷,B.class A.class 調(diào)用 Y 方法就都具備 X 權(quán)限。如果 Y 方法沒有標(biāo)注 doPrivilege观谦,那么對 Y 方法的調(diào)用就不具備 X 權(quán)限拉盾。

還有一種特殊的情況,就是訪問控制上下文的繼承問題坎匿。當(dāng)一個(gè)線程創(chuàng)建另一個(gè)新線程時(shí)盾剩,會(huì)同時(shí)創(chuàng)建新的堆棧。如果創(chuàng)建新線程時(shí)沒有保留當(dāng)前的安全上下文替蔬,也就是線程相關(guān)的安全信息告私,則新線程調(diào)用 AccessController.checkPermission 檢驗(yàn)權(quán)限時(shí),安全訪問控制機(jī)制只會(huì)根據(jù)新線程的上下文來決定安全性問題承桥,而不會(huì)考慮其父線程的相應(yīng)權(quán)限驻粟。這個(gè)清除堆棧的做法本身并不會(huì)給系統(tǒng)帶來安全隱患,但它會(huì)使源代碼,尤其是系統(tǒng)代碼的編寫容易出現(xiàn)錯(cuò)誤蜀撑。例如挤巡,對安全框架實(shí)現(xiàn)不熟悉編程人員可能會(huì)很自然地認(rèn)為,子線程執(zhí)行的信任代碼繼承了父線程執(zhí)行的不可信任代碼的安全限制特性酷麦。當(dāng)從子線程內(nèi)訪問受控制的資源時(shí)矿卑,如果父線程的安全上下文信息并未保存,就會(huì)導(dǎo)致意外的安全漏洞沃饶。因?yàn)閬G失的父線程中安全限制數(shù)據(jù)會(huì)使子線程將資源傳遞給一些不可信任的代碼母廷。因此,在創(chuàng)建新線程時(shí)糊肤,必須確保利用父線程創(chuàng)建琴昆,或利用其他形式創(chuàng)建代碼」萑啵總之业舍,要保證讓子線程自動(dòng)繼承父線程的安全性上下文,這樣子線程中的后續(xù) AccessController.checkPermission 調(diào)用就會(huì)考慮所繼承的父線程的安全特性升酣。

需要注意是 AccessController 類的 checkPermission 方法將在當(dāng)前執(zhí)行線程的上下文舷暮,包括繼承的上下文中進(jìn)行安全檢查。當(dāng)這種安全檢查只能在不同的上下文中進(jìn)行時(shí)就會(huì)出現(xiàn)問題拗踢。意即脚牍,本應(yīng)在一個(gè)線程上下文內(nèi)部進(jìn)行的安全檢查,有時(shí)卻需要在不同上下文中進(jìn)行巢墅。例如诸狭,當(dāng)一個(gè)線程將某個(gè)事件傳給另一個(gè)線程時(shí),如果所請求的事件服務(wù)要求訪問某種安全受控資源君纫,則為其請求事件服務(wù)的第二個(gè)線程將沒有事件產(chǎn)生源線程相應(yīng)的上下文來完成所需的訪問控制決策驯遇。為解決這樣的問題,Java 在 AccessController 類中提供了 getContext 方法和 AccessControlContext 對象蓄髓。通過 getContext 方法可獲取當(dāng)前調(diào)用上下文的“快照 (snapshot)”叉庐,然后將其存放到返回的 AccessControlContext 對象中。調(diào)用的樣例程序如下所示:

AccessControlContext acc = AccessController.getContext();

getContext 方法將當(dāng)前上下文的快照信息捕獲会喝,然后執(zhí)行程序就可以通過檢查前后不同上下文中的信息陡叠,即比較快照上下文信息與本上下文信息,然后來做出對受控資源訪問控制的決策肢执。上面問題就可以如下方式來解決:

當(dāng)前一個(gè)線程把某個(gè)請求事件傳給第二個(gè)線程時(shí)枉阵,同時(shí)捕獲其上下文信息并將這些信息提供給后一個(gè)線程。略有不同的是预茄,AccessControlContext 類本身的 checkPermission 方法可根據(jù)它自身攜帶的上下文信息來決定訪問控制兴溜,而不是根據(jù)當(dāng)前正在執(zhí)行的線程上下文。因此必要時(shí),后一個(gè)線程可直接通過調(diào)用前一個(gè)線程上下文快照本身的權(quán)限檢查方法來執(zhí)行相應(yīng)的安全檢查拙徽。如下:

acc.checkPermission(permission)

上述方法調(diào)用等同于在前一個(gè)線程的上下文中執(zhí)行相同的安全檢查刨沦,盡管訪問控制檢查實(shí)際上是在后一個(gè)線程中完成的。

安全控制使用的代碼實(shí)例

上面關(guān)于安全控制使用的描述還是比較晦澀膘怕,下面將通過一個(gè)代碼示例進(jìn)行說明想诅。

在 Eclipse 開發(fā)環(huán)境中建立兩個(gè)不同工程:projectX 和 projectY。我們會(huì)給 projectX 工程中的 bin 目錄賦予寫文件的權(quán)限岛心,換句話說就是允許所有存在于此目錄中的 class 文件可以自由的在 bin 目錄中進(jìn)行文件寫操作侧蘸。然后,我們會(huì)在 projectY 工程中調(diào)用 projectX 工程中的一個(gè)文件操作工具類鹉梨。這個(gè)工具類提供兩種類型接口,一種是特權(quán)訪問方式穿稳,另外一種是普通訪問方式存皂。由于在 projectY 工程中的文件是不具備在 projectX 工程中 bin 目錄的任何寫權(quán)限,所以通過三種不同訪問方式的調(diào)用結(jié)果逢艘,我們就可以很清楚地了解到 Java 中安全控制該如何使用旦袋。

假定 ProjectX 的項(xiàng)目路徑為 D:\workspace\projectX\

package learn.java.security; 

import java.io.File; 
import java.io.IOException; 
import java.security.AccessControlException; 
import java.security.AccessController; 
import java.security.PrivilegedAction; 

public class FileUtil { 
  // 工程 A 執(zhí)行文件的路徑 
  private final static String FOLDER_PATH = "D:\\workspace\\projectX\\bin"; 
  
  public static void makeFile(String fileName) { 
    try { 
      // 嘗試在工程 A 執(zhí)行文件的路徑中創(chuàng)建一個(gè)新文件
      File fs = new File(FOLDER_PATH + "\\" + fileName); 
      fs.createNewFile(); 
    } catch (AccessControlException e) { 
      e.printStackTrace(); 
    } catch (IOException e) { 
      e.printStackTrace(); 
    } 
  } 
  
  public static void doPrivilegedAction(final String fileName) { 
    // 用特權(quán)訪問方式創(chuàng)建文件
    AccessController.doPrivileged(new PrivilegedAction<``String``>() { 
      @Override 
      public String run() { 
        makeFile(fileName); 
        return null; 
      } 
    }); 
  } 
}  

假定 ProjectY 的項(xiàng)目路徑為 D:\workspace\projectY\

package demo.security; 

import java.io.File; 
import java.io.IOException; 
import java.security.AccessControlException; 

import learn.java.security.FileUtil; 

public class DemoDoPrivilege { 
  public static void main(String[] args) { 
    System.out.println("***************************************"); 
    System.out.println("I will show AccessControl functionality..."); 
    
    System.out.println("Preparation step : turn on system permission check..."); 
    // 打開系統(tǒng)安全權(quán)限檢查開關(guān)
    System.setSecurityManager(new SecurityManager()); 
    System.out.println(); 
    
    System.out.println("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"); 
    System.out.println("Create a new file named temp1.txt via privileged action ..."); 
    // 用特權(quán)訪問方式在工程 A 執(zhí)行文件路徑中創(chuàng)建 temp1.txt 文件
    FileUtil.doPrivilegedAction("temp1.txt"); 
    System.out.println("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"); 
    System.out.println();
    System.out.println("http://///////////////////////////////////////"); 
    System.out.println("Create a new file named temp2.txt via File ..."); 
    try { 
      // 用普通文件操作方式在工程 A 執(zhí)行文件路徑中創(chuàng)建 temp2.txt 文件
      File fs = new File("D:\\workspace\\projectX\\bin\\temp2.txt"); 
      fs.createNewFile(); 
    } catch (IOException e) { 
      e.printStackTrace(); 
    } catch (AccessControlException e1) { 
      e1.printStackTrace(); 
    } 
    System.out.println("http://///////////////////////////////////////"); 
    System.out.println(); 
    
    System.out.println("-----------------------------------------"); 
    System.out.println("create a new file named temp3.txt via FileUtil ..."); 
    // 直接調(diào)用普通接口方式在工程 A 執(zhí)行文件路徑中創(chuàng)建 temp3.txt 文件
    FileUtil.makeFile("temp3.txt"); 
    System.out.println("-----------------------------------------"); 
    System.out.println(); 
    System.out.println("***************************************"); 
  } 
}

應(yīng)用的安全訪問控制策略文件 (MyPolicy.txt) 如下 , 假定安全策略文件放于 projectY 工程的根目錄下:

// 授權(quán)工程 A 執(zhí)行文件路徑中文件在本目錄中的寫文件權(quán)限
grant codebase "file:/D:/workspace/projectX/bin"
{
    permission java.io.FilePermission
        "D:\\workspace\\projectX\\bin\\*", "write"; 
};

下面就可以運(yùn)行程序了,您可以選擇在 Eclipse 開發(fā)環(huán)境中直接運(yùn)行它改,也可以通過命令行來執(zhí)行疤孕。命令行執(zhí)行如下所示,假定當(dāng)前執(zhí)行目錄就是 projectY 的根目錄央拖。

java -Djava.security.policy=.\\MyPolicy.txt -classpath D:\workspace\projectY\bin;D:\workspace\projectX\bin demo.security.DemoDoPrivilege

執(zhí)行結(jié)果如下:

image-20200325152712108.png

通過程序打印結(jié)果來看祭阀,當(dāng)往 projectX 工程中 bin 目錄創(chuàng)建 temp1.txt,temp2.txt鲜戒,temp3.txt 文件時(shí)候专控,除了通過特權(quán)訪問方式可以創(chuàng)建成功外,通過普通接口訪問或者直接文件操作方式都會(huì)失敗遏餐,失敗的原因都是沒有通過權(quán)限檢查伦腐。

對照前文所描述的權(quán)限檢查規(guī)則,用一句話總結(jié)就是想訪問安全資源失都,要么調(diào)用鏈上權(quán)限齊全柏蘑,要么就要用特權(quán)。特權(quán)訪問機(jī)制實(shí)際上就是給應(yīng)用開后門的粹庞,使用上需要小心咳焚,所以這也給代碼實(shí)現(xiàn)帶來新的考慮,開放范圍一定要限定好信粮,否則可能留下安全隱患黔攒。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子督惰,更是在濱河造成了極大的恐慌不傅,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,692評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件赏胚,死亡現(xiàn)場離奇詭異访娶,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)觉阅,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,482評論 3 392
  • 文/潘曉璐 我一進(jìn)店門崖疤,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人典勇,你說我怎么就攤上這事劫哼。” “怎么了割笙?”我有些...
    開封第一講書人閱讀 162,995評論 0 353
  • 文/不壞的土叔 我叫張陵权烧,是天一觀的道長。 經(jīng)常有香客問我伤溉,道長般码,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,223評論 1 292
  • 正文 為了忘掉前任乱顾,我火速辦了婚禮板祝,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘走净。我一直安慰自己券时,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,245評論 6 388
  • 文/花漫 我一把揭開白布温技。 她就那樣靜靜地躺著革为,像睡著了一般。 火紅的嫁衣襯著肌膚如雪舵鳞。 梳的紋絲不亂的頭發(fā)上震檩,一...
    開封第一講書人閱讀 51,208評論 1 299
  • 那天,我揣著相機(jī)與錄音蜓堕,去河邊找鬼抛虏。 笑死,一個(gè)胖子當(dāng)著我的面吹牛套才,可吹牛的內(nèi)容都是我干的迂猴。 我是一名探鬼主播,決...
    沈念sama閱讀 40,091評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼背伴,長吁一口氣:“原來是場噩夢啊……” “哼沸毁!你這毒婦竟也來了峰髓?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,929評論 0 274
  • 序言:老撾萬榮一對情侶失蹤息尺,失蹤者是張志新(化名)和其女友劉穎携兵,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體搂誉,經(jīng)...
    沈念sama閱讀 45,346評論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡徐紧,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,570評論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了炭懊。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片并级。...
    茶點(diǎn)故事閱讀 39,739評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖侮腹,靈堂內(nèi)的尸體忽然破棺而出嘲碧,到底是詐尸還是另有隱情,我是刑警寧澤父阻,帶...
    沈念sama閱讀 35,437評論 5 344
  • 正文 年R本政府宣布呀潭,位于F島的核電站,受9級特大地震影響至非,放射性物質(zhì)發(fā)生泄漏糠聪。R本人自食惡果不足惜荒椭,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,037評論 3 326
  • 文/蒙蒙 一舰蟆、第九天 我趴在偏房一處隱蔽的房頂上張望趣惠。 院中可真熱鬧身害,春花似錦味悄、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,677評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至丙猬,卻和暖如春涨颜,著一層夾襖步出監(jiān)牢的瞬間茧球,已是汗流浹背庭瑰。 一陣腳步聲響...
    開封第一講書人閱讀 32,833評論 1 269
  • 我被黑心中介騙來泰國打工抢埋, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留弹灭,地道東北人督暂。 一個(gè)月前我還...
    沈念sama閱讀 47,760評論 2 369
  • 正文 我出身青樓,卻偏偏與公主長得像穷吮,于是被迫代替她去往敵國和親逻翁。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,647評論 2 354

推薦閱讀更多精彩內(nèi)容

  • 作為一種誕生于互聯(lián)網(wǎng)興起時(shí)代的語言酒来,Java 從一開始就帶有安全上的考慮卢未,如何保證通過互聯(lián)網(wǎng)下載到本地的 Java...
    barry_di閱讀 550評論 0 2
  • Java安全模型側(cè)重于保護(hù)終端用戶免受從網(wǎng)絡(luò)下載的堰汉、來自不可靠來源的辽社、惡意程序(以及善意程序中的bug)的侵犯翘鸭。為...
    strang_閱讀 476評論 0 2
  • 一:java概述:1滴铅,JDK:Java Development Kit就乓,java的開發(fā)和運(yùn)行環(huán)境汉匙,java的開發(fā)工...
    ZaneInTheSun閱讀 2,650評論 0 11
  • 1生蚁、面向?qū)ο蟮奶卣饔心男┓矫?1.抽象:抽象就是忽略一個(gè)主題中與當(dāng)前目標(biāo)無關(guān)的那些方面,以便更充分地注意與當(dāng)前目標(biāo)...
    michaelgong閱讀 823評論 0 1
  • 1. cpu通過時(shí)間片分配算法來循環(huán)執(zhí)行任務(wù)邦投,當(dāng)前任務(wù)執(zhí)行一個(gè)時(shí)間片后會(huì)切換到下一任務(wù)伤锚。但是志衣,再切換之前會(huì)保存上一...
    冰與河豚魚閱讀 664評論 0 0