陳剛
(內(nèi)江職業(yè)技術(shù)學(xué)院 信息電子工程系,四川 內(nèi)江 641100)
基于Web程序提供的產(chǎn)品和服務(wù),使信息產(chǎn)業(yè)已滲透到人們?nèi)粘I?、學(xué)習(xí)和工作的方方面面,隨之而來(lái)的是Web程序也日益成為惡意攻擊的目標(biāo)。當(dāng)前Web應(yīng)用的開發(fā)都是基于某一軟件體系架構(gòu),與別的開發(fā)架構(gòu)一樣,ASP.NET MVC的內(nèi)置特征并不能對(duì)常見的網(wǎng)絡(luò)安全問題給予足夠的支持。為了更好地解決這個(gè)問題,同時(shí)遵循軟件工程的一些基本原則,(如分隔原則、構(gòu)件原則以及復(fù)用原則等),需要配合一定的設(shè)計(jì)模式,以提高軟件產(chǎn)品的質(zhì)量。
微軟自2009年推出ASP.NET MVC1以來(lái),到目前為止已推出第3個(gè)正式版本,即ASP.NET MVC3。ASP.NET MVC將Web應(yīng)用程序的輸入邏輯、業(yè)務(wù)邏輯和用戶界面邏輯3個(gè)不同的方面進(jìn)行隔離,從而將一個(gè)MVC程序分為3個(gè)部分:模型(Model)、視圖(View)和控制器(Controller)。 每一部分都定義良好且是自包含的,即:與數(shù)據(jù)操作相關(guān)的邏輯僅包含在Model之中;與數(shù)據(jù)顯示相關(guān)的邏輯僅包含在View中;處理用戶請(qǐng)求和輸入僅包含在Controller中。Model、View和 Controller描述如下:
(1)Model:是對(duì)應(yīng)用領(lǐng)域的定義,它可以是簡(jiǎn)單的view model, 也可以是 domain model。view models只是描述在View和Controller之間傳遞的數(shù)據(jù);而 domain model則包含業(yè)務(wù)邏輯和數(shù)據(jù)操作規(guī)則。Model的設(shè)計(jì)是MVC的核心。
(2)View:代表應(yīng)用程序的用戶界面,顯示數(shù)據(jù)。
(3)Controller:是 View 和 Model之間的膠合劑,它處理請(qǐng)求,執(zhí)行Model上定義的操作,選擇View顯示給用戶。
在處理 HTTP請(qǐng)求時(shí),Controller、Model和 View之間的相互作用如圖1[1]所示。
圖1 控制器、模型和視圖之間的相互作用
ASP.NET MVC3具有非常優(yōu)秀的靈活性和可擴(kuò)展性,但其內(nèi)置特性對(duì)基于MVC架構(gòu)的應(yīng)用只提供了基礎(chǔ)的支持,許多在實(shí)際應(yīng)用中需要的功能ASP.NET MVC3并沒有實(shí)現(xiàn),只是留下一些接口供開發(fā)者根據(jù)具體的應(yīng)用環(huán)境加以實(shí)施。這其中比較重要的一點(diǎn)就是Web程序的安全性能。因?yàn)殡S著信息技術(shù)的迅猛發(fā)展,人們?nèi)粘5膶W(xué)習(xí)、生活和工作越來(lái)越依賴于Web程序所提供的服務(wù),與此同時(shí)Web程序也日益成為惡意攻擊的目標(biāo)。所以,如何在基于MVC架構(gòu)的應(yīng)用中解決Web程序的安全風(fēng)險(xiǎn)就成為了系統(tǒng)開發(fā)人員必須面對(duì)和解決的問題。據(jù) OWASP(Open Web Application Security Project)提供的數(shù)據(jù)顯示,目前排在前兩位的Web程序安全風(fēng)險(xiǎn)是注入和 CSS(Cross-Site Scripting)[2],要較為完善地解決這個(gè)問題需要遵循軟件工程的一些基本原則,并配合使用一定的設(shè)計(jì)模式,才能開發(fā)出質(zhì)量較高的應(yīng)用系統(tǒng)。
截取過(guò)濾器模式是Web應(yīng)用程序?qū)S玫?,表示層的設(shè)計(jì)模式表達(dá)的是表示層的請(qǐng)求處理機(jī)制,它工作在應(yīng)用程序級(jí)別上,對(duì)行為和信息流而非對(duì)象進(jìn)行處理。截取過(guò)濾器模式的核心思想是用一個(gè)簡(jiǎn)單的機(jī)制實(shí)現(xiàn)不同過(guò)濾動(dòng)作的處理組件的添加和刪除,通過(guò)創(chuàng)建可插拔的過(guò)濾器,以標(biāo)準(zhǔn)的方式提供各種服務(wù),而不需要修改核心的請(qǐng)求處理代碼。定義在這些過(guò)濾器中的方法被ASP.NET MVC的內(nèi)置代碼解析出來(lái)掛接到MVC請(qǐng)求處理管道的恰當(dāng)?shù)奈恢蒙希⒃诟髯缘沫h(huán)節(jié)上截取Web請(qǐng)求,對(duì)請(qǐng)求信息進(jìn)行分析、修改或重定向,從而為Web請(qǐng)求的處理提供諸如安全、登錄、加密等服務(wù)。
截取過(guò)濾器有如下的優(yōu)點(diǎn)[3]:
(1)關(guān)注分離:由于過(guò)濾器中的邏輯和應(yīng)用程序的邏輯是去耦合的,因此當(dāng)?shù)讓犹匦愿淖儠r(shí),應(yīng)用程序的代碼不受影響。
(2)靈活性:由于過(guò)濾器之間是相互獨(dú)立的,因此可以任意地組合這些過(guò)濾器而不需要改變過(guò)濾器的代碼。
(3)中心化配置:由于過(guò)濾器的可組合性,可以使用單一的配置文件來(lái)加載過(guò)濾器鏈,也可以修改這個(gè)配置文件來(lái)決定處理請(qǐng)求的過(guò)濾器鏈的組成。
(4)可復(fù)用性:因?yàn)檫^(guò)濾器不依賴于它們操作的環(huán)境,因此這些過(guò)濾器能夠在別的Web程序中被重用。
(5)部署時(shí)的兼容性:由于過(guò)濾器鏈能夠在運(yùn)行時(shí)基于配置文件構(gòu)建出來(lái),因此可以在部署期間改變過(guò)濾器的順序而不用修改代碼。
考慮到截取過(guò)濾器在ASP.NET WebForm架構(gòu)中的實(shí)現(xiàn),為保持一致性和連貫性,本文針對(duì)ASP.NET MVC3提出一種基于配置文件的全局動(dòng)態(tài)截取過(guò)濾器實(shí)現(xiàn)方案。該方案中的任何一個(gè)全局動(dòng)態(tài)過(guò)濾器是否應(yīng)用于某個(gè)Controller或Action取決于該過(guò)濾器在配置文件中的配置情況,并使用庫(kù)類FilterProviders注冊(cè)過(guò)濾器。該方案簡(jiǎn)要描述如下:
各過(guò)濾器獨(dú)立編碼,并編譯為獨(dú)立的程序集,并在配置文件中配置各過(guò)濾器要應(yīng)用到哪些Controller或Action;然后,使用類 FiltersConfiguration 的 GetAllFilters()方法讀取配置文件中各個(gè)過(guò)濾器的配置信息,并用這些配置信息構(gòu)建一個(gè)泛型列表List 該方案中各個(gè)部分描述如下: (1)過(guò)濾器:過(guò)濾器繼承抽象類FilterAttribute并實(shí)現(xiàn)接口IActionFilter、IExceptionFilter、IResultFilter、IAuthorizationFilter中的一個(gè)或多個(gè)。過(guò)濾器及其使用情況在配置文件中進(jìn)行配置,配置結(jié)構(gòu)如下: 其中,節(jié)點(diǎn)filter用于配置一個(gè)過(guò)濾器;節(jié)點(diǎn)element用于設(shè)置該過(guò)濾器需要應(yīng)用的Controller和Action,若要應(yīng)用到所有的Controller和Action,則需將該節(jié)點(diǎn)屬性controller和 action都設(shè)置為字符“*”;節(jié)點(diǎn) Allfilters可以包含0個(gè)或多個(gè)filter節(jié)點(diǎn),每個(gè)filter節(jié)點(diǎn)可以包含1個(gè)或多個(gè)element節(jié)點(diǎn)。 (2)讀取配置信息:使用自定義類 FilterNode、Element、FiltersConfiguration來(lái)讀取配置信息。FilterNode對(duì)應(yīng)于filter節(jié)點(diǎn),用于存放配置文件中每個(gè)過(guò)濾器的配置信息,相應(yīng)地該類的成員有:屬性Name、Assembly以及Elements。Name對(duì)應(yīng)于 filter節(jié)點(diǎn)的Name屬性,Assembly對(duì)應(yīng)于 filter節(jié)點(diǎn)的 assembly屬性,Elements包含 filter節(jié)點(diǎn)所有element子節(jié)點(diǎn)的配置信息。Element類對(duì)應(yīng)于element節(jié)點(diǎn),包含屬性Controller和Action,分別對(duì)應(yīng)于element節(jié)點(diǎn)的controller和action屬性。FiltersConfiguration類讀取配置文件中過(guò)濾器的配置信息,其方法是用GetAllFilters()實(shí)現(xiàn)該功能,并返回一個(gè)由過(guò)濾器配置信息構(gòu)建的一個(gè)泛型列表List (3)過(guò)濾器提供器:自定義類 FilterProvider,該類實(shí)現(xiàn)IFilterProvider接口,用于實(shí)例化過(guò)濾器,包含有:屬性Assembly和Name、字段actions以及方法Add和GetFilters。Assembly和Name分別對(duì)應(yīng)于配置文件中各過(guò)濾器的程序集名稱和類名;字段actions包含當(dāng)前要實(shí)例化的過(guò)濾器在配置文件中element節(jié)點(diǎn)的信息,是一個(gè)ControllerAction實(shí)例的泛型列表。自定義類ControllerAction,包含屬性Controller和 Action,對(duì)應(yīng)于element節(jié)點(diǎn)的配置信息;Add方法用于向actions字段添加element節(jié)點(diǎn)的信息,構(gòu)建泛型列表List (4)注冊(cè)過(guò)濾器:在Global.cs文件的RegisterGlobalFilters方法中調(diào)用FiltersConfiguration的GetAllFilters方法讀取各過(guò)濾器的配置信息。針對(duì)每一個(gè)過(guò)濾器,使用一個(gè)FilterProvider實(shí)例來(lái)處理,并將其添加到MVC FilterProvider collection中。 采用了本截取過(guò)濾器實(shí)現(xiàn)方案的系統(tǒng)的應(yīng)用模型如圖2所示。 圖2 本截取過(guò)濾器實(shí)現(xiàn)方案的應(yīng)用模型 說(shuō)明如下: (1)Filter1 可以是 Authorization filter或 Action filter,F(xiàn)ilter2可以是 Action filter或 Result filter,F(xiàn)ilter3可以是Result filter或 Exception filter。 (2)Filter1、Filter2、Filter3 中任何一個(gè)都可以代表 0個(gè)或多個(gè)過(guò)濾器。 本實(shí)例以某一在線購(gòu)書網(wǎng)站來(lái)說(shuō)明如何利用本文提出的基于ASP.NET MVC3的截取過(guò)濾器實(shí)現(xiàn)方案消除Web程序的注入風(fēng)險(xiǎn) (包括SQL注入和JavaScript注入)。該系統(tǒng)提供常見的在線購(gòu)物功能,其中的一些動(dòng)態(tài)內(nèi)容存在注入風(fēng)險(xiǎn),如:注冊(cè)、會(huì)員登錄、庫(kù)存搜索、服務(wù)質(zhì)量評(píng)價(jià)和書籍缺貨預(yù)訂等,由于這些風(fēng)險(xiǎn)跨越多個(gè)Controller,因此可以考慮用本文提出的截取過(guò)濾器實(shí)現(xiàn)方案來(lái)解決這個(gè)問題,即:針對(duì)SQL注入風(fēng)險(xiǎn)定義過(guò)濾器類 SqlInjectionFilterAttribute,針對(duì) JavaScript注入風(fēng)險(xiǎn)定義過(guò)濾器類JavaScriptFilterAttribute。這兩個(gè)類均繼承自FilterAttribute并分別實(shí)現(xiàn)IActionFilter.OnActionExecuting方法和IResultFilter.OnResultExecuted方法。限于篇幅,具體的編碼不能詳述,這里僅對(duì)這兩個(gè)方法的實(shí)現(xiàn)算法做一扼要說(shuō)明。 (1)SqlInjectionFilterAttribute.OnActionExecuting 方法 本方法對(duì)用戶輸入的內(nèi)容進(jìn)行過(guò)濾,以有效減少SQL注入的發(fā)生,對(duì)輸入數(shù)據(jù)中有潛在威脅的字符,如單引號(hào)、連接符、SQL關(guān)鍵字等分別進(jìn)行處理:將所有單獨(dú)出現(xiàn)的單引號(hào)改成兩個(gè)單引號(hào);刪除連字符;對(duì)含有諸如 exec、insert、select、delete、from、update 等 SQL 關(guān)鍵字的輸入內(nèi)容,不予響應(yīng)。 (2)JavaScriptFilterAttribute.OnResultExecuted 方法[4] 在本方法中對(duì)用戶輸入字符串中包含的一些特殊字符進(jìn)行編碼,如:字符“<”被轉(zhuǎn)換成 <;,字符“>”轉(zhuǎn)換成 >;,字符 “&”被轉(zhuǎn)換成 &;等,從而消除JavaScript注入風(fēng)險(xiǎn)。 這兩個(gè)過(guò)濾器在Web.config中的配置如下(限于篇幅做了部分省略): 在使用ASP.NET MVC架構(gòu)進(jìn)行應(yīng)用系統(tǒng)開發(fā)中有效地使用截取過(guò)濾器模式,可以使在遵循軟件工程的一些基本原則的情況下,較好地解決一些Web應(yīng)用中常見的問題。本文針對(duì)ASP.NET MVC3提出一種可配的全局動(dòng)態(tài)截取過(guò)濾器實(shí)現(xiàn)方案,并應(yīng)用該方案來(lái)優(yōu)化ASP.NET MVC架構(gòu)的安全性能,體現(xiàn)了軟件工程中分隔原則、構(gòu)件原則以及復(fù)用原則等一些基本準(zhǔn)則,提高了代碼的復(fù)用性、增強(qiáng)了系統(tǒng)的靈活性,并使得程序的擴(kuò)展和維護(hù)變得更加容易。 [1]FREEMAN A,SANDERSON S.Pro ASP.NET MVC3 framework[M].Apress press,2011. [2]OWASP.Category: OWASP top ten project[EB/OL]. (2012-01-18).https: //www.owasp.org/index.php/Category:OWASP_Top_Ten_Project. [3]Microsoft.Intercepting filter[EB/OL].[2012-05-01].http://msdn.microsoft.com/en-us/library/ff647251.aspx. [4]SALEM A.Intercepting filter approach to injection flaws[J].Journal of Information Processing Systems.,2010,12(4):563-574.3 截取過(guò)濾器實(shí)現(xiàn)方案的應(yīng)用