在b/s頁面間的通信,http是無狀態的協議。web頁面本身無法向下一個頁面傳遞信息,如果需要讓下一個頁面得知該頁面中的值,可以通過服務器,web頁面保持狀態並傳遞給其他頁面。
在http協議中一共有4種方法來完成這件事情:
1)url傳值
2)表單傳值
3)Cookie方法
4)Session方法
1、URL傳值
將頁面1中的值傳給頁面2
<body> <% String str="123"; int number=Integer.parseInt(str); %> 該數的平方為:<%=number*number%><hr> <a href="index.jsp?number=<%=number%>">到達index頁面</a> </body>
index頁面:
<body> <% //獲得number String str=request.getParamter("number"); int number=Integer.parseInt(str); %> 該數字的立方為:<%=number*number*number%><hr> </body>
頁面顯示效果:
優點:簡單性和平台支持的多樣性(沒有瀏覽器不支持url)
缺點:
1)傳輸的數據只能是字符串,對數據類型具有一定的限制
2)傳輸數據的值會在瀏覽器地址欄里面被看到,從保密的角度講,這是不安全的。特別是秘密性要求比較嚴格的數據,如密碼
2、表單傳值
方法一中通過url傳的值會被看到,為了避免這個問題,我們可以使用表單將頁面1中的變量傳給頁面2
<body> <% String str="10"; int number=Integer.parseInt(str); %> 該數的平方為:<%=number*number%><hr> <form action="index.jsp" method="post"> <input type="text" name="number" value="<%=number%>"> <input type="submit" value="到達index頁面"> </form> </body>
index.jsp頁面:
<body> <% //獲得number String str=request.getParameter("number"); int number=Integer.parseInt(str); %> 該數字的立方為:<%=number*number*number%><hr> </bpdy>
頁面展示結果:
該方法順利的進行了值傳遞,並且無法看到傳遞的信息,在文本框中如果想要隱藏,將type="text"改為type="hidden"即可實現隱藏
該方法的問題:
1)和url方法類似,該方法傳輸的數據,也只能是字符串,對數據類型具有一定的限制
2)傳輸數據的值雖然可以保證在瀏覽器地址欄里不被看到,但是在客戶端源代碼里面也會被看到,從保密的角度講,這里也是不安全的。對於是秘密性要求比較嚴格的數據,如密碼還是不建議使用表單進行傳輸
3、Cookie方法
為解決以上問題,在頁面之間進行數據傳遞的過程中,Cookie是一種常見的方法
Cookie是一個小的文本數據,由服務器端生成,發送給客戶端瀏覽器,客戶端瀏覽器如果設置為啟用cookie,則會將這個小文本數據保存到其目錄下的文本文件內
客戶端下次登錄同一網站,瀏覽器則會自動將Cookie讀入之后,傳給服務器端。服務器端可以對該Cookie進行讀取並驗證(當然也可以不讀取)
一般情況下,Cookie中的值是以key-value的形式進行表達的。基於這個原理,上面的例子可以用Cookie來進行。即:在第一個頁面中,將要共享的變量值保存在客戶端Cookie文件內,在客戶端訪問第二個頁面時,由於瀏覽器自動將Cookie讀入之后,傳給服務器端,因此只需要第二個頁面中,由服務器端頁面讀取這個Cookie值即可。
1、cookie.jsp:
<body> <h3>登錄成功</h3> <% String uri=request.getRequestURI();//返回請求行中的資源名稱 String url=request.getRequestURL().toString();//獲得客戶端發送請求的完整url String ip=request.getRemoteAddr();//返回發出請求的IP地址 String params=request.getQueryString();//返回請求行中的參數部分 String host=request.getRemoteHost();//返回發出請求的客戶機的主機名 int port=request.getPemotePort();//返回發出請求的客戶端的端口號 %> <% Cookie c=new Cookie("get_ip",ip); c.setMaxAge(600); response.addCookie(c); %> </body>
2、get_cookie.jsp:
<body> <h3>從cookie.jsp頁面中獲取的信息</h3> <% String ip=null; Cookie[] cookies=request.getCookies(); for(int i=0;i<cookies.length;i++){ if(cookies[i].getName().equals("get_ip")){ ip=cookies[i].getValue(); break; } } %> ip:<%=ip%> </body>
顯示結果:
1.該方法總結:
在客戶端的瀏覽器器上,我們看不到任何的和傳遞的值相關的信息,說明在客戶端瀏覽器中,Cookie 中的數據是安全的。
但是就此也不能說Cookie是完全安全的。因為 Cookie 是以文件形式保存在客戶端的,客戶端存儲的 Cookie 文件就可能敵方獲知。如果將用戶名、密碼等敏感信息保存在Cookie內,在用戶離開客戶機時不注意清空,這些信息容易泄露,因此Cookie在保存敏感信息方面具有潛在危險。可以很清楚地看到。
Cookie的危險性來源於Cookie的被盜取。目前盜取的方法有多種:
a)利用跨站腳本技術(有關跨站腳本技術,后面的篇幅將會有介紹),將信息發給目標服務器;為了隱藏跨站腳本的 URL,甚至可以結合 Ajax(異步Javascript 和 XML技術)在后台竊取 Cookie;
b)通過某些軟件,竊取硬盤下的 Cookie。如前所述,當用戶訪問完某站點后,Cookie文件會存在機器的某個文件夾(如 C:\Documents and Settings\用戶名\Cookies)下,因此可以通過某些盜取和分析軟件來盜取 Cookie。
具體步驟如下:
(1)利用盜取軟件分析系統中的 Cookie,列出用戶訪問過的網站;
(2)在這些網站中尋找攻擊者感興趣的網站;
(3)從該網站的 Cookie 中獲取相應的信息。不同的軟件有不同的實現方法,有興趣的讀者可以在網上搜索相應的軟件;
c)利用客戶端腳本盜取 Cookie。在 Javascript 中有很多 API 可以讀取客戶端 Cookie,可以將這些代碼隱藏在一個程序(如畫圖片)中,很隱秘地得到 Cookie 的值,不過,這也是跨站腳本的一種實現方式。
以上的問題並不能代表Cookie就沒有任何用處,Cookie在Web編程中應用的幾個方面:
a)Cookie 的值能夠持久化,即使客戶端機器關閉,下次打開還是可以得到里面的值。因此 Cookie 可以用來減輕用戶一些驗證工作的輸入負擔,比如用戶名和密碼的輸入,就可以在第一次登錄成功之后,將用戶名和密碼保存在客戶端 Cookie,下次不用輸入。當然,這不安全,但是,對於一些安全要求不高的網站,Cookie 還是大有用武之地。
b)Cookie可以幫助服務器端保存多個狀態信息,但是不用服務器端專門分配存儲資源,減輕了服務器端的負擔。比如網上商店中的購物車,必須將物品和具體客戶名稱綁定,但是放在服務器端又需要占據大量資源的情況下,可以用 Cookie 來實現,將每個物品和客戶的內容作為 Cookie 來保存在客戶端。
c)Cookie可以持久保持一些和客戶相關的信息。如很多網站上,客戶可以自主設計自己的個性化主頁,其作用是避免用戶每次都需要自己去找自己喜愛的內容,設計好之后,下次打開該網址,主頁上顯示的是客戶設置好的界面。這些設置信息保存在服務器端的話,消耗服務器端的資源,因此,可以將客戶的個性化設計保存在 Cookie 內,每一次訪問該主頁,客戶端將 Cookie 發送給服務器端,服務器根據 Cookie 的值來決定顯示給客戶端什么樣的界面。
2.解決Cookie安全的方法有很多,常見的有以下幾種:
a)替代cookie。將數據保存在服務器端,可選的是session方案;
b)及時刪除cookie。要刪除一個已經存在的Cookie,有以下幾種方法:
b_1:給一個Cookie賦以空置;
b_2:設置 Cookie 的失效時間為當前時間,讓該 Cookie 在當前頁面的瀏覽完之后就被刪除了;通過瀏覽器刪除Cookie。如在IE中,可以選擇“工具”——“Internet選項”——常規”,在里面點擊“刪除Cookies”,就可以刪除文件夾中的Cookie。
4、Session方法
1、與前三種的區別:
前幾種方法在傳遞數據時,有一個共同的問題就是內容保存在客戶端里。因此,具有泄露的危險性。如果在不考慮服務器負載的情況下,將數據保存在服務端里,是一個比較好的方法,這就是session方法。
通過session.setAttribute("num",str);將str存到session中,通過session.getAttribute("num");從session中獲取num。
2、服務器怎么知道要分配給它的是同一個session對象呢?
實際上,在客戶進行第一次訪問時,服務器端就給 session 分配了一個 sessionId,並且讓客戶端記住了這個 sessionId,客戶端訪問下一個頁面時,又將 sessionId 傳送給服務器端,服務器端根據這個 sessionId 來找到前一個頁面用的 session,由此保證為同一個客戶服務的 session 對象是同一個。
3、session分配的具體過程為:
1)客戶端訪問服務器,服務器使用 session,首先檢查這個客戶端的請求里是否已包含了 sessionId;
2)如果有,服務器就在內存中檢索相應 Id 的 session 來用;
3)否則服務器為該客戶端創建一個 session 並且生成一個相應的 sessionId,並且在該次響應中返回給客戶端保存。
4、session的應用
session 經常用於保存用戶登錄狀態。比如用戶登錄成功之后要訪問好幾個頁面,但是每個頁面都需要知道是哪個用戶在登錄,此時就可以將用戶的用戶名保存在 session 內。
login.jsp:
歡迎登錄郵箱 <form action="login.jsp" method="post"> 賬號:<input name="account" type="text"><br> 密碼:<input name="password" type="password"><br> <input type="submit" value="登錄"> </form> <% //獲取賬號密碼 String account=request.getParameter("account"); String password=request.getParameter("password"); if(account!=null){ //驗證賬號密碼,假如賬號密碼相同表示登錄成功 if(account.equals(password)){ //放入session,跳轉到下一個頁面 session.setAttribute("account",account); response.sendRedirect("loginResult.jsp"); }else{ out.println("登錄不成功"); } } %>
loginResult.jsp
<% if(session.getAttribute("account")==null){ response.sendRedirect("login.jsp"); } %> 歡迎<%=session.getAttribute("account")%>來到郵箱!
session 機制最大的不安全因素是 sessionId 可以被攻擊者截獲,如果攻擊者通過一些手段知道了 sessionId,由於 sessionId 是客戶端尋找服務器端 session 對象的唯一標識,攻擊者就有可能根據 sesionId 來訪問服務器端的 session 對象,得知 session 中的內容,從而實施攻擊。
在 session 機制中,很多人認為:只要瀏覽器關閉,會話結束,session 就消失了。其實不然,瀏覽器關閉,會話結束,對於客戶端來說,已經無法直接再訪問原來的那個 session,但並不代表 session 在服務器端會馬上消失。除非程序通知服務器刪除一個 session,否則服務器會一直保留這個 session 對象,直到 session 超時失效,被垃圾收集機制收集掉。但是令人遺憾的是,客戶在關閉瀏覽器時,一般不會通知服務器。由於關閉瀏覽器不會導致 session 被刪除,因此,客戶端關閉之后,session 還未失效的情況下,就給了攻擊者以機會來獲取 session 中的內容。
雖然 sessionId 是隨機的長字符串,通常比較難被猜測到,這在某種程度上可以加強其安全性,但是一旦被攻擊者獲得,就可以進行一些攻擊活動,如:攻擊者獲取客戶 sessionId,然后攻擊者自行偽造一個相同的 sessionId,訪問服務器,實際上等價於偽裝成該用戶進行操作。
6、防止以上因為 sessionId 泄露而造成的安全問題
1)在服務器端,可以在客戶端登陸系統時,盡量不要使用單一的 sessionId 對用戶登陸進行驗證。可以通過一定的手段,不時地變更用戶的 sessionId;
2)在客戶端,應該在瀏覽器關閉時刪除服務器端的 session,也就是說在關閉時必須通知服務器端。最簡單的方法,可以用 Javascript 實現。