銀色幻想

          導(dǎo)航

          <2006年6月>
          28293031123
          45678910
          11121314151617
          18192021222324
          2526272829301
          2345678

          留言簿(2)

          文章分類(3)

          收藏夾(34)

          隨筆檔案(23)

          文章檔案(3)

          相冊(cè)

          閱讀排行榜

          評(píng)論排行榜

          常用鏈接

          統(tǒng)計(jì)

          積分與排名

          學(xué)習(xí)交流

          最新評(píng)論

          J2EE工程實(shí)現(xiàn)中常見安全問題解決對(duì)策

          by fleshwound (http://www.smatrix.org)
          (注:這是我們的完整設(shè)計(jì)中的一部分,其它有些部分尚要求保密,希望這個(gè)拙文能給做J2EE項(xiàng)目的兄弟們帶來點(diǎn)幫助,有任何關(guān)于JAVA安全和密碼學(xué)理論和應(yīng)用的問題可以來我們的論壇:http://bbs.smatrix.org)
             近年來,隨著互連網(wǎng)和計(jì)算機(jī)的普及,電子商務(wù)和電子政務(wù)成為當(dāng)今社會(huì)生活的重要組成部分,以網(wǎng)上訂購和網(wǎng)上在線支付的為主要功能的網(wǎng)店系統(tǒng)(Web Shop System)是目前電子商務(wù)的熱門技術(shù)。
             JAVA以它“一次編譯,處處運(yùn)行”的神奇魅力和強(qiáng)大的安全技術(shù)支持,很快成為WEB信息系統(tǒng)開發(fā)的首選語言,而J2EE就是為了WEB應(yīng)用開發(fā)而誕生的。目前J2EE的應(yīng)用大部份都是多層結(jié)構(gòu)的, 良好的分層可以帶來很多好處,例如可以使得代碼結(jié)構(gòu)清晰,方便組件復(fù)用,可以快速適應(yīng)應(yīng)用的新需求。同時(shí),JAVA還提供了強(qiáng)大的安全技術(shù)(例如:JCA,HTTPS,JSSA等)。對(duì)于電子商務(wù)系統(tǒng)而言,系統(tǒng)平臺(tái)的安全性和效率是其中的核心問題,而這些正好是J2EE及其相關(guān)技術(shù)的強(qiáng)項(xiàng)。

          0 系統(tǒng)中所要使用的API及其特點(diǎn)介紹
          該系統(tǒng)中主要使用的技術(shù)和特點(diǎn)如下:
          (1)EJB :主要是作為J2EE中間層,完成商業(yè)邏輯。目前主要有三種類型的EJB: 會(huì)話 Bean (Session Bean)、實(shí)體Bean (Entity Bean)、消息驅(qū)動(dòng)的Bean(MDB);
          (2)JAAS:在J2EE 中用于處理認(rèn)證和授權(quán)服務(wù),進(jìn)行資源控制;
          (3)JSP和Java Servlets:用于J2EE的表示層,生成用戶界面;
          (4)JDBC:用于數(shù)據(jù)庫(資源層)的連接和與數(shù)據(jù)庫進(jìn)行交互;
          (5)JNDI:Java命名和目錄接口,該API實(shí)際上是用來訪問J2EE的所有資源;
          (6)JMS:Java消息傳輸服務(wù),配合MDB使用。

          1 Session的安全問題與解決方案
          在項(xiàng)目中,保存Session一般有兩種方法,一是分別放在客戶端,一是集中放在服務(wù)器端。在客戶端保存Session是指將Session的狀態(tài)串行化,然后嵌入到返回給客戶的HTML頁面中。當(dāng)Session中的信息很少時(shí),這樣實(shí)現(xiàn)比較容易,另外這種方法還消除了跨越多個(gè)服務(wù)器復(fù)制狀態(tài)的問題。
            但是在客戶端保存Session狀態(tài)時(shí),必須考慮到由此帶來的安全問題,因?yàn)楹诳涂赡芡ㄟ^嗅探攻擊(Sniffer)獲取敏感信息。為了不讓敏感信息數(shù)據(jù)暴露,解決的方法是對(duì)數(shù)據(jù)進(jìn)行加密或者使用HTTPS,采用SSL技術(shù)。
            如果是要保存大量Session狀態(tài)的應(yīng)用,最好的方法是將Session狀態(tài)統(tǒng)一放在服務(wù)器端。當(dāng)狀態(tài)被保存在服務(wù)器上時(shí),不會(huì)有客戶端Session管理的大小和類型限制。此外,還避免了由此帶來的安全問題,而且也不會(huì)遇到由于在每個(gè)請(qǐng)求間傳送Session狀態(tài)帶來的性能影響,但是對(duì)服務(wù)器的性能要求比較高。網(wǎng)店系統(tǒng)的安全性要求較高,因此Session還是集中放在中間層服務(wù)器端,同時(shí)對(duì)客戶端到服務(wù)器端采用SSL連接。
          2客戶端的緩存安全設(shè)計(jì)
          大部分顧客使用的WEB瀏覽器將瀏覽過的頁面緩存在磁盤上,這樣我們?yōu)g覽網(wǎng)頁的時(shí)候不需要重新向服務(wù)器發(fā)出HTTP請(qǐng)求,對(duì)于普通的網(wǎng)頁不存在安全問題。但是對(duì)于需要保密的WEB應(yīng)用,會(huì)帶來安全隱患和泄漏隱私,因此對(duì)于客戶端緩存,也必須做適當(dāng)?shù)奶幚怼W詈玫姆椒ň褪墙故褂镁彺妫菍?duì)于大部分顧客而言,要求在客戶端不用緩存是不現(xiàn)實(shí)的,因此我們必須在中間層解決該問題,方法是采用Servlet過濾器技術(shù)。該技術(shù)是Servlet2.3以后才出現(xiàn)的,在J2EE中的應(yīng)用很廣泛。要使用該技術(shù),需要執(zhí)行以下步驟:
          (1)    編寫一個(gè)Servlet過濾器,實(shí)現(xiàn)javax.servlet.Filter接口;
          (2)    修改Web.xml文件,使容器知道過濾器在什么時(shí)候被調(diào)用。
          Javax.servlet.Filter主要有3個(gè)方法:
          (1)init(FilterConfig cfg) :當(dāng)開始使用 servlet 過濾器服務(wù)時(shí),容器調(diào)用此方法一次。傳送給此方法的 FilterConfig 參數(shù)包含 servlet 過濾器的初始化參數(shù);
          (2)destroy() :當(dāng)不再使用 servlet 過濾器服務(wù)時(shí),容器調(diào)用此方法;
          (3)doFilter(ServletRequest req, ServletResponse res, FilterChain chain): 容器為每個(gè)映射至此過濾器的 servlet 請(qǐng)求調(diào)用此方法,然后才調(diào)用該 servlet 本身。傳送至此方法的 FilterChain 參數(shù)可用來調(diào)用過濾器鏈中的下一個(gè)過濾器。當(dāng)鏈中的最后一個(gè)過濾器調(diào)用 chain.doFilter() 方法時(shí),將運(yùn)行最初請(qǐng)求的 servlet。因此,所有過濾器都應(yīng)該調(diào)用 chain.doFilter() 方法。如果過濾器代碼中的附加認(rèn)證檢查導(dǎo)致故障,則不需要將原始 servlet 實(shí)例化。在這種情況下,不需要調(diào)用 chain.doFilter() 方法,相反,可將其重定向至其它一些錯(cuò)誤頁面。
          如果 servlet 映射至許多 servlet 過濾器,則按照應(yīng)用程序的部署描述符(web.xml)中的先后出現(xiàn)的次序來調(diào)用 servlet 過濾器。這一部分的主要代碼如下:
          //要引入的類庫
          import javax.servlet.*;
          import javax.servlet.http.HttpServletResponse;
          import java.io.*;
          import java.security.*;
          //設(shè)置servlet過濾代碼段
          public class CacheFilter implements Filter {
          protected FilterConfig filterConfig;
          private String cachetp;
          //初始化
          public void init(FilterConfig filterConfig) throws ServletException
          {
            this.filterConfig = filterConfig;
            cachetp=config.getInitParameter("CacheControlType");
            if (cachetp==null)
            {
            throw new  ServletException("沒有定義Cache控制類型");
            }
          }
          //
          public void destroy()
          {
            this.filterConfig = null;
          }
          //執(zhí)行過濾器部分
          public void doFilter(ServletRequest request,ServletResponse response,FilterChain chain)
          throws IOException, ServletException {
            if (response instanceof HttpServletResponse )
            {
                HttpServletResponse resp=(HttpServletResponse) response;
                resp.addHeader("Cache-Control",cachetp);
            }
            else
            {
              throw new  ServletException("非法相應(yīng)!");
            }
              chain.doFilter(request, response);
            }


          }
          以下是在Web.xml中添加的對(duì)應(yīng)的內(nèi)容

          <filter id="Filter_cache">
            <filter-name>CacheFilter</filter-name>
            <filter-class>CacheFilter</filter-class>
            <description>Cache filter</description>
            <init-param>
              <param-name>CacheControlType</param-name>
              <param-value>no-store</param-value>
            </init-param>
            </filter-id>
          <filter-mapping>
            <filter-name>CacheFilter</filter-name>
            <url-pattern>/cachecontrol</url-pattern>
          </filter-mapping>
          3視圖訪問的安全設(shè)置
            所有用戶都必須登陸,只有登陸才可以看到用戶的角色和權(quán)限相對(duì)應(yīng)的視圖。因此一個(gè)重要的問題就是如何防止一個(gè)視圖或者部分的視圖被一個(gè)未被授權(quán)的客戶直接訪問。
            在一些情況下,資源被限制為完全不允許某些用戶訪問,例如:管理后臺(tái)就不應(yīng)該讓普通顧客會(huì)員訪問。有幾個(gè)方法可以做到這一點(diǎn)。一個(gè)方法是加入應(yīng)用邏輯到處理控制器或者視圖的程序中,禁止某些用戶訪問。另一個(gè)方案是設(shè)置運(yùn)行時(shí)的系統(tǒng),對(duì)于一些資源,僅允許經(jīng)由另一個(gè)應(yīng)用資源內(nèi)部調(diào)用。在這種情形,對(duì)于這些資源的訪問必須被通過另一個(gè)表現(xiàn)層的應(yīng)用資源進(jìn)行,例如一個(gè)servlet控制器。對(duì)于這些受限制的資源不允許通過瀏覽器直接調(diào)用。
            在J2EE中,可以利用Web容器中內(nèi)置的安全技術(shù)來進(jìn)行角色訪問資源的控制。根據(jù)最新版本的servlet和EJB規(guī)范,安全限制在web.xml的配置描述文件中描述,我們可以通過配置web.xml來控制角色訪問,修改配置描述文件web.xml就可以達(dá)到快速修改安全策略的目的。
            安全限制允許使用編程的方法根據(jù)用戶的角色來控制訪問。資源可以被某些角色的用戶訪問,同時(shí)禁止其它的角色訪問。另外,某個(gè)視圖的一部分也可以根據(jù)用戶的角色來限制其訪問。如果某些資源完全不允許來自于瀏覽器的直接訪問,那么這些資源可以配置只允許一些特殊的安全角色訪問,而這些安全角色不分配給任何一個(gè)用戶。這樣只要不分配這個(gè)安全角色,那么以這種方式配置的資源將禁止所有的瀏覽器直接訪問。下面一個(gè)例子就是web.xml配置文件的一部分,它定義了一個(gè)安全的角色以限制直接的瀏覽器訪問。角色的名字是“vip”,受限制資源的名字是specialgood1.jsp、specialgood2.jsp、specialgood3.jsp和bookinfo.jsp。除非一個(gè)用戶或者組被分配到“vip”角色,否則這些客戶都不可以直接訪問這些JSP頁面。不過,由于內(nèi)部的請(qǐng)求并不受這些安全的限制,一個(gè)初始時(shí)由某servlet控制器處理的請(qǐng)求將會(huì)導(dǎo)向到這些受限制的頁面,這樣它們就可以間接訪問這些JSP頁面。
              <security-constraint>
              <web-resource-collection>
              <web-resource-name>specialgood </web-resource-name>
              <description>special good infomation</description>
              <url-pattern>/shop/jsp/a1/specialgood1.jsp</url-pattern>
              <url-pattern>/shop/jsp/a1/specialgood2.jsp</url-pattern>
              <url-pattern>/shop/jsp/a1/specialgood3.jsp</url-pattern>
          <url-pattern>/shop/jsp/a1/bookinfo.jsp</url-pattern>
              <http-method>GET</http-method>
              <http-method>POST</http-method>
              </web-resource-collection>
              <auth-constraint>
              <role-name>vip</role-name>
              </auth-constraint>
              </security-constraint>
          3 各層次間的耦合問題與解決策略
            表現(xiàn)層的數(shù)據(jù)結(jié)構(gòu),例如HttpServletRequest,應(yīng)該被限制在表現(xiàn)層上。如果將這些細(xì)節(jié)放到其它層(主要是業(yè)務(wù)邏輯層)中,將大大降低了代碼的的重用性,令代碼變得復(fù)雜,并且增加了層間的耦合。解決方法一個(gè)常用方法是不讓表現(xiàn)層的數(shù)據(jù)結(jié)構(gòu)和商業(yè)層共享,而是拷貝相關(guān)的狀態(tài)到一個(gè)更常見的數(shù)據(jù)結(jié)構(gòu)中再共享。你也可以選擇由表現(xiàn)層數(shù)據(jù)結(jié)構(gòu)中將相關(guān)的狀態(tài)分離出來,作為獨(dú)立的參數(shù)共享。另外在域?qū)ο蟊┞侗憩F(xiàn)層的數(shù)據(jù)結(jié)構(gòu),如果將諸如HttpServletRequest的請(qǐng)求處理數(shù)據(jù)結(jié)構(gòu)和域?qū)ο蠊蚕恚@樣做也會(huì)增加了應(yīng)用中兩個(gè)不同方面的耦合。域?qū)ο髴?yīng)該是可重用的組件,如果它們的實(shí)現(xiàn)依賴協(xié)議或者層相關(guān)的細(xì)節(jié),它們可重用性就很差,同時(shí)維護(hù)和調(diào)試高耦合的應(yīng)用更加困難。成熟的解決方案是不通過傳送一個(gè)HttpServletRequest對(duì)象作為一個(gè)參數(shù),而是拷貝request對(duì)象的狀態(tài)到一個(gè)更為常用的數(shù)據(jù)結(jié)構(gòu)中,并且將這個(gè)對(duì)象共享給域?qū)ο蟆D阋部梢赃x擇由HttpServletRequest對(duì)象中將相關(guān)的狀態(tài)分離出來,并且將每一個(gè)的狀態(tài)作為一個(gè)獨(dú)立的參數(shù)提供給域?qū)ο蟆?br />4 EJB的安全設(shè)計(jì)與控制
          EJB的執(zhí)行過程一般是這樣的:(1)客戶端通過JNDI檢索Home對(duì)象的引用;(2)JNDI返回Home對(duì)象的引用;(3)請(qǐng)求創(chuàng)建一個(gè)新的EJB對(duì)象;(4)創(chuàng)建EJB對(duì)象;(5)返回EJB對(duì)象;(6)調(diào)用商務(wù)方法;(7)調(diào)用Enterprise Bean.引起EJB的安全問題原因主要存在三個(gè)方面:
          (1)用包嗅探器(Packet Sniffer)獲取用戶憑證信息并直接調(diào)用會(huì)話Bean;(2)對(duì)實(shí)體Bean進(jìn)行未授權(quán)訪問;(3)對(duì)消息驅(qū)動(dòng)的Bean的無效訪問(發(fā)布惡意或者虛假的消息).
          以上安全問題可導(dǎo)致客戶端或者服務(wù)端欺騙攻擊和DDOS攻擊。解決問題(1)的方法是使用JAVA中SSL技術(shù)來保護(hù)通訊,解決(2)的方法是對(duì)于實(shí)體Bean全部采用本地接口或者采用JAAS(文獻(xiàn)[1]),對(duì)于(1)和(2),我們可以同時(shí)采取以下措施:讓容器完成認(rèn)證并傳輸用戶憑證信息,另外使用聲明性或者程序設(shè)計(jì)的安全驗(yàn)證角色。對(duì)于問題(3),J2EE并沒有提供一個(gè)很好的方案,我們的解決方案是采用數(shù)字簽名技術(shù)來保證信息來自可信任的源。該方法的結(jié)合代碼簡要說明如下,消息采用JMS傳遞:
          //客戶端,要用到消息發(fā)送者的私鑰進(jìn)行簽名
          ...
          message.setString("userid",userid);
          message.setString("useritem",useritem);
          message.setInt("usersn",serialnum);//包含一個(gè)序列號(hào)
          message.setString("usercertid",certid);
          String signature=getSignature(userid+":"+useritem+":"+serialnum+":"+certid);
          //進(jìn)行簽名,其中g(shù)etSignature為簽名函數(shù),要用到消息發(fā)送者的私鑰進(jìn)行簽名,具體密碼學(xué)技術(shù)可參考文獻(xiàn)[2];
          message.setString("signature",signature);
          sendmessage(message);//發(fā)送信息
          ...
          //服務(wù)器端
          String checkstr=userid+":"+message.getString("useritem")+":"+
          message.getInt("usersn")+":"+usercertid;
          boolean b_check=checkSignature(checkstr,msg.getString("signature"),
          usercertid,userid);
          //進(jìn)行驗(yàn)證,其中checkSignature為驗(yàn)證函數(shù),要用到消息發(fā)送者的公鑰進(jìn)行驗(yàn)證,具體密碼學(xué)技術(shù)可參考文獻(xiàn)[2];
          5 CA中心與證書的生成
          前面我們已經(jīng)提出在客戶端要使用HTTPS和SSL,因此要建立一個(gè)自己的CA中心來管理分發(fā)證書,加強(qiáng)客戶端到中間層服務(wù)器端通訊的安全性.建立CA中心的第一步是利用JAVA工具包中的Keytool生成一個(gè)X509證書,然后將該證書交由權(quán)威CA中心Vertsign簽名,再將該證書設(shè)置為根證書,建立自己的CA.每次有新用戶注冊(cè)交易的時(shí)候,都必須簽發(fā)一個(gè)用戶獨(dú)一無二的證書,關(guān)鍵的過程是如何簽發(fā)證書.簽發(fā)證書的過程如下:
          (1)從中間層CA服務(wù)器的密鑰庫中讀取CA的證書:
          FileInputStream in=new FileInputStream(ShopCAstorename);
                  KeyStore ks=KeyStore.getInstance("JKS");
                  ks.load(in,storepass);
                  java.security.cert.Certificate c1=ks.getCertificate(alias);
          (2)獲得CA的私鑰:
          PrivateKey caprk=(PrivateKey)ks.getKey(alias,cakeypass);
          (3)從CA的證書中提取簽發(fā)者信息:
          byte[] encod1=c1.getEncoded();
                  X509CertImpl shopcimp1=new X509CertImpl(encod1);
                  X509CertInfo shopcinfo1=(X509CertInfo)shopcimp1.get(X509CertImpl.NAME+
          "."+X509CertImpl.INFO);
                  X500Name issuer=(X500Name)shopcinfo1.get(X509CertInfo.SUBJECT+
          "."+CertificateIssuerName.DN_NAME);
          (4)獲取待簽發(fā)的證書相關(guān)信息,與(3)類似;
          (5)設(shè)置新證書的有效期、序列號(hào)、簽發(fā)者和簽名算法:
          //設(shè)置新證書有效期為1年
                 Date begindate =new Date();
                 Date enddate =new Date(begindate.getTime()+3000*24*360*60*1000L);            CertificateValidity cv=new CertificateValidity(begindate,enddate);
                 cinfo2.set(X509CertInfo.VALIDITY,cv);
               //設(shè)置新證書序列號(hào)
                 int sn=(int)(begindate.getTime()/1000);
                 CertificateSerialNumber csn=new CertificateSerialNumber(sn);
                 cinfo2.set(X509CertInfo.SERIAL_NUMBER,csn);
                 //設(shè)置新證書簽發(fā)者
                 cinfo2.set(X509CertInfo.ISSUER+"."+
          CertificateIssuerName.DN_NAME,issuer);
                    //設(shè)置新證書算法
                 AlgorithmId algorithm =
          new AlgorithmId(AlgorithmId.md5WithRSAEncryption_oid);
                 cinfo2.set(CertificateAlgorithmId.NAME+
          "."+CertificateAlgorithmId.ALGORITHM, algorithm);
          (6)創(chuàng)建證書并簽發(fā):
          // 創(chuàng)建證書
                  X509CertImpl newcert=new X509CertImpl(cinfo2);
                  // 簽名
                  newcert.sign(caprk,"MD5WithRSA");
          (7)將新證書提供給注冊(cè)用戶,并提示安裝,一般的做法是在用戶注冊(cè)成功后系統(tǒng)立即返回一個(gè)證書對(duì)象給中間層某個(gè)Servlet,由其返回給用戶。
                                參考文獻(xiàn)
          [1]沈耀,陳昊鵬,李新顏.EJB容器中基于JAAS 的安全機(jī)制的實(shí)現(xiàn).[J]:計(jì)算機(jī)應(yīng)用與軟件 2004.9 16~18
          [2](美)Jess Garms著,龐南等譯. Java安全性編程指南[M].北京:電子工業(yè)出版社 2002
          [3] http://java.sun.com/j2ee/
          [4] 蔡劍,景楠. Java 網(wǎng)絡(luò)程序設(shè)計(jì):J2EE(含1.4最新功能)[M].北京: 清華大學(xué)出版社 2003
          [5](美)John Bell Tony Loton. Java Servlets 2.3編程指南[M].北京: 電子工業(yè)出版社 2002
          [6](美)Joseph J.Bambara等著,劉堃等譯. J2EE技術(shù)內(nèi)幕[M].北京:機(jī)械工業(yè)出版社 2002
          [7](美)Li Gong著.JAVA 2平臺(tái)安全技術(shù)——結(jié)構(gòu)、API設(shè)計(jì)和實(shí)現(xiàn)[M].北京: 機(jī)械工業(yè)出版社 2000
          [8](英)Danny Ayers等著,曾國平等譯. Java服務(wù)器高級(jí)編程[M].北京:機(jī)械工業(yè)出版社 2005
          [9]http://www.smatrix.org/bbs
          [10]http://www.smatrix.cn/bbs
          (歡迎轉(zhuǎn)載,但需保留作者信息!-by felshwound)

          posted on 2006-06-20 17:35 銀色幻想 閱讀(313) 評(píng)論(0)  編輯  收藏


          只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 彝良县| 昌都县| 古丈县| 武乡县| 湟中县| 旌德县| 咸丰县| 凤翔县| 和龙市| 四会市| 云梦县| 万山特区| 加查县| 平山县| 准格尔旗| 伊川县| 晴隆县| 揭东县| 萍乡市| 葫芦岛市| 西丰县| 金平| 威信县| 太湖县| 丰镇市| 邛崃市| 临漳县| 马关县| 怀仁县| 钦州市| 贡嘎县| 达拉特旗| 滕州市| 吉木乃县| 临城县| 运城市| 漠河县| 大丰市| 江门市| 永仁县| 广南县|