最近在做一个项目,两个异构系统中间需要进行数据交互,老大要求要保证安全性,数据交互方式初定为web service方式,用cxf实现。虽然CXF的WS-Security提供了比较全面的功能,但由于资料可以参考的资料太少,按照官方文档的试了一下没有跑通,就干脆自己做了一个。
异构系统之间的数据交互涉及到两个方面:
(1)传输的数据需要加密。比如从系统A向系统B发送了银行的账号和密码,这些信息是绝对不能在网络传输的过程中被截取到的。
(2)传输的系统间要建立信任关系。如果web service服务器发布了一个接收数据接口,是不能允许第三方不明身份的客户端调用这个接口的。
上述的两个安全性问题在所涉及的系统中,第二个问题比较重要,第一个问题只要不要明文出现就可以了,用一般的对称加密算法就可以了。所以问题的关键在于如何建立客户端和服务器端数据交换的数字证书。
对于数据的加密,目前比较公认的最保险的算法是非对称加密算法。基于非对称加密算法的思想,创建数字证书的思路为:客户端在调用服务器接口传输数据之前,先调用服务器端的一个接口,获取一个公钥;客户端用服务器端传输的公钥对一个共享密码进行加密,制造一个数字证书;服务器用自己保存的私钥和共享密码对证书进行验证。这样做有三个方面可以保证绝对保证安全:(1)服务器端每次产生的公钥和私钥对都是不同的、随机的;(2)共享密码是固定的,只有服务器端和被授权的客户端才知道,攻击方是不知道的;(3)共享密码制作的安全证书每次数据传输都是不同的,是不可伪造和修改无效的。
确定了方案,接下来只需要引入Srping的AOP功能,在客户端调用接口前系统执行安全相关的动作。相关代码如下:
web service 服务器端代码:
(1)服务器端产生公钥的接口:
import javax.jws.WebService;
@WebService
public interface ISignatureEncrp {
public String getIdentityKey()throws Exception;
}
(2)服务器端实现公钥的类
import javax.jws.WebService;
@WebService(endpointInterface = "com.wanmei.wmqc.exclusr.IPasswordEncrp")
public class PasswordEncrpImpl implements ISignatureEncrp{
public String getIdentityKey()throws Exception{
Object[] temp = RSAManager.generaterKey();
if(temp != null && temp.length>1){
ExcluServerConstants.KEY_PAIR_MAP.put(ExcluServerConstants.IDENTITY_KEY_PAIR, temp);
return new String((byte[])temp[1]);
}else{
return null;
}
}
}
(3)RSA算法具体实现类
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Random;
public class RSAManager {
public static Object[] generaterKey() throws Exception{
java.security.KeyPairGenerator keygen = java.security.KeyPairGenerator.getInstance("RSA");
SecureRandom secrand = new SecureRandom();
String seedsur = "abc"; // random seeds.
keygen.initialize(1024, secrand);
KeyPair keys = keygen.genKeyPair();
PublicKey pubkey = keys.getPublic();
PrivateKey prikey = keys.getPrivate();
byte[] pubKey = Base64.encodeToByte(pubkey.getEncoded());
byte[] priKey = Base64.encodeToByte(prikey.getEncoded());
Object[] result = new Object[2];
result[0] = pubKey;
result[1] = priKey;
return result;
}
public static byte[] sign(byte[] priKeyText, String plainText)throws Exception {
PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(
Base64.decode(priKeyText));
KeyFactory keyf = KeyFactory.getInstance("RSA");
PrivateKey prikey = keyf.generatePrivate(priPKCS8);
java.security.Signature signet = java.security.Signature.getInstance("MD5withRSA");
signet.initSign(prikey);
signet.update(plainText.getBytes());
byte[] signed = Base64.encodeToByte(signet.sign());
return signed;
}
public static boolean verify(byte[] pubKeyText, String plainText, byte[] signText) throws Exception{
java.security.spec.X509EncodedKeySpec bobPubKeySpec =
new java.security.spec.X509EncodedKeySpec(Base64.decode(pubKeyText));
java.security.KeyFactory keyFactory = java.security.KeyFactory.getInstance("RSA");
java.security.PublicKey pubKey = keyFactory.generatePublic(bobPubKeySpec);
byte[] signed = Base64.decode(signText);
java.security.Signature signatureChecker = java.security.Signature.getInstance("MD5withRSA");
signatureChecker.initVerify(pubKey);
signatureChecker.update(plainText.getBytes());
if (signatureChecker.verify(signed))
return true;
else
return false;
}
}
(4)beans.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jaxws="http://cxf.apache.org/jaxws"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://cxf.apache.org/jaxws
http://cxf.apache.org/schemas/jaxws.xsd">
<import resource="classpath:META-INF/cxf/cxf.xml" />
<import resource="classpath:META-INF/cxf/cxf-extension-soap.xml" />
<import resource="classpath:META-INF/cxf/cxf-servlet.xml" />
<bean id="serverPasswordCallback"
class="com.**.**.exclusr.ServerPasswordCallback" />
<jaxws:endpoint id="exclusiveUser"
implementor="com.**.**.exclusr.ExclusiveUserImpl" address="/ExclUsr">
<jaxws:inInterceptors>
<bean class="org.apache.cxf.interceptor.LoggingInInterceptor" />
</jaxws:inInterceptors>
</jaxws:endpoint>
<jaxws:endpoint id="signatureEncrp"
implementor="com.**.**.exclusr.SignatureEncrpImpl" address="/PwEncrp">
<jaxws:inInterceptors>
<bean class="org.apache.cxf.interceptor.LoggingInInterceptor" />
</jaxws:inInterceptors>
</jaxws:endpoint>
</beans>
web service客户端代码实现:
(1)公钥调用接口
import javax.jws.WebService;
@WebService
public interface ISignatureEncrp {
public String getIdentityKey()throws Exception;
}
(2)自动执行安全处理的切面类
import java.util.Iterator;
import java.util.List;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Service;
@Service
@Aspect
public class EncrptionAspect {
@Before("execution (* com.**.**.IExclusiveUser.sendSingleUser*(..)) && args(user,commPwd)")
public void doSingleUserFilter(UserInfo user,CommPwdInfo commPwd)throws Exception{
//初始化通讯密码:ExclusiveConstants.COMMUNICATION_PASSWORD
RSAManager.initEncrpClient();
commPwd.setCommunicationPwd(ExclusiveConstants.COMMUNICATION_PASSWORD);
}
}
(3)RSA实现类
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.List;
public class RSAManager {
public static byte[] sign(byte[] priKeyText, String plainText)throws Exception {
PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec
(Base64.decode(ExclusiveConstants.IDENTITY_PRIVATE_KEY.getBytes()));
KeyFactory keyf = KeyFactory.getInstance("RSA");
PrivateKey prikey = keyf.generatePrivate(priPKCS8);
java.security.Signature signet = java.security.Signature.getInstance("MD5withRSA");
signet.initSign(prikey);
signet.update(plainText.getBytes());
byte[] signed = Base64.encodeToByte(signet.sign());
return signed;
}
public static void initEncrpClient()throws Exception{
IPasswordEncrp iencrp = (IPasswordEncrp)ExclusiveConstants.APPLICATION_CONTEXT
.getBean(ExclusiveConstants.PASSWORD_ENCRP_INTERFACE);
try {
String priKey = iencrp.getIdentityKey();
ExclusiveConstants.IDENTITY_PRIVATE_KEY = priKey;
String password = new String(RSAManager.sign(priKey.getBytes(), ExclusiveConstants.IDENTITY_PASSWORD));
ExclusiveConstants.COMMUNICATION_PASSWORD = password;
} catch (Exception e1) {
e1.printStackTrace();
}
}
}
(4)aop配置
<?xml version="1.0" encoding="UTF-8"?>
<!--
Application context definition for PetClinic on Hibernate.
-->
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context"
xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.5.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
<context:component-scan base-package="com.**.**.exclusr"/>
<context:annotation-config/>
<aop:aspectj-autoproxy/>
</beans>
(5)client-beans.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:jaxws="http://cxf.apache.org/jaxws"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://cxf.apache.org/jaxws
http://cxf.apache.org/schemas/jaxws.xsd" >
<jaxws:client id="pwEncrp"
serviceClass="com.**.**.exclusr.IPasswordEncrp"
address="http://127.0.0.1:8080/ws/PwEncrp" >
<!--If the LoggingOutInterceptor is useless for you, you can delete it. -->
<jaxws:outInterceptors>
<bean class="org.apache.cxf.interceptor.LoggingOutInterceptor" />
</jaxws:outInterceptors>
<!-- End LoggingOutInterceptor -->
</jaxws:client>
<jaxws:client id="exclUsrClient"
serviceClass="com.**.**.exclusr.IExclusiveUser"
address="http://127.0.0.1:8080/ws/ExclUsr" >
<!--If the LoggingOutInterceptor is useless for you, you can delete it. -->
<jaxws:outInterceptors>
<bean class="org.apache.cxf.interceptor.LoggingOutInterceptor" />
</jaxws:outInterceptors>
<!-- End LoggingOutInterceptor -->
</jaxws:client>
<bean id="clientPasswordCallback" class="com.**.**.exclusr.ClientPasswordCallback" />
</beans>
相关推荐
1)参考: ...2)CXFWS工程是基于WS-Security规范,实现X.509身份验证的,同时实现签名和加密 keytool 工具的使用参考 http://hi.baidu.com/qianshuifanchuan/blog/item/6291b8510009ad3c42a75b8e.html ...
纯java调用ws-security+CXF实现的webservice安全接口
赠送jar包:cxf-rt-ws-addr-3.0.1.jar; 赠送原API文档:cxf-rt-ws-addr-3.0.1-javadoc.jar; 赠送源代码:cxf-rt-ws-addr-3.0.1-sources.jar; 赠送Maven依赖信息文件:cxf-rt-ws-addr-3.0.1.pom; 包含翻译后的API...
cxf结合ws-security实现webservice 用户名/密码身份认证安全调用,依赖包
赠送jar包:cxf-rt-ws-policy-3.0.1.jar; 赠送原API文档:cxf-rt-ws-policy-3.0.1-javadoc.jar; 赠送源代码:cxf-rt-ws-policy-3.0.1-sources.jar; 赠送Maven依赖信息文件:cxf-rt-ws-policy-3.0.1.pom; 包含...
经过了几天的努力与查询不少的资料与调试,头都大了,终于给CXF加上了一把密码锁,希望进步;
cxf ws-Security的实现 WS-SecurityPolicy 安全配置指定在客户机和服务之间交换的消息所需的安全处理。在大多数情况下,Web 服务堆栈还需要更多信息,才能对消息交换应用安全措施。 里面有2个project,分别server ...
赠送jar包:cxf-rt-transports-http-3.0.1.jar; 赠送原API文档:cxf-rt-transports-http-3.0.1-javadoc.jar; 赠送源代码:cxf-rt-transports-http-3.0.1-sources.jar; 赠送Maven依赖信息文件:cxf-rt-transports-...
赠送jar包:cxf-rt-frontend-simple-3.0.1.jar; 赠送原API文档:cxf-rt-frontend-simple-3.0.1-javadoc.jar; 赠送源代码:cxf-rt-frontend-simple-3.0.1-sources.jar; 赠送Maven依赖信息文件:cxf-rt-frontend-...
赠送jar包:cxf-rt-bindings-soap-3.0.1.jar; 赠送原API文档:cxf-rt-bindings-soap-3.0.1-javadoc.jar; 赠送源代码:cxf-rt-bindings-soap-3.0.1-sources.jar; 赠送Maven依赖信息文件:cxf-rt-bindings-soap-...
CXF使用WSS4J实现WS-Security规范,本例的配置是Timestamp Signature Encrypt,具体使用可以参考我的博客http://blog.csdn.net/wangchsh2008/article/details/6708270
赠送jar包:cxf-core-3.0.1.jar; 赠送原API文档:cxf-core-3.0.1-javadoc.jar; 赠送源代码:cxf-core-3.0.1-sources.jar; 赠送Maven依赖信息文件:cxf-core-3.0.1.pom; 包含翻译后的API文档:cxf-core-3.0.1-...
CXF WS-Security WSS4J 例子 可以运行,运行的时候只要运行client就行,重点是运行完之后要关掉第一个控制台,才能看到结果。一定要记得改一下client的路径名
赠送jar包:cxf-rt-frontend-jaxws-3.0.1.jar; 赠送原API文档:cxf-rt-frontend-jaxws-3.0.1-javadoc.jar; 赠送源代码:cxf-rt-frontend-jaxws-3.0.1-sources.jar; 赠送Maven依赖信息文件:cxf-rt-frontend-jaxws...
udp-3.0.11.jar,cxf-rt-wsdl-3.0.0.jar,cxf-rt-ws-security-3.0.0.jar,neethi-3.0.3.jar,slf4j-api-1.7.7.jar,stax2-api-3.1.4.jar,woodstox-core-asl-4.4.1.jar,wsdl4j-1.6.3.jar,wss4j-bindings-2.0.9.jar,xml...
赠送jar包:cxf-rt-frontend-jaxrs-3.0.1.jar; 赠送原API文档:cxf-rt-frontend-jaxrs-3.0.1-javadoc.jar; 赠送源代码:cxf-rt-frontend-jaxrs-3.0.1-sources.jar; 赠送Maven依赖信息文件:cxf-rt-frontend-jaxrs...
<import resource="classpath:META-INF/cxf/cxf.xml"/> <import resource="classpath:META-INF/cxf/cxf-extension-soap.xml"/> <import resource="classpath:META-INF/cxf/cxf-servlet.xml"/>
赠送jar包:cxf-rt-rs-client-3.0.1.jar; 赠送原API文档:cxf-rt-rs-client-3.0.1-javadoc.jar; 赠送源代码:cxf-rt-rs-client-3.0.1-sources.jar; 赠送Maven依赖信息文件:cxf-rt-rs-client-3.0.1.pom; 包含...
赠送jar包:cxf-rt-bindings-xml-3.0.1.jar; 赠送原API文档:cxf-rt-bindings-xml-3.0.1-javadoc.jar; 赠送源代码:cxf-rt-bindings-xml-3.0.1-sources.jar; 赠送Maven依赖信息文件:cxf-rt-bindings-xml-3.0.1....
cxf-rt-frontend-jaxws-3.0.16.jar jar包下载3.0.16版本下载