Security Model

Model one

Servlet技術規範規定了兩種由容器實現的Java Web應用程序的安全模型。它們分別是:聲明性安全模型和程序性安全模型。

   程序性安全模型是指可以在部署的時候由部署者爲WEB資源配置安全限制。如:將用戶放入組中(後面稱之爲角色role),爲特定資源配置身份驗證。Web應用程序的部署描述符文件(web.xml文件)就是定義這些操作的位置。程序性安全模型指的是由程序開發者在代碼中使用特定的方法來限制某些資源的訪問。如果安全規則發生變化之後,那麼就需要重新編寫代碼和重新編譯,所以只有在絕對必要的情況下才使用這種安全模型。

   下面我用Tomcat5.5.9容器,通過一個例子程序給大家介紹一下以上兩種模型。例子環境如下:

  Web根目錄名稱:SecurityWeb

  有如下JSP頁面:addPet.jsp  增加寵物信息頁面和增加獸醫信息頁面

                              modifyVet.jsp 修改寵物信息頁面和修改獸醫信息頁面

                                    searchVet.jsp 查詢寵物信息頁面和查詢獸醫信息頁面

  診所科室三個:掛號室(能查詢、添加寵物和獸醫信息,但不能修改寵物和獸醫信息),檔案室(能查詢、修改寵物和獸醫信息,但不能添加寵物和獸醫信息),所長室(能查詢、添加、修改寵物和獸醫信息)

以上三個科室用拼音表示分別爲三個角色:

  Guahaoshi 角色有用戶:  gua1   gua2

   Danganshi 角色有用戶:dang1 dang2

   Suozhangshi 角色有用戶:suo1 suo2

   建立web應用程序大家自己建立,我就不多說了,但是強調一下,在使用JBuilder的時候,可能會遇到一些麻煩,可能需要你單獨部署web應用程序或者更改啓動參數才能看到效果。

   在web.xml文件中我們做如下的配置: <!--哪些web資源需要保護,需要的身份驗證類型,及哪些角色可以訪問 -->
  <security-constraint>
   <!--給該安全約束起一個名字,GUI工具可以使用-->
   <display-name>add</display-name>
   <web-resource-collection>
      <!--給被保護的資源起一個名字-->
     <web-resource-name>add Resource</web-resource-name>
       <!--被保護的資源-->
       <url-pattern>/addPet.jsp</url-pattern>
       <url-pattern>/addVet.jsp</url-pattern>
       <!--被保護的方法,沒有設置爲全部方法-->
       <http-method>GET</http-method>
       <http-method>POST</http-method>
   </web-resource-collection>
   <!--授予權限,哪些角色可以訪問-->
   <auth-constraint>
     <role-name>guahaoshi</role-name>
     <role-name>suozhangshi</role-name>
   </auth-constraint>
 </security-constraint>

<security-constraint>
   <display-name>search</display-name>
   <web-resource-collection>
     <web-resource-name>search Resource</web-resource-name>
     <url-pattern>/searchPet.jsp</url-pattern>
     <url-pattern>/searchVet.jsp</url-pattern>
     <http-method>GET</http-method>
     <http-method>POST</http-method>
   </web-resource-collection>
   <auth-constraint>
     <role-name>guahaoshi</role-name>
     <role-name>suozhangshi</role-name>
     <role-name>danganshi</role-name>
   </auth-constraint>
 </security-constraint>

  <login-config>
    <!--被保護資源的驗證方法,共四種,後面講述其它三種-->
    <auth-method>BASIC</auth-method>
    <realm-name>Welcome to Pet hospital</realm-name>
 </login-config>

配置好這些還不行,我們還要定義角色及哪些用戶屬於該角色。默認位置是${CATALINA_HOME}conf \tomcat-user.xml文件,其中${CATALINA_HOME}表示tomcat根目錄。在該文件中加入如下信息:<!--定義角色-->
<role rolename="suozhangshi"/>
<role rolename="guahaoshi"/>
<role rolename="danganshi"/>
<!--定義用戶,並授予角色中-->
<user username="gua1" password="gua1" roles="guahaoshi"/>
<user username="gua2" password="gua2" roles="guahaoshi"/>
<user username="dang1" password="dang1" roles="danganshi"/>
<user username="dang2" password="dang2" roles="danganshi"/>
<user username="suo1" password="suo1" roles="suozhangshi"/>
<user username="suo2" password="suo2" roles="suozhangshi"/>     部署應用程序,然後啓動服務器,在瀏覽器的地址欄中鍵入如下的網址:   http://localhost:8080/SecurityWeb/addPet.jsp後,可以看到如下圖所示:

  輸入用戶名和密碼,只有被授權的用戶可以訪問。至於哪些用戶能夠訪問addPet.jsp頁面,我想答案應該是上帝才知道

Model two

上文且說到tomcat-users.xml文件,這個文件中的內容是不依賴於任何一個web應用程序,所以在任何一個web程序中都可以使用,如果這些用戶和角色只對你的應用起作用,那麼你完全可以放置在你自己的應用程序中,比如WEB-INF中.下面我們將上次加入到tomcat-users.xml文件中的內容, 加入到我們在WEB-INF下新建的myUser.xml文件中,注意此文件應該是以<tomcat-users>爲根目錄,如下所示:

<tomcat-users>
  <!--定義角色-->
  <role rolename="suozhangshi"/>
  <role rolename="guahaoshi"/>
  <role rolename="danganshi"/>
  <!--定義用戶,並加入到角色中-->
  <user username="gua1" password="gua1" roles="guahaoshi"/>
  <user username="gua2" password="gua2" roles="guahaoshi"/>
  <user username="dang1" password="dang1" roles="danganshi"/>
  <user username="dang2" password="dang2" roles="danganshi"/>
  <user username="suo1" password="suo1" roles="suozhangshi"/>
  <user username="suo2" password="suo2" roles="suozhangshi"/>
</tomcat-users>

   這個文件已經建立好了,那麼怎麼告訴Tomcat加載這個文件呢?我們通過下面這一種方式,在你的Web應用程序中的META-INF文件夾中加入Context.xml 文件,這樣當此應用程序部署的時候,就會加載該文件的內容,內容如下:

<Context>
  <Realm className="org.apache.catalina.realm.MemoryRealm"
    pathname="webapps/SecurityWeb/WEB-INF/myUsers.xml" />
</Context>

   Realm標籤中className屬性定義了使用MemoryRealm類從pathname處加載xml文件。關於Realm的詳細信息,我們今後找專題研究。還要注意這裏的pathname它是以相對Tomcat根目錄的,所以上文件路徑應該從webapps開始。最後重新啓動服務器再訪問你程序,應該能夠看到和上次相同的效果。

 

 

Module three

上文中myUsers.xml文件的密碼都是以明文的方式存放的,這樣看起來不是十分的安全,我們可以採用加密的方式來進行保存。本例我們採用MD5算法。

   說道MD5算法我們要稍稍多說一點,MD5其實是一種Hash函數,那麼什麼是hash函數呢?hash函數要做的就是給定一個輸入然後計算出一個輸出結果,如果輸入不同那麼結果應該不同的。MD5算法就是一種常用的hash函數,通過MD5算法我們可以給一個字符串計算出一個值,我們把這個值就成爲摘要值。如:字符串“coresun”計算出的摘要值是“2dfb75bf781f454fa2e02048d8e23bd3”。理想情況下一個hash函數所採用的算法是隻能夠通過輸入計算出摘要值,但是通過摘要值是不能夠推斷出原始輸入的,其實MD5就是一個非常不錯的算法。但是這一點我們大家應該記住,2004年山東大學的王小云教授已將此算法破解,令全世界震驚,大漲國人志氣。

   那麼我們怎麼爲一個字符串生成它的摘要值呢?在tomcat中有一個類org.apache.catalina.realm.RealmBase這個類在${CATALINA_HOME}serverlibcatalina.jar中,應用此類還要用到一個通用日誌類org.apache.commons.logging.LogFactory,此類在commons-logging-1.1.jar中,可以到apache的網站上下載。http://commons.apache.org/logging/,準備好兩個jar包之後,將兩個jar包放在一個文件下如(D:lib),然後按如下操作:

  1.設置path環境變量,也就是java命令所在的命令,這個不用我多說了吧。

  2.設置classpath環境變量,如 set classpath=D:catalina.jar;commons-logging-1.1.jar

  3.通過下列命令生成coresun字符串的摘要值:java org.apache.catalina.realm.RealmBase -a MD5 coresun

  稍等片刻,就會看到coresun:2dfb75bf781f454fa2e02048d8e23bd3

  按照同樣的方式將myUsers.xml文件中的密碼都通過此方式計算摘要值。計算完之後用摘要值替換原始值,文件內容如下:

<tomcat-users>
  <role rolename="suozhangshi"/>
  <role rolename="guahaoshi"/>
  <role rolename="danganshi"/>
  <user username="gua2" password="7af209faf16bf686ece05b75f9131080" roles="guahaoshi"/>
  <user username="dang2" password="908aa608050f6a7a7caf0c44c295845b" roles="danganshi"/>
  <user username="suo1" password="f5dc9fddbe2dc1fd2389bc16e096fd51" roles="suozhangshi"/>
  <user username="dang1" password="9bc8a8e63dce56f669b0247a47742ca8" roles="danganshi"/>
  <user username="suo2" password="09d063a79ac6aba2290fcb8e31dd4c81" roles="suozhangshi"/>
  <user username="gua1" password="f4adbb43c78e73a9dcf0dc1a8bb8bb93" roles="guahaoshi"/>
</tomcat-users>

   更改完之後,再將META-INF文件夾下的Context.xml 文件填入下列內容,

<Context>
  <Realm className="org.apache.catalina.realm.MemoryRealm"
         pathname="webapps/SecurityWeb/WEB-INF/myDigestUsers.xml"
         digest="MD5" />
</Context>

   記住web.xml文件的內容不需要更改。重新部署並重新啓動服務器,效果可以是一樣的。

Module four

驗證方法我們前面已經提到了,一共有四種分別是BASIC,DIGEST,FORM,CLIENT-CERT。下面我們分別來介紹一下:

   1、BASIC驗證

   這種驗證方式是比較流行的。當你訪問受保護的資源時會彈出一個對話框,提示你輸入用戶名和口令。用戶名以明文的方式傳送,而密碼則採用一種很容易實現的Base64編碼。由於Base64容易實現,所以這種驗證方法的安全性最低。

   2、DIGEST驗證

   這種驗證是將口令以加密的數字摘要進行傳遞,使用單向散列算法,在服務器端預先存放經過散列處理的口令,與傳送過來的進行對比。由於在實際傳輸的時候傳送的是摘要值,而它又是經過單向散列得來的,所謂單向散列就是通過摘要值是很難推斷出原始值的,所以這種驗證方式要比BASIC驗證方式安全。

   3、FORM驗證

   這種驗證是採用自定義的一個登錄和錯誤頁面來處理驗證。登錄頁面就是一個普通的表單,採用POST方式傳送,所以這種驗證方式安全性也比較低。下面通過一個簡單的實例來了解一下怎樣使用這種驗證方式,如下代碼:

  更改後的web.xml文件

<login-config>
   <auth-method>FORM</auth-method>
   <realm-name>Welcome to Pet hospital</realm-name>
   <form-login-config>
     <form-login-page>/Login.jsp</form-login-page>
     <form-error-page>/Error.jsp</form-error-page>
   </form-login-config>
 </login-config>

  登錄頁面Login.jsp如下:

<form action="j_security_check" method="post">
   userName:<input type="text" name="j_username"><br>
   password:<input type="text" name="j_password"><br>
   <input type="submit" value="authenticate">
</form>

  注意這裏的action值應該是j_security_check,用戶名是j_username,口令是j_password.

  錯誤頁面沒有什麼特別的,隨便寫一些提示信息就可以了。重新部署和啓動服務器測試一下效果,看是不是已經調用了你的登錄頁面。

   4、CLIENT-CERT驗證

數字簽名

   剛剛我們已經知道了如果消息改變了,那麼改變後的消息與原消息的消息摘要一定是不同的。我們將消息和消息摘要分別傳送,如果消息摘要沒有被截獲那麼我們還是可以知道消息是否被更改了,但是如果消息和消息摘要都被截獲的話,那麼我們也不會知道消息是否被篡改了。下面我們看一下數字簽名如何解決這個問題。

   爲了瞭解數字簽名的工作原理,我們有必要先了解一下公共密鑰加密技術。公共密鑰加密技術是基於公共密鑰和私有密鑰這兩個概念的。它的設計思想是你可以將公共密鑰告訴世界上的任何人,但是隻有你才擁有私有密鑰,最重要的是你一定要保護好你的私有密鑰,不要將它告訴任何人。公共密鑰和私有密鑰是有數學關係的,那你可能會擔心,很多人都知道我的公共密鑰,他們根據公鑰密鑰會不會推斷出我的私有密鑰呢?你的擔心是有道理的,但是你大可放心,幾乎是不可能的?這似乎令人難以相信,但直至今日,還沒有人能夠找到一種能夠通過公共密鑰來推斷私有密鑰的方法。所以在目前看來這種技術是絕對安全的,應該完全去信任它。那麼我們怎麼去使用這兩個密鑰呢?非常簡單,如果消息用公共密鑰去加密,那麼只能通過私有密鑰去解密。如果消息用私有密鑰去加密,那麼只能通過公有密鑰去解密。看起來非常簡單,的確它就是這麼簡單。基於這兩句話,公共密鑰加密技術有兩個非常有用的應用:

 1、數據加密

   如果某人給你發送數據,他用你的公共密鑰加密數據,那麼這個數據就只有你能夠看得懂,因爲只有你才擁有私有密鑰。其他人根本無法解密數據。

 2、數據認證

   如果你用私有密鑰加密一個數據,那麼任何持有你公有密鑰的人都可以解密數據,當然這個時候並不是爲了保密數據,而是爲了證明這個數據是不是你發送的。你想想看,如果某人用你的公共密鑰解開了數據,他就會知道這個數據一定是你發送的,因爲通過其他人的公共密鑰是不可能解開數據的。

   通過上面的介紹你應該知道了公共密鑰加密技術的用途了,那麼怎麼產生公共密鑰和私有密鑰呢?有很多的算法,其中比較有名的是RSA和DSA。

   好了,現在我們就可以通過使用公共密鑰加密技術的數字簽名來徹底解決上面的問題了,我們還是用剛纔的字母來舉例:

  1) 你的朋友通過某種軟件產生一對密鑰(公共密鑰和私有密鑰)。

  2)然後你的朋友和你聯繫,將他的公共密鑰告訴你和其他的人。

  3)通過產生的私有密鑰對A加密,產生加密數據,這個加密的數據我們就稱之爲數字簽名,我們用AS表示。

  4)你的朋友將A和AS發送給你,如果發送過程中被竊取了,竊取者將A改爲了   B,現在戲劇性的事情發生了,我們來看看這個竊取者怎麼僞造數字簽名?數字簽名是用私有密鑰來加密數據產生的,這個竊取者根本就沒有你朋友的私有密鑰,因爲私有密鑰沒有在網絡上傳送。如果竊取者也通過一個軟件產生了一對密鑰,然後用他的私有密鑰對B加密產生了新的簽名BS,然後他將B和BS一起發送給你。

  5)這時我們就能夠完全判斷出這個數據的真僞了。怎麼辦?很簡單,我們用你朋友的公共密鑰去解密數據?結果呢?不能解密?因爲這個數據是用竊取者的私有密鑰加密的,要解密當然得使用竊取者的公共密鑰了。

  6)如果A和AS沒有被竊取,那麼你用你朋友的公共密鑰解密,應該是能夠順利解密的,如果不能解密,那麼數據肯定是已經被修改了。

   通過上面的說明大家應該知道,要想安全的傳輸數據,其實也並不是什麼難的事情,所以我們應該大膽的去使用數字簽名。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章