webservice高级,安全(附带实例)
最简单的安全方案J2EE容器端的WebService,是由Servlet来提供的,以Metro为例,所有的webservice请求都是由com.sun.xml.ws.transport.http.servlet.WSServlet处理的。所以,最简单的方法,便是将安全问题交给web容器来处理。比如,使用HTTPs保证消息传输安全,使用BA来保证认证与授权。 使用此种方案,首先需要配置容器,开启SSL端口,如http://my.oschina.net/xpbug/blog/204794#OSC_h3_5?一段展示了如何开启tomcat的SSL端口 。其次,需要配置容器BA认证与授权机制,如http://my.oschina.net/xpbug/blog/198765,文章展示了如何配置tomcat容器的安全?。前面均是针对容器所做的配置,针对WebServiceClient,我们还需要按照BA的格式,将用户名和密码放置到HTTP header中。 下面一段代码展示了如何将用户名和密码以BA的形式放入HTTP header中。 public?class?WsClient{ ? ????//Because?of?BA,?we?can't?parse?wsdl?"http://localhost:8080/WebServiceExample/user.wsdl"?directly ????//save?it?as?local?file,?and?parse?it ????private?static?final?String?WS_URL?=?"file:c://user.wsdl"; ? ????public?static?void?main(String[]?args)?throws?Exception?{ ? ????URL?url?=?new?URL(WS_URL); ????????QName?qname?=?new?QName("http://mycompany.com/",?"TestImplService"); ? ????????Service?service?=?Service.create(url,?qname); ????????Test?port?=?service.getPort(Test.class); ? ????????//add?username?and?password?for?container?authentication ????????BindingProvider?bp?=?(BindingProvider)?port; ????????bp.getRequestContext().put(BindingProvider.USERNAME_PROPERTY,?"mkyong"); ????????bp.getRequestContext().put(BindingProvider.PASSWORD_PROPERTY,?"123456"); ? ????????System.out.println(port.doSth()); ????} } 最简单的安全存在着很多缺陷,无法发挥webservice的全部特性,缺陷有下:
综上所述,最简单的安全方案可以用在消息并不敏感的服务商中,如果针对银行,那还是需要更加复杂的安全方案。 专门针对WebService的安全方案Metro实现了WS-Security,WS-SecureConversation和WS-Trust等设计安全的规范。其复杂性自不必说,我对此也是一知半解。需要深入了解的时候,还是需要去读文档说明。但安全,总是无外乎这么一个过程: 1, 签名,接收端可以验证签名,以检验消息是否被修改过。 2, 加密,对消息整体进行加密,保证消息不会泄露。任何中介都无法解析原始消息。如果有恶意中介篡改加密后的消息,但它却给出正确的加密签名。使用第一项便可验证处消息被篡改过。 3, 用户名与密码验证。在传输过程中,将用户名密码放入header中,再进行加密。服务器端可以拿到用户密码,并加以验证。 4, 使用证书。 WS-Security可以不依赖传输协议,完全实现SOAP消息的自包含式安全,它对SOAP消息体签名,把签名放到SOAP header中,可以把用户信息放入SOAP header中,最后可以对部分SOAP消系进行加密。WS-Security很复杂,它也提供了非常繁多的安全解决机制。不过好在NetBeans帮我们简化了这部分的开发。 首先看下,Metro提供了多少安全组合方案: 服务端: 客户端 各种组合的解释可以在这个网站获得:https://metro.java.net/guide/ch12.html#ahicu? 我们不可能在真正使用之前全部掌握所有的安全机制,只可能了解每一个机制的特点,当真正需要用到时,再一边看文档,一边实现。 接下来,我选取上面安全机制中的第一个,来做一个实验。使用Username Authentication with Symmetric Key (UA)。 对称密钥用户认证原理原英文名叫Username Authentication with Symmetric Key (UA),我把它翻译成使用对称密钥及用户认证的安全机制 作为WS-Security安全机制的一种,此种机制是一种最常见的加密方法。其效率要比非对称加密算法要高很多。它的原理如下:
接下来,我将对此做实现。 必备软件最新NetBeans IDE. Glassfish4 JDK7 由于Glassfish4本身就自带Metro2.3,比Tomcat更容易使用,所以选择Glassfish4作为服务器。而NetBeans又是开发Metro WebService的利器。 创建账户向Glassfish中添加账号。启动Glassfish,打开控制台:http://localhost:4848/? 展开Configurations->Default Config -> Security ->Realms->File 在此页面上,点击Manage Users按钮,添加一个用户:{name: xpbug,?group: test,password: test} 确保Glassfish使用的是File Realm做认证。 创建服务器端数字证书Glassfish的keystore和trustStore在domain下的config目录中,例如C:glassfish4glassfishdomainsdomain1config。 其中keystore为keystore.jks,而trustStore为cacerts.jks. 对于服务器端,我们不需要去管trustStore。 在glassfish keystore目录下面,使用命令,创建证书: keytool?-genkey?-alias?myWebService?-keyalg?RSA?-keysize?1024?-keystore?keystore.jks?-validity?365 keystore.jks的默认密码为changeit 注意,在填写First and Last name或者是Common name的时候,需要填写网站的域名。否则证书无法工作。 注意,生成数字证书的密码必须使用跟keystore相同的密码,这是glassfish的一个limitation,否则,glassfish会启动失败。这里有解释:http://weblogs.java.net/blog/kumarjayanti/archive/2007/11/ssl_and_crl_che.html? 导出证书需要将服务器端的数字证书导出,证书中含有公钥。此证书将为客户端所用。在服务器的keystore目录下,运行命令: keytool?-export?-alias?myWebService?-file?my.cer?-keystore?keystore.jks 创建WebService使用NetBeans创建一个Java Web项目,取名为Test。 然后右键点击项目,创建一个Web Service。取名为Say。SEI中将默认产生一个hello方法。我们就用它做实验。 右键点击生成的webservice,选择Edit Web Service Attributes. 按照下图填写: 点击Keystore按钮,在弹出的对话框中填写你的keystore,密码,证书alias,以及证书的密码: 右键点击项目,点击deploy。 访问http://localhost:8080/Test/Say?看WebService是否部署成功。运行http://localhost:8080/Test/Say?Tester?,网站会报告webservice被加密,无法运行tester的信息。 创建客户端在NetBeans中,创建一个Java项目。然后再项目中,创建Web Service Client。WSDL的地址为?http://localhost:8080/Test/Say?wsdl 当项目编译完成以后,客户端endport的java 类已经完全在项目中了,接下来,在Library中加入Metro2 在main函数中调用endport。 public?class?JavaApplication1?{ ????public?static?void?main(String[]?args)?{ ????????Say?port?=?new?Say_Service().getSayPort(); ????????System.out.println(port.hello("test")); ????} } 运行项目,会发现运行错误。SOAP header无法解析。 原因在于我还没有导入server的证书。 首先,服务器的证书my.cert导入到客户端的truststore中。使用命令: keytool?-import?-alias?myWebService?-file?my.cer?-keystore?d:/clientTrustStore.jks?-storepass?testit 将my.cer导入到我的truststore中,如果store不存在,则自动创建。 然后,在NetBeans中,右键点击客户端项目中的web service 在弹出的菜单中选择Edit Web Service Attributes. 在QoS面板下的Security一栏中,点击Truststore. 填写上刚刚创建好的truststore的信息。 接着,在用户栏中使用Glassfish Realm中的账号。 运行项目,这次可以看到:
在glassfish的domain.xml中,添加 <jvm-options>-Dcom.sun.xml.ws.transport.http.HttpAdapter.dump=true</jvm-options> 可以在log中看到SOAP消息的进出记录。 ??---[HTTP?request]--- accept:?text/xml,?multipart/related connection:?keep-alive content-length:?8202 content-type:?text/xml;charset=utf-8 host:?localhost:8080 soapaction:?"http://my.com/Say/helloRequest" user-agent:?JAX-WS?RI?2.2-hudson-740- 【SOAP?message】 自己去查看,会发现所有的内容均被加密。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |