新聞中心
好長時(shí)間沒有更新了,今天更新一篇關(guān)于java反射機(jī)制的文章,初學(xué)Java安全,內(nèi)容如有不恰當(dāng)?shù)牡胤剑€請(qǐng)各位大佬指正。

在梅里斯等地區(qū),都構(gòu)建了全面的區(qū)域性戰(zhàn)略布局,加強(qiáng)發(fā)展的系統(tǒng)性、市場(chǎng)前瞻性、產(chǎn)品創(chuàng)新能力,以專注、極致的服務(wù)理念,為客戶提供做網(wǎng)站、成都網(wǎng)站設(shè)計(jì) 網(wǎng)站設(shè)計(jì)制作按需定制,公司網(wǎng)站建設(shè),企業(yè)網(wǎng)站建設(shè),品牌網(wǎng)站設(shè)計(jì),全網(wǎng)營銷推廣,外貿(mào)網(wǎng)站制作,梅里斯網(wǎng)站建設(shè)費(fèi)用合理。
一、什么是反射
反射(Reflection)是Java的特征之一,C/C++語言中不存在反射,反射的存在使得運(yùn)行中的Java程序能夠獲取自身的信息,并且可以操作類或?qū)ο蟮膬?nèi)部屬性。那什么是反射呢?
下面是官方的解釋:
反射使得Java代碼能夠發(fā)現(xiàn)有已加載類的字段、方法和構(gòu)造函數(shù)的信息,并在安全限制內(nèi)使用反射的字段、方法和構(gòu)造函數(shù)對(duì)其底層對(duì)應(yīng)的對(duì)象進(jìn)行操作
簡(jiǎn)單來說,通過反射,我們可以在運(yùn)行時(shí)獲得程序或程序集中每一個(gè)類型的成員和成員的信息。同樣的,Java的反射機(jī)制也是也是如此,在運(yùn)行狀態(tài)中,通過Java的反射機(jī)制,我們能夠判斷一個(gè)對(duì)象所屬的類;了解任意一個(gè)類的所有屬性和方法;能夠調(diào)用任意一個(gè)對(duì)象的任意方法和屬性;這種動(dòng)態(tài)獲取的信息以及動(dòng)態(tài)調(diào)用對(duì)象的方法的功能稱為Java語言的反射機(jī)制。
二、反射的用途
在靜態(tài)語言中,一般對(duì)象的類型都是在編譯期就確定下來的,二通過Java反射機(jī)制,可以動(dòng)態(tài)的創(chuàng)建對(duì)象并調(diào)用其方法或?qū)傩?,這也就使得的反射的用途很廣泛,在開發(fā)過程中使用Eclipse、IDEA等開發(fā)工具時(shí),當(dāng)我們輸入一個(gè)對(duì)象或類并想調(diào)用它的屬性或方法時(shí),編譯器會(huì)自動(dòng)列出它的屬性或方法,這是通過反射實(shí)現(xiàn)的;載入,JavaBean和jsp之間的調(diào)用也是通過反射實(shí)現(xiàn)的。反射最重要的用途是開發(fā)各種框架,如上文中提到的Spring框架以及ORM框架,都是通過反射機(jī)制來實(shí)現(xiàn)的。
面向不同的用戶,反射機(jī)制的重要程度也大不相同。對(duì)于框架開發(fā)人員來說,反射雖小但作用非常大,它是各種容器實(shí)現(xiàn)的核心。對(duì)于一般的開發(fā)者來說,反射的作用相對(duì)較小。但總體來說,適當(dāng)了解二框架的底層機(jī)制對(duì)我們的編程思想也是非常有幫助的。
三、靜態(tài)語言和動(dòng)態(tài)語言
在學(xué)習(xí)反射之前,我們有必要了解一下什么是動(dòng)態(tài)語言和靜態(tài)語言
- 靜態(tài)語言(強(qiáng)類型語言)
靜態(tài)語言是在編譯時(shí)變量的數(shù)據(jù)類型即可確定的語言,多數(shù)靜態(tài)語言要求在使用變量之前必須聲明數(shù)據(jù)的類型。如C++、Java、Delphi、C#等
- 動(dòng)態(tài)語言(弱類型語言)
動(dòng)態(tài)語言時(shí)在運(yùn)行是確定數(shù)據(jù)類型的語言。變量使用之前不需要類型聲明,通常變量的類型是被賦值的那個(gè)值的類型。如PHP/ASP/Ruby/Python.Perl/ABAP/SQL/JavaScript/Unix Shell等等。
可以在程序運(yùn)行時(shí)改變程序結(jié)構(gòu)和變量類型的語言,比如在程序運(yùn)行時(shí),新的類和對(duì)象可以被加載和創(chuàng)建,新的函數(shù)或方法可以被加入或者去除等等。
3.1、動(dòng)態(tài)特性
動(dòng)態(tài)語言具有的某些特性即為動(dòng)態(tài)特性
以PHP舉例,一段代碼,其中變量值的改變可鞥導(dǎo)致這段代碼發(fā)生功能上的變化,我們將這種現(xiàn)象稱為PHP的動(dòng)態(tài)特性
比如下面的這個(gè)例子
我們只有當(dāng)代碼運(yùn)行時(shí),通過變量傳入的值才能確定其具體功能
3.2、動(dòng)態(tài)特性與Java反射
正是因?yàn)镻HP中存在多種動(dòng)態(tài)特性,使得開發(fā)人員能通過很少的代碼實(shí)現(xiàn)非常多的功能,比較經(jīng)典的例子就是一句話木馬,通過一行
但是Java本身是一門靜態(tài)語言,無法像PHP那么靈活多變。但是通過Java反射機(jī)制,可以為自身提供一些動(dòng)態(tài)特性。比如,當(dāng)我們通過IDE寫代碼時(shí),敲擊點(diǎn)好號(hào)“.”,會(huì)出現(xiàn)當(dāng)前對(duì)象或類所包含的屬性和方法,這里用到的就是Java反射機(jī)制。
反射最重要的用途就是開發(fā)各種通用框架,很多框架嗾使通過XML文件來進(jìn)行配置的(如:struts.xml,spring-*.xml等),即所謂的框架核心配置文件。為了確??蚣艿耐ㄓ眯?,程序運(yùn)行時(shí)需要根據(jù)配置文件中對(duì)應(yīng)的內(nèi)容加載不同的類或?qū)ο螅{(diào)用不同的方法,這也依賴于Java反射機(jī)制。
3.3、Java反射機(jī)制功能點(diǎn)
綜上所述,Java反射機(jī)制的功能可分為如下幾點(diǎn):
- 在程序運(yùn)行時(shí)查找一個(gè)對(duì)象所屬的類
- 在程序運(yùn)行時(shí)查找任意一個(gè)類的成員變量和方法
- 在程序運(yùn)行時(shí)構(gòu)造任意一個(gè)類的對(duì)象
- 在程序運(yùn)行時(shí)調(diào)用任意一個(gè)對(duì)象的方法
四、Java的命令執(zhí)行類
4.1、java.lang.Runtime類
這個(gè)類是一個(gè)共有類,每個(gè)Java應(yīng)用程序都有一個(gè)Runtime類實(shí)例,它允許應(yīng)用程序與運(yùn)行應(yīng)用程序的環(huán)境交互。當(dāng)前運(yùn)行時(shí)可以從getRuntime方法獲得。應(yīng)用程序無法創(chuàng)建自己的此類實(shí)例。
該類的主要方法是:getRuntime(),得到一個(gè)和當(dāng)前程序相關(guān)聯(lián)的Runtime類的對(duì)象,解釋如下:
返回與當(dāng)前Java應(yīng)用關(guān)聯(lián)的runtime對(duì)象。大多數(shù)Runtime類的方法是實(shí)例方法,所以必須被當(dāng)前運(yùn)行時(shí)對(duì)象調(diào)用。
Runtime對(duì)象可以調(diào)用exec()方法執(zhí)行命令,詳細(xì)文檔解釋如下:
在一個(gè)單獨(dú)的進(jìn)程中執(zhí)行指定的命令。這是一個(gè)方便的方法。以exec(command)形式調(diào)用與exec(String,Stringp[],file)的表現(xiàn)是相同的。
下面是一段代碼示例:
五、獲取類對(duì)象
獲取類對(duì)象的方式有很多種,這里提供四種方式
- forName()
- 直接獲取
- getClass()
- getSystemClassLoader().loadClass()
5.1、獲取類對(duì)象-forName()
如果要使用Class類中的方法完成,就需要使用forName方法,只要有類名稱即可,更為防爆,擴(kuò)展性更強(qiáng)。這種方法并不陌生,在配置JDBC的時(shí)候,我們通常采用這種方法
5.2、獲取類對(duì)象-直接獲取
任何數(shù)據(jù)類型都具備一個(gè)靜態(tài)的屬性,可以使用.class來獲取其對(duì)應(yīng)的Class對(duì)象。這種方法相對(duì)簡(jiǎn)單,但還是要明確用到類的靜態(tài)成員
5.3、獲取類對(duì)象-getClass()
我們可以通過Object類中的getClass()方法來獲取字節(jié)碼對(duì)象,不過這種方式較為繁瑣,必須要明確具體的類,然后創(chuàng)建對(duì)象
六、獲取類方法
獲取某個(gè)Class對(duì)象的方法集合,主要有以下幾種方法:
- getDeclareMethods
- getDecleardMethod
- getMethods
- getMethod
6.1、獲取類方法-getDeclaredMethods
getDeclaredMethods方法返回類或接口聲明的所有方法,包括:public、protected、private和默認(rèn)方法,但不包括繼承的方法
6.2、獲取類方法-getMethods
getMethods方法返回某個(gè)類的所有public方法,包括其繼承的public方法
6.3、獲取類方法-getMethod
getMethod方法只能返回一個(gè)特定的方法,如 Runtime類中的exec()方法,該方法的第一個(gè)參數(shù)為方法名稱,后面的參數(shù)為方法的參數(shù)對(duì)應(yīng)Class的對(duì)象
6.4、獲取類方法 - getDeclaredMethod
getDeclaredMethod方法與getMethod類似,也只能返回一個(gè)特定的方法,該方法的第一個(gè)參數(shù)為方法名,第二個(gè)參數(shù)名是方法參數(shù)
七、獲取類成員變量
為了更直觀地體現(xiàn)出獲取類成員變量的方法,我們首先創(chuàng)建一個(gè)Student類,要獲取Student類成員變量,主要有以下幾個(gè)方法:
- getDeclaredFields
- getDeclaredField
- getFields
- getField
7.1、獲取類成員變量-getDeclaredFields
getDeclaredFields方法能夠獲得類成員變量數(shù)組,包括public、private和proteced,但是不包括父類的聲明字段
7.2、獲取類成員變量-getFields
gteFields能夠獲得某個(gè)類的所有的public字段,包括父類中的字段
7.3、獲取類成員變量-getDeclaredField
該方法與getDeclaresFields的區(qū)別是只能獲得類的單個(gè)成員變量
7.4、獲取類成員變量-getField
與getFields類似,getField方法能夠獲得某個(gè)類特定的public字段,包括父類中的字段
八、構(gòu)造任意類的對(duì)象
構(gòu)造任意類的對(duì)象最經(jīng)典的方式:
無參數(shù):className.newInstance()
有參數(shù):getConstructor().newInstance()
構(gòu)造任意類的對(duì)象兩種方式異同
(1)首先兩種方式在原始碼所在的位置上不同
- Class.newInstance() → 在java.lang包
- Constructor.newInstance() → 在java.lang.reflect包
(2)在使用方法上的不同
- ClassName.newInstance():
- Class.forName("com.ms08067.newInstance.newInstanceExample").newInstance();
- newInstanceExample.class.newInstance();- getConstructor().newInstance()
- newInstanceExample.class.getConstructor().newInstance();
- Class.newInstance() 只能反射無參的構(gòu)造器
- Constructor.newInstance() 可以反射任何構(gòu)造器
- Class.newInstance() 需要構(gòu)造器可見
- Constructor.newInstance() 可以反私有構(gòu)造器
- Class.newInstance() 對(duì)于捕獲或者未捕獲的一場(chǎng)均由構(gòu)造器丟擲;
- Constructor.newInstance() 通常會(huì)把丟擲的異常封裝成InvocationTrageException丟擲
九、調(diào)用任意實(shí)例對(duì)象的方法
調(diào)用任意實(shí)例對(duì)象的方法最經(jīng)典的方式
- 直接調(diào)用:objectName.functionName()
- invoke調(diào)用:invoke()
invoke方法調(diào)用任意實(shí)例對(duì)象是通過反射實(shí)現(xiàn)的,下面是一個(gè)示例:
十、不安全的反射
如前所述,利用Java的反射機(jī)制,我們可以無視類方法、變量訪問權(quán)限修飾符,調(diào)用任何類的任意方法、訪問并修改成員變量值,但是這樣做可能導(dǎo)致安全問題,如果一個(gè)攻擊者能夠通過應(yīng)用程序創(chuàng)建意外的控制流路徑,就有可能繞過安全檢查發(fā)起相關(guān)攻擊。假設(shè)有一段代碼如下:
其中存在一個(gè)字段name,當(dāng)獲取用戶請(qǐng)求的name字段后進(jìn)行判斷,如果請(qǐng)求的是Delect操作,則執(zhí)行DelectCommand函數(shù);若執(zhí)行的是Add操作,則執(zhí)行AddCommand函數(shù);如果不是這兩種操作,則執(zhí)行其他代碼。
假如開發(fā)者看到了這段代碼,他認(rèn)為可以使用Java的反射來重構(gòu)此代碼以減少代碼行,如下所示:
這樣的重構(gòu)看起來使得代碼行減少,消除了if/else塊,而且可以在不修改命令分派器的情況下添加新的命令類型,但是如果沒有對(duì)傳入的name字段進(jìn)行限制,則可以實(shí)例化實(shí)現(xiàn)Command接口的任何對(duì)象,從而導(dǎo)致安全問題。實(shí)際上,攻擊者甚至不局限于本例中的Command接對(duì)象,而是使用任何其他對(duì)象來實(shí)現(xiàn),如調(diào)用系統(tǒng)中任何對(duì)象的默認(rèn)構(gòu)造函數(shù),或者調(diào)用Runtime對(duì)象去執(zhí)行系統(tǒng)命令,這可能導(dǎo)致遠(yuǎn)程命令執(zhí)行漏洞,因此不安全的反射的危害性極大,也是我們審計(jì)過程中需要重點(diǎn)關(guān)注的內(nèi)容。
本文標(biāo)題:Java安全基礎(chǔ)之Java的反射機(jī)制
轉(zhuǎn)載源于:http://www.dlmjj.cn/article/djohdhp.html


咨詢
建站咨詢
