如何⽤JAVA实现CA认证?
如何⽤JAVA实现CA认证?
by fleshwound ( ) (注:这是我们的完整设计中的⼀部分,其它有些部分尚要求保密,希望这个拙⽂能给做J2EE项⽬的兄弟们带来点帮助,有任何关于JAVA安全和密码学理论和应⽤的问题可以来我们的论坛: ) 近年来,随着互连⽹和计算机的普及,电⼦商务和电⼦政务成为当今社会⽣活的重要组成部分,以⽹上订购和⽹上在线⽀付的为主要功能的⽹店系统(Web Shop System)是⽬前电⼦商务的热门技术。 JAVA 以它“⼀次编译,处处运⾏”的神奇魅⼒和强⼤的安全技术⽀持,很快成为WEB信息系统开发的⾸选语⾔,⽽J2EE就是为了WEB应⽤开发⽽诞⽣的。⽬前J2EE的应⽤⼤部份都是多层结构的, 良好的分层可以带来很多好处,例如可以使得代码结构清晰,⽅便组件复⽤,可以快速适应应⽤的新需求。同时,JAVA还提供了强⼤的安全技术(例如:JCA,HTTPS,JSSA等)。对于电⼦商务系统⽽⾔,系统平台的安全性和效率是其中的核⼼问题,⽽这些正好是J2EE及其相关技术的强项。 0 系统中所要使⽤的API及其特点介绍 该系统中主要使⽤的技术和特点如下: (1)EJB :主要是作为J2EE中间层,完成商业逻辑。⽬前主要有三种类型的EJB: 会话 Bean (Session Bean)、实体Bean (Entity Bean)、消息驱动的Bean(MDB); (2)JAAS:在J2EE 中⽤于处理认证和授权服务,进⾏资源控制; (3)JSP和Java Servlets:⽤于J2EE的表⽰层,⽣成⽤户界⾯; (4)JDBC:⽤于数据库(资源层)的连接和与数据库进⾏交互; (5)JNDI:Java命名和⽬录接⼝,该API实际上是⽤来访问
J2EE的所有资源; (6)JMS:Java消息传输服务,配合MDB使⽤。 1 Session的安全问题与解决⽅案 在项⽬中,保存Session⼀般有两种⽅法,⼀是分别放在客户端,⼀是集中放在服务器端。在客户端保存Session是指将Session的状态串⾏化,然后嵌⼊到返回给客户的HTML 页⾯中。当Session中的信息很少时,这样实现⽐较容易,另外这种⽅法还消除了跨越多个服务器复制状态的问题。 但是在客户端保存Session状态时,必须考虑到由此带来的安全问题,因为⿊客可能通过嗅探攻击(Sniffer)获取敏感信息。为了不让敏感信息数据暴露,解决的⽅法是对数据进⾏加密或者使⽤HTTPS,采⽤SSL技术。 如果是要保存⼤量Session状态的应⽤,最好的⽅法是将Session状态统⼀放在服务器端。当状态被保存在服务器上时,不会有客户端Session管理的⼤⼩和类型限制。此外,还避免了由此带来的安全问题,⽽且也不会遇到由于在每个请求间传送Session状态带来的性能影响,但是对服务器的性能要求⽐较⾼。⽹店系统的安全性要求较⾼,因此Session还是集中放在中间层服务器端,同时对客户端到服务器端采⽤SSL连接。 2客户端的缓存安全设计 ⼤部分顾客使⽤的WEB浏览器将浏览过的页⾯缓存在磁盘上,这样我们浏览⽹页的时候不需要重新向服务器发出HTTP请求,对于普通的⽹页不存在安全问题。但是对于需要保密的WEB应⽤,会带来安全隐患和泄漏隐私,因此对于客户端缓存,也必须做适当的处理。最好的⽅法就是禁⽌使⽤缓存,但是对于⼤部分顾客⽽⾔,要求在客户端不⽤缓存是不现实的,因此我们必须在中间层解决该问题,⽅法是采⽤Servlet过滤器技术。该技术是Servlet2.3以后才出现的,在J2EE中的应⽤很⼴泛。要使⽤该技术,需要执⾏以下步骤: (1) 编写⼀个Servlet过滤器,实现
javax.servlet.Filter接⼝; (2) 修改l⽂件,使容器知道过滤器在什么时候被调⽤。 Javax.servlet.Filter主要有3个⽅法:
(1)init(FilterConfig cfg) :当开始使⽤ servlet 过滤器服务时,容器调⽤此⽅法⼀次。传送给此⽅法的 FilterConfig 参数包含 servlet 过滤器的初始化参数; (2)destroy() :当不再使⽤ servlet 过滤器服务时,容器调⽤此⽅法; (3)doFilter(ServletRequest req, ServletResponse res, FilterChain chain): 容器为每个映射⾄此过滤器的 servlet 请求调⽤此⽅法,然后才调⽤该 servlet 本⾝。传送⾄此⽅法的 FilterChain 参数可⽤来调⽤过滤器链中的下⼀个过滤器。当链中的最后⼀个过滤器调⽤ chain.doFilter() ⽅法时,将运⾏最初请求的 servlet。因此,所有过滤器都应该调⽤ chain.doFilter() ⽅法。如果过滤器代码中的附加认证检查导致故障,则不需要将原始 servlet 实例化。在这种情况下,不需要调⽤ chain.doFilter() ⽅法,相反,可将其重定向⾄其它⼀些错误页⾯。 如果 servlet 映射⾄许多 servlet 过滤器,则按照应⽤程序的部署描述符(l)中的先后出现的次序来调⽤ servlet 过滤器。这⼀部分的主要代码如下: //要引⼊的类库 import javax.servlet.*; import javax.servlet.http.HttpServletResponse; import java.io.*; import java.security.*; //设置servlet 过滤代码段 public class CacheFilter implements Filter { protected FilterConfig filterConfig; private String cachetp; //初始化public void init(FilterConfig filterConfig) throws ServletException { this.filterConfig = filterConfig;
InitParameter("CacheControlType"); if (cachetp==null) { throw new ServletException("没有定义Cache控制类型"); } } // public void destroy() { this.filterConfig = null; } //执⾏过滤器部分 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("⾮法相应!"); } chain.doFilter(request, response); } } 以下是在l中添加的对应的内容 CacheFilter CacheFilter Cache filter CacheControlType no-store CacheFilter /cachecontrol 3视图访问的安全设置 所有⽤户都必须登陆,只有登陆才可以看到⽤户的⾓⾊和权限相对应的视图。因此⼀个重要的问题就是如何防⽌⼀个视图或者部分的视图被⼀个未被授权的客户直接访问。 在⼀些情况下,资源被限制为完全不允许某些⽤户访问,例如:管理后台就不应该让普通顾客会员访问。有⼏个⽅法可以做到这⼀点。⼀个⽅法是加⼊应⽤逻辑到处理控制器或者视图的程序中,禁⽌某些⽤户访问。另⼀个⽅案是设置运⾏时的系统,对于⼀些资源,仅允许经由另⼀个应⽤资源内部调⽤。在这种情形,对于这些资源的访问必须被通过另⼀个表现层的应⽤资源进⾏,例如⼀个servlet控制器。对于这些受限制的资源不允许通过浏览器直接调⽤。 在J2EE中,可以利⽤Web容器中内置的安全技术来进⾏⾓⾊访问资源的控制。根据最新版本的s
ervlet和EJB规范,安全限制在l的配置描述⽂件中描述,我们可以通过配置l来控制⾓⾊访问,修改配置描述⽂件l就可以达到快速修改安全策略的⽬的。 安全限制允许使⽤编程的⽅法根据⽤户的⾓⾊来控制访问。资源可以被某些⾓⾊的⽤户访问,同时禁⽌其它的⾓⾊访问。另外,某个视图的⼀部分也可以根据⽤户的⾓⾊来限制其访问。如果某些资源完全不允许来⾃于浏览器的直接访问,那么这些资源可以配置只允许⼀些特殊的安全⾓⾊访问,⽽这些安全⾓⾊不分配给任何⼀个⽤户。这样只要不分配这个安全⾓⾊,那么以这种⽅式配置的资源将禁⽌所有的浏览器直接访问。下⾯⼀个例⼦就是l配置⽂件的⼀部分,它定义了⼀个安全的⾓⾊以限制直接的浏览器访问。⾓⾊的名字是“vip”,受限制资源的名字是specialgood1.jsp、specialgood2.jsp、specialgood3.jsp和bookinfo.jsp。除⾮⼀个⽤户或者组被分配到“vip”⾓⾊,否则这些客户都不可以直接访问这些JSP页⾯。不过,由于内部的请求并不受这些安全的限制,⼀个初始时由某servlet控制器处理的请求将会导向到这些受限制的页⾯,这样它们就可以间接访问这些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>P
OST</http-method> </web-resource-collection> <auth-constraint> <role-name>vip</role-name> </auth-constraint> </security-constraint> 3 各层次间的耦合问题与解决策略 表现层的数据结构,例如HttpServletRequest,应该被限制在表现层上。如果将这些细节放到其它层(主要是业务逻辑层)中,将⼤⼤降低了代码的的重⽤性,令代码变得复杂,并且增加了层间的耦合。解决⽅法⼀个常⽤⽅法是不让表现层的数据结构和商业层共享,⽽是拷贝相关的状态到⼀个更常见的数据结构中再共享。你也可以选择由表现层数据结构中将相关的状态分离出来,作为独⽴的参数共享。另外在域对象暴露表现层的数据结构,如果将诸如HttpServletRequest的请求处理数据结构和域对象共享,这样做也会增加了应⽤中两个不同⽅⾯的耦合。域对象应该是可重⽤的组件,如果它们的实现依赖协议或者层相关的细节,它们可重⽤性就很差,同时维护和调试⾼耦合的应⽤更加困难。成熟的解决⽅案是不通过传送⼀个HttpServletRequest对象作为⼀个参数,⽽是拷贝request对象的状态到⼀个更为常⽤的数据结构中,并且将这个对象共享给域对象。你也可以选择由HttpServletRequest对象中将相关的状态分离出来,并且将每⼀个的状态作为⼀个独⽴的参数提供给域对象。 4 EJB的安全设计与控制 EJB的执⾏过程⼀般是这样的:(1)客户端通过JNDI检索Home对象的引⽤;(2)JNDI返回Home对象的引⽤;(3)请求创建⼀个新的EJB对象;(4)创建EJB对象;(5)返回EJB对象;(6)调⽤商务⽅法;(7)调⽤Enterprise Bean.引起EJB的安全问题原因主要存在三个⽅⾯: (1)⽤包嗅探器(Packet Sniffer)获取⽤户凭证信息并直接调⽤会话Bean;(2)对实体Bean进⾏未授权访问;(3)对消息驱动的Bean的⽆效访问(发布恶意或者虚假的消息). 以上安全问题可导致客户端或者服务端欺骗攻击和DDOS攻击。解决
问题(1)的⽅法是使⽤JAVA中SSL技术来保护通讯,解决(2)的⽅法是对于实体Bean全部采⽤本地接⼝或者采⽤JAAS(⽂献[1]),对于(1)和(2),我们可以同时采取以下措施:让容器完成认证并传输⽤户凭证信息,另外使⽤声明性或者程序设计的安全验证⾓⾊。对于问题(3),J2EE并没有提供⼀个很好的⽅案,我们的解决⽅案是采⽤数字签名技术来保证信息来⾃可信任的源。该⽅法的结合代码简要说明如下,消息采⽤JMS传递: //客户端,要⽤到消息发送者的私钥进⾏签名 ... message.setString("userid",userid); message.setString("useritem",useritem); message.setInt("usersn",serialnum);//包含⼀个序列号 message.setString("usercertid",certid); String
session如何设置和读取
signature=getSignature(userid+":"+useritem+":"+serialnum+":"+certid); //进⾏签名,其中getSignature为签名函数,要⽤到消息发送者的私钥进⾏签名,具体密码学技术可参考⽂献[2]; message.setString("signature",signature); sendmessage(message);//发送信息 ... //服务器端 String checkstr=userid+":"+String("useritem")+":"+ Int("usersn")+":"+usercertid; boolean b_check=checkSignature(String("signature"), usercertid,userid); //进⾏验证,其中checkSignature为验证函数,要⽤到消息发送者的公钥进⾏验证,具体密码学技术可参考⽂献[2]; 5 CA中⼼与证书的⽣成 前⾯我们已经提出在客户端要使⽤HTTPS和SSL,因此要建⽴⼀个⾃⼰的CA中⼼来管理分发证书,加强客户端到中间层服务器端通讯的安全性.建⽴CA中⼼的第⼀步是利⽤JAVA⼯具包中的Keytool⽣成⼀个X509证书,然后将该证书交由权威CA中⼼Vertsign签名,再将该
证书设置为根证书,建⽴⾃⼰的CA.每次有新⽤户注册交易的时候,都必须签发⼀个⽤户独⼀⽆⼆的证书,关键的过程是如何签发证书.签发证书的过程如下: (1)从中间层CA服务器的密钥库中读取CA的证书: FileInputStream in=new FileInputStream(ShopCAstorename); KeyStore
Instance("JKS"); ks.load(in,storepass); Certificate Certificate(alias); (2)获得CA的私钥: PrivateKey caprk=(Key(alias,cakeypass); (3)从CA的证书中提取签发者信息: byte[]
Encoded(); X509CertImpl shopcimp1=new X509CertImpl(encod1); X509CertInfo shopcinfo1=
((X509CertImpl.NAME+ "."+X509CertImpl.INFO); X500Name issuer=
((X509CertInfo.SUBJECT+ "."+CertificateIssuerName.DN_NAME); (4)获取待签发的证书相关信息,与(3)类似; (5)设置新证书的有效期、序列号、签发者和签名算法: //设置新证书有效期为1年 Date begindate =new Date(); Date enddate =new Time()+3000*24*360*60*1000L); CertificateValidity cv=new
CertificateValidity(begindate,enddate); cinfo2.set(X509CertInfo.VALIDITY,cv); //设置新证书序列号 int sn=(int)
(Time()/1000); CertificateSerialNumber csn=new CertificateSerialNumber(sn);
cinfo2.set(X509CertInfo.SERIAL_NUMBER,csn); //设置新证书签发者 cinfo2.set(X509CertInfo.ISSUER+"."+ CertificateIssuerName.DN_NAME,issuer); //设置新证书算法 AlgorithmId algorithm = new
AlgorithmId(AlgorithmId.md5WithRSAEncryption_oid); cinfo2.set(CertificateAlgorithmId.NAME+
"."+CertificateAlgorithmId.ALGORITHM, algorithm); (6)创建证书并签发: // 创建证书 X509CertImpl newcert=new
X509CertImpl(cinfo2); // 签名 newcert.sign(caprk,"MD5WithRSA"); (7)将新证书提供给注册⽤户,并提⽰安装,⼀般的做法是在⽤户注册成功后系统⽴即返回⼀个证书对象给中间层某个Servlet,由其返回给⽤户。 参考⽂献 [1]沈耀,陈昊鹏,李新颜.EJB容器中基于JAAS 的安全机制的实现.[J]:计算机应⽤与软件 2004.9 16~18 [2](美)Jess Garms著,庞南等译. Java安全性编程指南[M].北京:电⼦⼯业出版社2002 [3] [4] 蔡剑,景楠. Java ⽹络程序设计:J2EE(含1.4最新功能)[M].北京: 清华⼤学出版社 2003 [5](美)John Bell Tony Loton. Java Servlets 2.3编程指南[M].北京: 电⼦⼯业出版社 2002 [6](美)Joseph J.Bambara等著,刘堃等译. J2EE技术内幕[M].北京:机械⼯业出版社 2002 [7](美)Li Gong著.JAVA 2平台安全技术——结构、API设计和实现[M].北京: 机械⼯业出版社 2000 [8](英)Danny
Ayers 等著,曾国平等译. Java服务器⾼级编程[M].北京:机械⼯业出版社 2005 [9] [10]

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。