![第13章移動代碼安全-課件_第1頁](http://file4.renrendoc.com/view/d856e145d67b59ac682227843ff58327/d856e145d67b59ac682227843ff583271.gif)
![第13章移動代碼安全-課件_第2頁](http://file4.renrendoc.com/view/d856e145d67b59ac682227843ff58327/d856e145d67b59ac682227843ff583272.gif)
![第13章移動代碼安全-課件_第3頁](http://file4.renrendoc.com/view/d856e145d67b59ac682227843ff58327/d856e145d67b59ac682227843ff583273.gif)
![第13章移動代碼安全-課件_第4頁](http://file4.renrendoc.com/view/d856e145d67b59ac682227843ff58327/d856e145d67b59ac682227843ff583274.gif)
![第13章移動代碼安全-課件_第5頁](http://file4.renrendoc.com/view/d856e145d67b59ac682227843ff58327/d856e145d67b59ac682227843ff583275.gif)
版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認(rèn)領(lǐng)
文檔簡介
1、第13章 移動代碼安全 13.1 引言 13.2 移動代碼安全技術(shù) 13.3 Java安全 13.1 引 言 移動代碼又稱移動代理、可下載代碼、可執(zhí)行內(nèi)容、遠程代碼等等,它是指在本地執(zhí)行的遠程代碼。傳統(tǒng)系統(tǒng)中,執(zhí)行的代碼都是駐留在執(zhí)行代碼的主機上,而對于移動代碼,執(zhí)行的代碼則是來自遠程主機。 Carzaniga等人1將移動代碼進行了分類并與傳統(tǒng)的基于客戶機服務(wù)器技術(shù)的分布式系統(tǒng)作了比較: (1) 客戶機服務(wù)器模型:客戶機和服務(wù)器位于不同的主機上,由客戶機向服務(wù)器發(fā)送請求;處理請求所需的資源和代碼都位于服務(wù)器端。 (2) 即時響應(yīng)代碼(Code-on-Demand):客戶機擁有完成某項操作的資源
2、,但沒有如何完成這項操作的代碼,客戶機通過向遠程服務(wù)器發(fā)送請求,由服務(wù)器將代碼發(fā)送給客戶機。這種類型的移動代碼包括:Java應(yīng)用程序、ActiveX控件、MIMI Tcl擴展和Postscript等。 (3) 遠程計算:客戶機擁有描述某項服務(wù)的代碼,而執(zhí)行代碼所需的資源位于遠程服務(wù)器上??蛻魴C把代碼發(fā)送到服務(wù)器上,由服務(wù)器執(zhí)行代碼并把結(jié)果回送到客戶機。 (4) 移動代理:客戶機進程在執(zhí)行期間為了完成某項服務(wù)需要訪問一些資源,而這些資源位于遠程服務(wù)器上,于是客戶機把客戶機進程移植到服務(wù)器端并由服務(wù)器完成服務(wù)。客戶機進程會一直停留在服務(wù)器上直到下一個客戶機進程移植過來。 Java應(yīng)用程序(Appl
3、et)和代理(Agent)是移動代碼中的兩種主要形式。Java應(yīng)用程序是用戶把代碼從遠程主機下載到本地執(zhí)行。這種技術(shù)在Web瀏覽器中嵌入了Java虛擬機。這樣,Web發(fā)布者就可以向用戶提供動畫、游戲等動態(tài)內(nèi)容,而不僅僅提供靜態(tài)的HTML頁面或依賴于帶寬的CGI交互式內(nèi)容。而代理則相反,用戶是把代碼發(fā)送到網(wǎng)絡(luò)上以完成用戶所需的某項任務(wù)。最早的移動代理系統(tǒng)之一是Telescript。 從上面的討論可以看出,移動代碼是由一方生成,但在另一方控制的環(huán)境中運行的代碼。這就會帶來安全問題。如對于Java應(yīng)用程序,用戶在執(zhí)行它來實現(xiàn)某些操作的同時要承擔(dān)惡意代碼破壞系統(tǒng)的風(fēng)險,而代理則要保護其代碼免受惡意主機
4、的利用。13.2 移動代碼安全技術(shù) 移動代碼會導(dǎo)致安全問題的本質(zhì)在于在運行代碼時需要訪問系統(tǒng)資源,而代碼卻是來自于另一臺,甚至是不可信的主機。即代碼提供者和代碼運行者之間可能是互不信任的。移動代碼易受到以下幾種類型的攻擊2: (1) 泄漏用戶或主機的機密信息; (2) 拒絕服務(wù):使合法用戶無法獲得資源; (3) 破壞或修改數(shù)據(jù); (4) 惡作劇攻擊:如在用戶屏幕上顯示圖片或在用戶主機上播放音樂等。移動代碼安全需要考慮以下幾個方面:(1) 訪問控制:規(guī)定誰可以使用代碼;(2) 用戶認(rèn)證:識別合法用戶;(3) 數(shù)據(jù)完整性:保證代碼在傳輸過程中未被修改過;(4) 不可抵賴:發(fā)送者和接收方不能否認(rèn)使用
5、過代碼;(5) 數(shù)據(jù)機密性:保護敏感數(shù)據(jù);(6) 審計:跟蹤移動代碼的使用。 在前面提到,移動代碼安全可以從兩個方面考慮:一是惡意代碼對本地系統(tǒng)的破壞;二是遠程惡意主機對代理的非法使用。接下來,我們將從惡意代碼和惡意主機兩個方面來討論移動代碼的安全技術(shù)3。 13.2.1 惡意代碼 對于Java應(yīng)用程序類的移動代碼,一般的操作是用戶下載可執(zhí)行格式的二進制Applet然后運行。這就很容易帶來安全問題:用戶必須允許不可信的代碼在本機運行,而這些代碼可能會隨機寫內(nèi)存,從而導(dǎo)致系統(tǒng)崩潰;代碼甚至可以讀、修改以至刪除用戶個人文件。 在運行Applet之前進行認(rèn)證可以解決這個問題。通過認(rèn)證,用戶就可以確定它
6、所運行的代碼來自于特定的可信源。但是這種方法帶來了兩個問題: (1) 嚴(yán)重限制了用戶可以運行的Applet(必須來自可信源),而不可信服務(wù)器也可提供有用的、好的代碼; (2) 更重要的是來自可信源的代碼可能存在bug,從而對用戶系統(tǒng)帶來惡劣的影響。 對這個問題的理想解決方法就是阻止不安全的行為。接下來討論三種解決惡意代碼問題的技術(shù):安全解釋器、故障隔離和代碼驗證。 1安全解釋器 直接運行二進制代碼是很危險的,解決這個問題的常用方法是不使用編譯好的可執(zhí)行代碼,而采用解釋移動代碼的方法。在這種情況下,解釋器能很好地控制Applet并能檢查每一條指令和每一個狀態(tài)以決定是否執(zhí)行Applet。這樣,系統(tǒng)
7、的安全性就在于實現(xiàn)解釋器的安全策略的正確性上。安全解釋器包括Safe-Tcl、Safe-Tcl擴展、Java等等。 2故障隔離 采用安全的解釋器系統(tǒng)能很好地解決惡意代碼的問題。但是,相對編譯的機器碼而言,解釋器存在嚴(yán)重的性能缺陷:執(zhí)行Java Applet比執(zhí)行一般的二進制代碼要慢得多。為此可以轉(zhuǎn)而采用一種稱為“沙盒”(sandbox)的方法來獲得安全。 在沙盒模式中,下載的不可信代碼的操作將嚴(yán)格局限于沙盒中。沙盒是由運行代碼的主機特別為移動代碼分配的地址空間,如Web瀏覽器特別為Java Applet分配的區(qū)域。這時,移動代碼可以在沙盒中運行,但不會超出沙盒的界限。例如,Applet不能讀取
8、或修改存儲在用戶系統(tǒng)上的文件。在某種情況下,即使用戶偶然引入了一個敵意的Applet,這個Applet也不能破壞用戶的系統(tǒng)。因此這種沙盒模式為移動代碼提供了一個受限的運行環(huán)境,在此環(huán)境中可以運行從開放網(wǎng)絡(luò)中獲得的不被完全信任的代碼(如Applet等)。 實現(xiàn)沙盒有兩種方法: (1) 插入對地址進行條件檢查的操作,如果地址非法則產(chǎn)生異常; (2) 簡單覆蓋對應(yīng)沙盒地址的高比特位。 第一種方法更適合調(diào)試,而第二種方法系統(tǒng)開銷小一些。 采用沙盒模式的主要缺點是可下載的代碼不再是與平臺無關(guān)的,而與操作平臺無關(guān)原本是Java系統(tǒng)的主要設(shè)計目標(biāo)之一。 3代碼驗證 第三種技術(shù)是一種稱為證明攜帶碼PCC(Pr
9、oof-Carrying Code)的技術(shù)4。采用這種技術(shù)時,移動代碼主機為Applet確定安全策略,然后以Edinburgh邏輯結(jié)構(gòu)(Logical Framework:用來發(fā)布安全策略和對證明進行編碼)對安全策略編碼并發(fā)布這個策略。Java Applet作者的任務(wù)不僅是把Applet編譯成機器代碼,還要產(chǎn)生一個安全證明(Safety Proof),用來證明這個代碼符合安全策略中指定的安全規(guī)則(Safety Rules)。 當(dāng)用戶下載代碼后,它只要驗證代碼中的證明,看是否合法并滿足安全規(guī)則就行。如果是則加載代碼并運行它。 這種方法是否有效的關(guān)鍵在于哪些程序特性可以用LF表示和證實。PCC已成
10、功應(yīng)用于最小和最大CPU周期限制、內(nèi)存的安全使用、網(wǎng)絡(luò)帶寬消耗以及類型安全中。此外,為C語言的安全子集開發(fā)了PCC編譯器,它可以自動生成安全證明。 PCC是一種很有前景的方法,但是,它也存在一些缺點:PCC與平臺有關(guān);LF編碼的安全策略和安全證明必須和操作系統(tǒng)以及機器硬件密切聯(lián)系。更多信息可以參考網(wǎng)站:/pcc.html。 13.2.2 惡意主機 在討論了惡意代碼問題之后,我們開始討論惡意主機問題。在移動代理編程中,用戶所關(guān)心的是其代理能否被正確執(zhí)行。如一個購物代理可能會攜帶電子現(xiàn)金,一個主機就可能會欺騙代理使它為某些商品支付高價錢,甚至竊取代
11、理內(nèi)的金錢。這都是用戶所要面對的安全問題。 主機為了執(zhí)行代理,需要訪問代理代碼和狀態(tài),那么如何保證敏感數(shù)據(jù)的機密性,或者說如何保證代理算法被忠實地執(zhí)行呢?Chess13等人認(rèn)為保護移動代理的限制有: (1) 要對代理代碼或狀態(tài)的任意部分保密,就必須采取加密; (2) 我們無法阻止拒絕服務(wù)攻擊,因為攻擊者不需要專門可信硬件的幫助就可以任意修改代理代碼或終止代理。 由此可見,要解決惡意主機問題就要從以下兩個方面著手: (1) 能夠檢驗篡改; (2) 能阻止機密信息泄漏。 1檢測篡改 我們無法采用技術(shù)途徑來使代理不受破壞,但是如果能明確地識別出惡意主機,那么法律的、社會的威脅就可能阻止惡意主機的操作
12、員破壞代理。識別惡意主機還可能使代理的所有者因代理的損失而獲得某種程度的補償。 下面將介紹檢測惡意主機的技術(shù),這些技術(shù)都是基于公開密鑰基礎(chǔ)設(shè)施的,它們允許用戶、主機和代理之間相互認(rèn)證。這些技術(shù)主要是要證明一個主機確實是惡意主機,因此,采用數(shù)字簽名非常重要。 (1) 執(zhí)行跟蹤??梢酝ㄟ^產(chǎn)生代理程序執(zhí)行跡的方法來檢測篡改。首先,將代理代碼的指令分成兩類:只依賴于代理內(nèi)部狀態(tài)的指令以及其結(jié)果依賴于和計算環(huán)境交互的指令。對于前一類指令,服務(wù)器只有在代理的任一變量的值發(fā)生變化時,才在執(zhí)行跡中記錄其新值;對于后一類指令,不但要記錄這些新值,還需要對這些值進行數(shù)字簽名。 一旦執(zhí)行完畢,服務(wù)器就計算整個執(zhí)行跡
13、的密碼散列值并將它返回給代理的所有者。這時,如果代理所有者懷疑在執(zhí)行代理時有違規(guī)操作,它就可以要求出示執(zhí)行跡,那么主機執(zhí)行代理時就必須生成執(zhí)行跡(執(zhí)行跡的散列值可被驗證),然后檢驗執(zhí)行跡就可確定: 主機是否錯誤地執(zhí)行了只依賴于內(nèi)部狀態(tài)的指令; 主機執(zhí)行代理過程中,在與計算環(huán)境交互時是否欺騙了代理。 這種方法在實際的操作中存在兩個問題: (a) 這種方法在主機違規(guī)操作時不會向代理所有者發(fā)出警報,而只有在所有者懷疑時提供一種可驗證的識別方法; (b) 在需要生成執(zhí)行跡時,服務(wù)器需要保存所有的執(zhí)行跡,這就給服務(wù)器帶來了非常高的負(fù)擔(dān)。 (2) 認(rèn)證部分結(jié)果。Yee4提出了兩種檢測惡意主機篡改代理的方法
14、。第一種方法是采用部分結(jié)果認(rèn)證碼(PRAC),發(fā)送代理的同時發(fā)送一組密鑰k1、k2、kn。在第i個服務(wù)器,代理使用密鑰ki對其執(zhí)行結(jié)果進行簽名并由此產(chǎn)生PARC;在轉(zhuǎn)移到下一個服務(wù)器之前,代理把ki從狀態(tài)中刪除。這樣,一個惡意主機就不能偽造來自前一個服務(wù)器的部分結(jié)果,最糟糕的情況也僅僅是把這些部分結(jié)果從代理中移除。 PRACs允許代理所有者(同時擁有k1、k2、kn)自動地對返回代理中包含的每一部分結(jié)果進行密碼驗證。這些消息可以保證非常好的前向完整性:設(shè)移動代理訪問一系列的服務(wù)器S=s1、s2、sn,而第一個惡意服務(wù)器為sc,則對于ic,服務(wù)器si的部分結(jié)果不是偽造的。 當(dāng)服務(wù)器僅僅通過與正在
15、運行的代理進行欺詐性的交互實現(xiàn)篡改時,上述方案就無法自動檢測到。此外,只有在代理所有者懷疑主機時才會產(chǎn)生PRAC所有的PRAC都是密碼有效的,但有些可能在語義上無效。 Yee提出了一種投機的方法來檢測語義上的篡改。對于程序x,設(shè)y為x的執(zhí)行跡。主機執(zhí)行完代理后把y發(fā)送給代理所有者,由所有者驗證y。由于執(zhí)行跡可能會很大,因此傳輸它的帶寬開銷會非常大。從而,主機把y編碼成全息樣片y。樣片y具有如下特性:代理所有者只需要檢查y某些位就能確信其正確與否。這樣,服務(wù)器就可以采用哈希樹的方案將樣片散列成一個小的根值,然后把根值返回給代理所有者,由所有者判斷y是否正確。這種方法的主要缺點是服務(wù)器的負(fù)荷問題。
16、構(gòu)造全息樣片y是一個全NP問題(不存在多項式時間算法解的一類問題,全NP問題則是最為困難的一類),在執(zhí)行跡y大到很難傳輸?shù)酱硭姓邥r,構(gòu)造y是不能實現(xiàn)的。 2保密 在有些情況下,事后檢測是不適當(dāng)?shù)幕蚴遣荒芙鉀Q問題的。如有時候采用法律行動的代價比篡改帶來的經(jīng)濟損失更大;有些時候,代理發(fā)送數(shù)字簽名,但由于某些原因其私鑰已被泄漏。為此,Sander和Tschudin13提出了一種理論上的方案以允許代理對惡意主機保留一些機密。 方案的本質(zhì)是這樣的:代理程序計算某個函數(shù)f,主機為代理計算f(x)但不需要知道f的任何實質(zhì)性的內(nèi)容。協(xié)議描述如下: (1) 代理所有者加密f; (2) 所有者創(chuàng)建程序P(E(
17、f)來實現(xiàn)E(f),并把它放在代理中; (3) 代理到達遠程主機,在遠程主機上計算P(E(f)(x),并把值返回給所有者; (4) 所有者解密P(E(f)(x)并獲得f(x)。 其中,E為某個加密函數(shù)。協(xié)議的基本思想是把基本算法轉(zhuǎn)化成雜亂算法,使其結(jié)果只對代理所有者有意義。 3總結(jié) 相比惡意代碼而言,惡意主機問題更難以處理,目前還沒有實際的、在計算上可行的方法用來檢測篡改,而一些可以用來證明發(fā)生了篡改的技術(shù)也會大大增加服務(wù)器的負(fù)荷。此外,在一個不友好的環(huán)境中運行代理時,有沒有可能為代理提供某種類型的機密性還是一個未知數(shù)。這些問題的存在或許可以解釋移動代理為什么得不到廣泛應(yīng)用。13.3 Java
18、 安 全 13.3.1 Java綜述 Java語言是Sun Microsystems公司開發(fā)的。在Sun Microsystems公司提供的技術(shù)報告5中稱:“Java是一種簡單的、面向?qū)ο蟮?、適合網(wǎng)絡(luò)編程的、解釋的、健壯的、安全的、與結(jié)構(gòu)無關(guān)的、可移植的、高性能的、多線程的動態(tài)語言?!?簡單:Java是一種易于使用的編程語言,其簡單性體現(xiàn)在以下幾個方面: (1) 它和C+類似(C+程序員可以很快掌握J(rèn)ava編程技術(shù)); (2) 它摒棄了C+中許多很少用、很難理解和容易混淆的特性,如操作符重載等; (3) Java實現(xiàn)了自動垃圾收集,從而簡化了Java編程。在C和C+中,一個復(fù)雜的操作是內(nèi)存管理
19、:內(nèi)存分配和內(nèi)存釋放。通過自動垃圾收集(周期性的釋放沒有被引用的內(nèi)存)不但可以使編程簡單化,還可大大地減少程序中的bug; (4) Java程序很小,易于通過網(wǎng)絡(luò)下載。 面向?qū)ο螅汉虲+一樣,Java是一種面向?qū)ο蟮木幊陶Z言。 適合網(wǎng)絡(luò)編程:Java擁有廣泛的、能輕易處理TCP/IP協(xié)議的運行庫,因此相比C和C+而言,Java更容易創(chuàng)建網(wǎng)絡(luò)連接。Java應(yīng)用程序通過URL打開和訪問網(wǎng)絡(luò)上的對象與編程人員訪問本地文件系統(tǒng)一樣簡單。 健壯性:Java能檢查程序在編譯和運行時的錯誤。類型檢查可以檢查出許多開發(fā)早期出現(xiàn)的錯誤;Java沒有采用C+中的指針?biāo)惴ǘ鴮崿F(xiàn)了真數(shù)組,從而避免了覆蓋內(nèi)存和破壞數(shù)據(jù)
20、的可能。 安全:設(shè)計Java是為了用于分布式網(wǎng)絡(luò)環(huán)境,因此安全在這里就顯得非常重要。本節(jié)的后續(xù)內(nèi)容將詳細(xì)介紹Java的安全實現(xiàn)以及其潛在的安全威脅。 與結(jié)構(gòu)無關(guān):Java程序是在網(wǎng)絡(luò)上傳播和應(yīng)用的,而網(wǎng)絡(luò)上的不同主機的CPU、操作系統(tǒng)結(jié)構(gòu)等等都不盡相同,為了使Java應(yīng)用程序能在網(wǎng)絡(luò)上的任何一臺主機上運行,編譯器必須產(chǎn)生一個與結(jié)構(gòu)無關(guān)的文件格式只要處理器上有Java虛擬機系統(tǒng),此文件格式的代碼就可以在此處理器上運行。Java的做法是讓編譯器生成與特定計算機體系結(jié)構(gòu)無關(guān)的字節(jié)碼指令,這些字節(jié)碼指令在任何機器上都很容易解釋,并能很容易地翻譯成本機機器代碼。 可移植:與體系結(jié)構(gòu)無關(guān)的特性使得Java
21、應(yīng)用程序可以在配備了Java解釋器和運行環(huán)境的任何計算機系統(tǒng)上運行,這為Java應(yīng)用程序便于移植打下了良好基礎(chǔ)。但僅僅如此還不夠,不同操作系統(tǒng)基本數(shù)據(jù)類型的設(shè)計實現(xiàn)是不同的,如在Windows 3.1中整數(shù)(int)為16位,在Windows 95中為32位,而在DEC Alpha中卻為64位。這不利于代碼的移植。為此,Java定義了獨立于平臺的基本數(shù)據(jù)類型及其運算,從而使得Java數(shù)據(jù)在任何硬件平臺上都是一致的。其次,Java編譯器本身是用Java語言編寫的,而運算系統(tǒng)是用ANSI C語言寫的。總之,在Java語言規(guī)范中沒有任何與具體實現(xiàn)相關(guān)的內(nèi)容。 解釋:Java是一種解釋性語言,其解釋器
22、可以將Java字節(jié)碼翻譯成本地機器指令并運行,而不需要存儲字節(jié)碼。 高性能:由于解釋字節(jié)碼的性能一般都是比較高的,從而Java可以在運行時直接將字節(jié)碼翻譯成機器指令。Sun Microsystems的SPARCStation 10在翻譯代碼時,可以在每秒鐘內(nèi)調(diào)用300 000個方法,這和直接生成機器目標(biāo)代碼C/C+的性能不相上下。 多線程:Java提供了一個內(nèi)建的機制來提供對多個并發(fā)子任務(wù)的支持。 動態(tài):在C+程序設(shè)計過程中,每當(dāng)在類中增加一個實例變量或一種成員函數(shù)后,引用該類的所有子類都必須重新編譯,否則將導(dǎo)致程序崩潰,而Java是一種動態(tài)語言,它不是把所有的類靜態(tài)地編譯成機器碼,而是由程序
23、動態(tài)地裝入運行過程中所需要的類。 13.3.2 Java底層安全性實現(xiàn) 1. 底層安全 Java解釋器通過以下幾種方式實現(xiàn)底層安全: 1) 通過發(fā)布源代碼獲得安全 如果需要,Java解釋器和編譯器均可獲得完整的源代碼。對Java源代碼可以執(zhí)行安全審計。 2) 通過明確定義獲得安全 Java語言的定義非常嚴(yán)格: 保證所有的基本類型使用指定的長度; 所有的操作必須按指定的順序執(zhí)行。 明確的定義可以保證兩個(正確的)Java編譯器執(zhí)行同一個程序不會得到兩個不同的結(jié)果。 3) 通過摒棄指針獲得安全 Java摒棄了C語言中的指針?biāo)惴?,因此編程人員無法偽造指針來訪問內(nèi)存。對類文件中所有方法和實例變量的引用
24、都是通過符號名來實現(xiàn)的,這就可以避免在C語言中利用指針非法訪問內(nèi)存而提升權(quán)限一類的攻擊,如緩沖區(qū)溢出等。 4) 通過垃圾收集獲得安全 在C/C+中,編程人員經(jīng)常面對的問題是內(nèi)存分配和釋放。當(dāng)釋放內(nèi)存不當(dāng),如沒有釋放不再使用的內(nèi)存或兩次釋放同一內(nèi)存區(qū)會導(dǎo)致安全問題。Java通過自動垃圾收集(周期性地釋放沒有被引用的內(nèi)存)來避免這些問題。 5) 通過在編譯時的嚴(yán)格檢查獲得安全 Java編譯器在編譯時要進行詳盡的、嚴(yán)格的檢查以盡可能地檢測編程中的錯誤。Java語言是強類型的: 在運行期,如果不進行明確的檢查不能把對象分配給某個子類; 要檢查所有對方法和變量的引用以確保對象具有合適的類型。 整數(shù)不能轉(zhuǎn)
25、換為對象,對象也不能轉(zhuǎn)換為整數(shù)。 編譯器還要確保程序沒有訪問未初始化的本地變量。 2. 類文件驗證 雖然編譯器可對類型進行詳盡的檢查,但攻擊者仍然可能通過使用專門的編譯器實現(xiàn)攻擊。如HotJava瀏覽器是下載已經(jīng)編譯好的類文件,它無法確定下載的字節(jié)碼是由可信的Java編譯器編譯的還是由某個有惡意企圖的編譯器編譯的。 在編譯時實現(xiàn)對類型的檢查還存在版本不一致的問題。如用戶編譯好了一個類,假設(shè) PurchaseStockOptions是TradingClass的一個子類。但是在類編譯完后,TradingClass的定義可能會發(fā)生變化:某個方法不用了或方法的參數(shù)改變了;變量類型變了。而且,方法或變量
26、也可能從公有變成私有。 為此,所有外來的類文件都需要經(jīng)過一個驗證器,由驗證器確保類文件具有正確的格式。 字節(jié)碼驗證器同樣可以增強解釋器的性能。利用字節(jié)碼驗證,解釋器就不用對每一條解釋的指令進行檢查,而會認(rèn)為這些檢查都已經(jīng)在此之前完成了。如解釋器能肯定代碼遵守以下限制: 代碼中不存在緩沖區(qū)溢出; 所有的寄存器訪問和存儲都是合法的; 所有字節(jié)碼的參數(shù)都是正確的; 不存在非法的數(shù)據(jù)轉(zhuǎn)換。 驗證器獨立于Java編譯器,它使用戶可以放心的從防火墻之外下載Java代碼。 下面詳細(xì)介紹驗證器的驗證過程,其中提到的類文件格式的具體細(xì)節(jié)可參考參考資料5: (1) 驗證的第一步發(fā)生在將類讀入解釋器時。這一步要確保
27、類文件具有類文件的格式:開始的幾個字節(jié)必須包含正確的魔幻數(shù);所有可驗證的屬性都具有正確的長度;類文件的末尾不能被截斷,也不能添加額外的字節(jié);常數(shù)存儲庫不能包含不可識別的信息。 (2) 第二步更進一步驗證類文件的格式: 確保final類沒有被繼承,final方法沒有被覆蓋; 每個類必須有一個超類; 確保常數(shù)存儲庫滿足一定的限制,如其中的類引用必須包含一個指向存儲庫中的一個unicode字符串引用的域。 常數(shù)存儲庫中所有的域引用和方法引用都必須有合法的名字、合法的類和合法的類型簽名。(3) 這一步是類驗證中最復(fù)雜的一步,在這一步中需要驗證每一個方法的字節(jié)碼。這一步要保證: 堆棧的大小和它包含的對象
28、類型保持不變; 除非已知包含了一個適當(dāng)類型的值,否則不能訪問寄存器; 以適當(dāng)?shù)膮?shù)調(diào)用方法; 以適當(dāng)類型的值修改域; 所有的操作碼在堆棧和寄存器中具有適當(dāng)類型的參數(shù)。在“字節(jié)碼驗證”中我們將進一步描述這一步的細(xì)節(jié)。 (4) 在第三步中,除非有必要,否則不會裝載類文件。如一個方法調(diào)用另一個返回foobarType類型對象的方法時,如果立即把同一類型的域分配給返回的對象,驗證器就不會驗證foobarType類型是否存在;如果把anotherType類型的域分配給返回的對象,則必須裝載foobarType和anotherType的定義以確保foobarType是anotherType的一個子類。 引
29、用類的指令第一次執(zhí)行時,驗證器需: 如果還沒有裝載這個類則裝載; 驗證當(dāng)前正在執(zhí)行的類是否被允許引用給定的類。 指令第一次調(diào)用方法或訪問、修改域時,驗證器需: 確保方法或域存在于給定的類中; 檢查方法或域是否具有要求的簽名; 檢查當(dāng)前正在執(zhí)行的方法是否有權(quán)訪問給定的方法或域。 這一步中,驗證器不需要檢查堆棧中對象的類型,因為在第三步中已經(jīng)執(zhí)行了這項檢查。 在執(zhí)行完驗證后,字節(jié)碼流中的指令就會被另一種形式的指令所代替。如操作碼new被new_quick代替。這個替換的指令表示已經(jīng)執(zhí)行了對這個指令的驗證,不需要再次驗證了。 3字節(jié)碼驗證 類文件驗證的第三步是字節(jié)碼驗證,這是類文件驗證過程中最復(fù)雜的
30、一步。首先,把組成虛指令的字節(jié)分成一系列的指令,每一個指令開始位置的偏移量保存在一個位表中。然后,驗證器再次掃描這些字節(jié)并解析指令。這一步中把每個指令轉(zhuǎn)換成一個結(jié)構(gòu)。檢查每個指令的參數(shù)(如果有的話)以確保它們是合理的: 所有的流程控制指令必須到達一個指令的開始,不允許有到達指令內(nèi)部的分支。類似的,不允許出現(xiàn)到達代碼開始前或代碼結(jié)束后的分支。 所有的寄存器引用必須是引用合法的寄存器。除方法指明的所能用的寄存器外,代碼不能訪問和修改任何其它的寄存器。 所有對常數(shù)存儲庫的引用必須是引用適當(dāng)類型的條目。如操作碼ldc1只能用于整數(shù)、浮點數(shù)或string類型,而操作碼getfield必須引用一個域。 代
31、碼不能在某個指令中間結(jié)束。 對每一個異常處理程序,其起始點和結(jié)束點都必須指向一個指令的開始。異常處理器的偏移必須是合法的指令;起始點必須在結(jié)束點之前。 對每一條指令,在執(zhí)行之前,驗證器要跟蹤堆棧和寄存器的內(nèi)容。對于堆棧,需要知道堆棧的長度和堆棧中元素的類型;對于寄存器,需要知道寄存器內(nèi)容的類型或寄存器內(nèi)的值是合法的。在確定堆棧中值的類型時,字節(jié)碼驗證器不需要區(qū)分不同的整數(shù)類型(如byte、short和char)。 接下來初始化數(shù)據(jù)流分析器。對于第一條指令,編號較小的寄存器包含方法類型簽名所指示的類型;堆棧為空;所有其它的寄存器包含非法值;對于其它指令,指示該指令沒有被訪問,還沒有其堆棧或寄存器
32、的信息。 最后,運行數(shù)據(jù)流分析器。對每一條指令都有一個“changed”位來表示這個指令是否需要查看。最初只有第一條指令設(shè)置了“changed”位。數(shù)據(jù)流分析器執(zhí)行如下循環(huán): (1) 找到一個設(shè)置了“changed”位的虛擬機器指令,如果沒有找到,則表示該方法已被驗證。清“changed”位。 (2) 仿真指令對堆棧和寄存器的影響: 如果指令要使用來自堆棧的值,需確保堆棧中有足夠的元素,并且堆棧頂端元素具有適當(dāng)?shù)念愋停駝t,驗證失敗。 如果指令使用了寄存器,需確保指定的寄存器包含了適當(dāng)類型的值,否則,驗證失敗。 如果指令要把值壓入堆棧,往堆棧頂端加入指示的類型,需確保堆棧有足夠的空間存放新元素
33、。 如果指令需要修改寄存器,需說明寄存器當(dāng)前包含了新的類型。 (3) 確定跟隨在當(dāng)前指令后面的虛擬機器指令。后續(xù)指令可能是: 如果當(dāng)前指令不是無條件goto、return或throw,則為下一條指令;如果可以離開最后一條指令,則這一步失敗。 有條件或無條件轉(zhuǎn)移的目標(biāo)。 當(dāng)前指令所有的異常處理程序。 (4) 在當(dāng)前指令的末尾,把堆棧和寄存器的狀態(tài)合并到下一條指令中。在異常處理的情況下,需要更改堆棧使得堆棧包含一個單一的對象,其異常類型由異常處理器信息指明。 如果下一條指令是第一次訪問,則在執(zhí)行下一條指令之前指明:由第(2)步和第(3)步計算得到的堆棧和寄存器的值是堆棧和寄存器的狀態(tài);設(shè)置下一條指
34、令的“changed”位。 如果指令以前訪問過,則把第(2)步和第(3)步計算得到的堆棧和寄存器的值合并到已有的值中;如果有改動則設(shè)置“changed”位。 (5) 回到第(1)步。 字節(jié)流分析器對某些指令和數(shù)據(jù)類型,如長整數(shù)、構(gòu)建函數(shù)、異常處理程序、Try/Finally等的具體驗證過程可參考參考資料6。 13.3.3 Java的沙盒模型 傳統(tǒng)的操作系統(tǒng)允許應(yīng)用程序?qū)C器有完全的訪問,因此不能信任運行環(huán)境。為此,安全策略一般要求在運行一個程序之前,需要在某種程度上信任程序。如在運行從Web上下載的程序之前,安全策略要求對程序進行病毒檢查以及檢查源代碼以發(fā)現(xiàn)惡意代碼。這種方法存在兩個問題: (
35、1) 建立對應(yīng)用程序信任的檢查在實際操作中非常復(fù)雜,且非常費時間。一般人們不會花時間去研讀源代碼以發(fā)現(xiàn)隱藏在其中的惡意行為。 (2) 要使病毒檢查有效,需要及時地維護:病毒庫要及時更新、掃描程序要安裝在每一臺計算機上等等。 Java采用了一種新的方法:沙盒。Java把Applet的所有操作都嚴(yán)格限制在一個稱之為“沙盒”(一個由Web瀏覽器專門為這個Applet分配的地址空間)的區(qū)域內(nèi)。Applet在其沙盒內(nèi)可以做任何事,但超出此邊界就不能有任何操作。沙盒模型實現(xiàn)了在一個信任環(huán)境中運行不信任的代碼的功能。這樣,即使用戶運行了一個惡意的Applet,也不會給用戶帶來什么損失。沙盒由幾個不同的系統(tǒng)操
36、作組成,下面將逐一介紹。 1類裝載程序ClassLoader Java運行時有兩種不同的方式來裝載一個新的類。其默認(rèn)機制是從本地機器上的文件中裝載一個類,這種機制不需要類裝載程序ClassLoader。另一種方式是通過網(wǎng)絡(luò)等裝載一個類,這時需要一個相關(guān)的類裝載程序ClassLoader,由ClassLoader負(fù)責(zé)將類的原始數(shù)據(jù)(如網(wǎng)絡(luò)上傳輸?shù)淖止?jié))轉(zhuǎn)化成表示那個類的內(nèi)部數(shù)據(jù)結(jié)構(gòu)。 類裝載程序除了要完成從網(wǎng)絡(luò)上獲得一個Applet的可執(zhí)行代碼外,還實施了命名空間的體系結(jié)構(gòu)。一個命名空間規(guī)定了一個Applet能訪問JVM(Java虛擬機)的其它哪些部分。通過為本地磁盤上的可信任代碼維護一個單獨的
37、命名空間,類裝載程序可以防止不可信的Applet獲得對系統(tǒng)可信部分(往往需要更多特權(quán)才能訪問)的訪問權(quán)。 從網(wǎng)絡(luò)上下載的Applet不能創(chuàng)建其自己的類裝載程序,也不能調(diào)用系統(tǒng)類裝載程序中的方法。 2驗證器 在運行一個新下載的Applet之前,類裝載程序要調(diào)用驗證器進行類文件驗證。 3安全管理器 安全管理器增強沙盒的邊界。在Applet試圖執(zhí)行可能導(dǎo)致本地機器崩潰或訪問信息的操作時,JVM首先向安全管理器詢問此操作是否可以安全地執(zhí)行。只有安全管理器準(zhǔn)許了這項操作,虛擬機才能執(zhí)行,否則,虛擬機將產(chǎn)生一個安全異常并向Java控制臺寫出錯信息。下面列舉了安全管理器禁止不可信Applet執(zhí)行的部分操作:
38、 對本地文件的讀寫; 刪除文件; 執(zhí)行操作系統(tǒng)命令或本地代碼; 載入一個直接調(diào)用本地方法的新的動態(tài)庫; 與不是此Applet源主機的機器建立連接; 建立一個新的進程。 一個應(yīng)用程序或Web瀏覽器只能有一個安全管理器,這可保證所有的訪問檢查都是由一個執(zhí)行單一安全策略的安全管理器來完成的。安全管理器在啟動時載入,它不能被擴展、重載或替代。顯然,Applet不能創(chuàng)建其自身的安全管理器。 4語言特性 在Java底層安全性實現(xiàn)一節(jié)中,我們可以看出,Java具有許多可以保護安全系統(tǒng)完整性,并防止某些常見攻擊的特性。 13.3.4 擴展Java安全 Java沙盒模型可以保護終端用戶機器和網(wǎng)絡(luò)計算資源不受惡意
39、Applet的破壞和進行信息竊取,從而用戶可以運行來自網(wǎng)絡(luò)上的不可信代碼而不會有安全風(fēng)險。但是沙盒模型沒有涉及其它的一些安全和保密性問題: 認(rèn)證可以幫助確認(rèn)一個Applet確實來自其聲明的主機; 數(shù)字簽名和認(rèn)證過的Applet可以提升為可信Applet,從而可以在較少的安全限制前提下運行; 加密可以保證Applet客戶端和Internet上服務(wù)器之間傳輸數(shù)據(jù)的機密性。 1簽署JAR文件 所有的網(wǎng)絡(luò)化系統(tǒng)都容易受到潛在的中間人攻擊。在這種攻擊中,客戶端與網(wǎng)絡(luò)上的合法服務(wù)器進行連接并請求某種操作;而攻擊者,即這里所說的中間人竊聽到這些請求后就等待服務(wù)器的響應(yīng),然后截獲響應(yīng)并向客戶端發(fā)送一個偽造的應(yīng)
40、答;這時客戶端就會根據(jù)這些偽造的信息進行某種操作,或者運行攻擊者提供的程序而使攻擊者獲得對機器的訪問權(quán)。如攻擊者可觀察一個基于Internet的銀行站點;當(dāng)客戶端訪問其提供付款服務(wù)的頁面時,攻擊者就可以截獲銀行的響應(yīng),而把一個可以模仿銀行服務(wù)并可竊取用戶信用卡副本和銀行賬號的惡意Applet作為響應(yīng)發(fā)送給客戶。 通過對Applet使用“數(shù)字簽名”可以阻止這種攻擊。首先,把所有Java代碼和相關(guān)文件捆綁成一個Java檔案(JAR);然后根據(jù)JAR的內(nèi)容利用數(shù)字簽名算法產(chǎn)生一個用字符串表示的數(shù)字簽名。通過驗證其數(shù)字簽名就可以確定這個JAR的來源,從而有效地防止了中間人攻擊。 JAR文件從某種程度上
41、還可幫助解決另外一個問題。目前,許多Java Applet需要很長時間才能下載下來。這和當(dāng)前的Internet協(xié)議有關(guān)。 目前的Internet協(xié)議每次只請求和傳送一個文件,每請求一個文件需要一定的開銷,而一個頁面和Java Applet一般都由許多小文件組成,從而可能使得請求文件和等待響應(yīng)的時間比真正傳輸信息的時間還要長。采用JAR文件后,把Applet和Web頁所需要的所有信息捆綁成一個文件,從而請求整個頁面就只需要一個請求。對于大部分的頁面,這可大大減少下載時間。 2靈活的策略 數(shù)字簽名可以賦予Java Applet某種可信度,從而可以放寬對某些Applet的Java安全限制。如上面提到
42、的家庭銀行Applet,如果采用了數(shù)字簽名,它就可以在用戶硬盤上建立自己目錄以存儲賬號、信用卡號、口令、個人身份號碼PIN和其它經(jīng)常要用的信息,這時的終端用戶不必經(jīng)常性地重輸這些信息。 數(shù)字簽名過的Applet可以創(chuàng)建自己的環(huán)境。如果終端用戶已提前指示Java系統(tǒng)某個特定的Web發(fā)布者是可信的,而且某個來自此Web發(fā)布者并簽名了的Applet被驗證通過,則Java安全管理器就可允許這個Applet的操作超出其沙盒的范圍,也就是說,把這個Applet看成一個普通的應(yīng)用程序。 安全管理器還可以根據(jù)對特定Web發(fā)布者的信任程度或?qū)φ麄€Internet的信任程度而執(zhí)行不同的控制策略。如一個安全意識很強
43、的用戶可能將系統(tǒng)配置成簽名了的Applet只能在沙盒范圍內(nèi)執(zhí)行;未簽名的Applet根本就不允許執(zhí)行。另外一個用戶可能將系統(tǒng)配置成銀行Applet只能訪問硬盤上的某個特定目錄,而一個網(wǎng)絡(luò)游戲Applet可以訪問另外一個目錄,同時所有其它的Applet只能在沙盒的范圍內(nèi)執(zhí)行。 3審計 審計是另一個重要的安全要素。審計軟件將維護系統(tǒng)上發(fā)生的每一件事的記錄。當(dāng)出現(xiàn)錯誤時(無論是偶然還是由于bug,或者是由于攻擊造成的),系統(tǒng)管理員和安全人員就可以根據(jù)審計跡推測出所發(fā)生的事,從而可以幫助他們確定如何防止錯誤的再次發(fā)生。雖然審計不能阻止事故和攻擊,但在錯誤發(fā)生后,它是把事情弄清楚的重要工具。 目前版本的
44、Java審計功能很有限,還沒有管理員可以依賴的審計能力,而且其記錄的特征很不詳細(xì)。 4加密 雖然沙盒模型和對Applet的數(shù)字簽名可以阻止惡意Applet的破壞和中間人攻擊,但在Internet上,Applet和服務(wù)器之間的信息傳輸仍然易遭到竊聽。這是因為Internet本身就是一個不安全的傳輸煤質(zhì)。攻擊者在Internet的關(guān)鍵點可以獲得經(jīng)過該關(guān)鍵點的所有的信息。由此,攻擊者可以偵聽出入一個銀行的所有流量,也可以只獲取通過的信用卡號和其它一些信息。為了防止這種攻擊,我們需要對Applet和服務(wù)器之間的所有流量進行加密,從而使它不可讀。 13.3.5 Java安全開發(fā)建議 雖然Sun聲稱Jav
45、a是一種安全語言,而且Java也采用了一些安全結(jié)構(gòu)以及內(nèi)建了一些安全特性,但是Java仍無法避免安全問題,其應(yīng)用程序中仍存在大量的安全漏洞和隱患。為了使用Java開發(fā)安全的程序,可參考以下建議101112。 1) 限制對類、方法和變量的訪問 把類、方法和變量聲明為公有會給攻擊者提供潛在的入口。為此:(a) 不要使用公共域或變量,把它們聲明為私有的,并提供訪問函數(shù)以限制對它們的訪問;(b) 除非有很好的理由,否則把方法都設(shè)為私有的(如果確實沒這樣做,說清楚其理由)。非私有的方法可能會接收受污染的數(shù)據(jù),因此必須保護這些方法(除非已經(jīng)用其它方式對它們進行了保護)。 2) 避免使用靜態(tài)域變量 靜態(tài)域變
46、量是附著在類而非類的實例上,而類可以被其它類所定位,其結(jié)果就是可以通過其它類找到靜態(tài)域變量,這就很難保證它們的安全。 3) 永遠不要把可變對象返回給潛在的有惡意代碼(因為代碼可能會改變它) 注意,數(shù)組是可變的(即使數(shù)組的內(nèi)容不可變),所以不要返回一個含有敏感數(shù)據(jù)的內(nèi)部數(shù)組的引用。 4) 永遠不要直接保存用戶給定的可變對象(包括對象的數(shù)組) 如果直接保存用戶給定的可變對象,用戶可以把對象交給安全代碼,讓安全代碼“檢查”對象,并在安全代碼試圖使用數(shù)據(jù)時改變數(shù)據(jù)。應(yīng)該在內(nèi)部存儲數(shù)組前復(fù)制它們,而且要小心(例如,警惕用戶編寫的復(fù)制例程)。 5) 不要依賴于初始化 許多Java開發(fā)人員認(rèn)為如果不運行構(gòu)建
47、器就無法為一個對象分配內(nèi)存,這是不對的,事實上有許多方法可以為未初始化的對象分配內(nèi)存。避免這個問題的一個簡單方法就是書寫自己的類,從而在對象進行某項操作前驗證對象。其做法為 使所有的變量為私有。如果要允許外部代碼訪問一個對象內(nèi)的變量,可以通過set和get方法來實現(xiàn)(這就使外部代碼不能訪問未初始化的對象)。 為每一個對象添加一個新的私有布爾變量initialized。 在返回之前讓每一個構(gòu)建器設(shè)置初始化的變量作為最后一個操作。 在進行進一步操作之前,讓每一個nonconstructor方法驗證initialized為真。 如果自己書寫的類具有靜態(tài)的初始化程序,則需要在類的層次做同樣的操作。也就
48、是說,對于任何一個具有靜態(tài)初始化程序的類,需要: 使所有的靜態(tài)變量私有。如果要允許外部代碼訪問類中的靜態(tài)變量,可以通過靜態(tài)set和get方法來實現(xiàn)(這就使外部代碼不能訪問未初始化的靜態(tài)變量)。 為類添加一個新的私有靜態(tài)布爾變量classInitialized。 在返回之前讓靜態(tài)構(gòu)建器設(shè)置初始化的變量作為最后一步操作。 在進行進一步操作之前,讓每一個靜態(tài)方法和每一個構(gòu)建器驗證classInitialized為真。 6) 除非有很好的理由,否則使每件事都final(終結(jié)) 如果某個類或方法不是final的,攻擊者就可以用某種危險且無法預(yù)知的方法來擴展它。注意,作為安全性的交換,這會帶來可擴展性的喪
49、失。 7) 不要在安全性上依賴包的范圍 在同一個包內(nèi)可以訪問沒有明確標(biāo)記為public、private或protected的類、方法和變量。Java類不是關(guān)閉的,因此,攻擊者可以向包中引入一個新類,并用此新類來訪問用戶以為保護了的信息。(某些類,如java.lang,缺省是關(guān)閉的,而且某些Java虛擬機(JVM)會讓用戶關(guān)閉其它包,但最好假設(shè)包不是關(guān)閉的。) 8) 不要使用內(nèi)部類 有些Java語言的書上稱只有封裝內(nèi)部類的類才可以訪問被封裝的內(nèi)部類,這是不正確的,因為Java字節(jié)碼沒有內(nèi)部類的概念,在內(nèi)部類轉(zhuǎn)換為字節(jié)代碼時,會被轉(zhuǎn)換為這個包中任意代碼可以訪問的類。更糟的是,被封裝類的私有域會靜悄
50、悄地變成非私有的,從而允許內(nèi)部類訪問! 9) 最小化特權(quán)和避免標(biāo)記代碼 運行沒有標(biāo)記的代碼不需要任何專門的特權(quán)。沒有專門特權(quán)的代碼不會帶來什么危害,為此應(yīng)避免標(biāo)記代碼。但是有時代碼需要獲得和使用特權(quán)以執(zhí)行某種危險的操作,此時應(yīng)使代碼特權(quán)最小化,同時應(yīng)更仔細(xì)地審閱特權(quán)代碼。 10) 如果一定要標(biāo)記代碼,應(yīng)該把它們都放在一個檔案文件里 此規(guī)則的目的是防止攻擊者使用混合匹配攻擊。在混合匹配攻擊中,攻擊者構(gòu)建新Applet或庫,把某些標(biāo)記類與有惡意的類連接在一起,或把根本意識不到會被一起使用的標(biāo)記類連接在一起。通過把一組類標(biāo)記在一起,就可以使這種攻擊更高明。現(xiàn)有的代碼標(biāo)記系統(tǒng)在防止混合匹配攻擊上做得還不夠,所以這一規(guī)則還不能完全防止此類攻擊。但使用單個檔案沒什么壞處。 11) 使類不可被復(fù)制 Java的類復(fù)制機制允許攻擊者不運行構(gòu)建函數(shù)就實例化某個類。只要在每個類里定義如下方法就可使類不可被復(fù)制: public final void c
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 二零二五年度高端辦公室文件消毒及深度保養(yǎng)合同
- 租賃期間房屋買賣合同
- 公司之間的借款協(xié)議
- 出租車停運損失上訴狀
- 電器代理合同協(xié)議
- 財務(wù)管理系統(tǒng)操作與應(yīng)用手冊指南
- 農(nóng)業(yè)科技行業(yè)現(xiàn)代農(nóng)業(yè)技術(shù)推廣與應(yīng)用策略
- 廣告招牌安裝合同年
- 辦公室租賃合同書
- 安全事故賠償協(xié)議書
- 110kV變電站專項電氣試驗及調(diào)試方案
- 2024年廣西桂盛金融信息科技服務(wù)有限公司招聘筆試沖刺題(帶答案解析)
- 外賣星級(商家評分)計算表
- DZ∕T 0215-2020 礦產(chǎn)地質(zhì)勘查規(guī)范 煤(正式版)
- 外出檢查病人突發(fā)呼吸心跳驟停應(yīng)急預(yù)案演練
- 《火力發(fā)電廠汽水管道設(shè)計規(guī)范+DLT+5054-2016》詳細(xì)解讀
- 幕墻施工成品及半成品保護措施
- 基于單片機的交通燈控制系統(tǒng)設(shè)計畢業(yè)論文
- 2024年執(zhí)業(yè)醫(yī)師考試-醫(yī)師定期考核(口腔)筆試參考題庫含答案
- 中國律師學(xué) 課件 陳衛(wèi)東 第10-17章 律師收費制度-律師非訴訟業(yè)務(wù)(二)
- 中國移動行測測評題及答案
評論
0/150
提交評論