webService的soap风格的接口的安全问题
2017-09-13 01:45
441 查看
ws接口的安全问题
1 接口调用者身份验证问题
Rsa:私钥加密,公钥解密
Cxf:usernameToken
Cxf:安全令牌拦截器
1) 在cxf发布的接口中服务中,加入安全拦截器(在spring配置文件中发布的服务中加入拦截器)实例代码如下:
<!-- 自定义一个回调函数来处理安全令牌的校验这个类要继承CallbackHandler类 -->
<bean id="myPasswordCallBack" class="com.util.MyPasswordCallBack"></bean>
<!-- 例如在发布的UserService的服务接口中添加拦截器WSS4JInInterceptor然后进行构造注入在map中依次放入安全令牌,用户密码,以及回调函数,注意这三个属性要在ConfigurationConstants常量类中去赋值避免写错 -->
<jaxws:endpoint address="/user" implementorClass="com.service.UserService">
<jaxws:inInterceptors>
<bean class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor">
<constructor-arg>
<map>
<entry key="action" value="UsernameToken"></entry>
<entry key="passwordType" value="PasswordText"></entry>
<entry key="passwordCallbackRef" >
<ref bean="myPasswordCallBack"/>
</entry>
</map>
</constructor-arg>
</bean>
</jaxws:inInterceptors>
<jaxws:implementor>
<bean class="com.service.UserServiceImpl"></bean>
</jaxws:implementor>
</jaxws:endpoint>
2.)编写回调函数的类,示例代码如下:
package com.util;
import java.io.IOException;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;
import org.apache.wss4j.common.ext.WSPasswordCallback;
import org.eclipse.jetty.util.security.Password;
public class MyPasswordCallBack implements CallbackHandler {
@Override
public void handle(Callback[] callbacks) throws IOException,UnsupportedCallbackException {
WSPasswordCallback wsPasswordCallback = (WSPasswordCallback) callbacks[0];
String identifier = wsPasswordCallback.getIdentifier();
String password = "";
if (identifier.equals("cxf")) {
password = "wss4j";
}
wsPasswordCallback.setPassword(password);
}
}
如此一来在服务端发布的接口就带有了校验安全令牌的功能
那么现在无论是在客户端访问该接口还是用SOAPUI工具访问该接口都会失败
但是应该怎么访问?
一.SOAPUI工具访问方式:在<soapenv:Header>中加入用户名和密码
即:
<soapenv:Header>
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsse:UsernameToken >
<wsse:Username>cxf</wsse:Username>
<wsse:Password
Type= "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">wss4j</wsse:Password>
</wsse:UsernameToken>
</wsse:Security>
</soapenv:Header>
二.如何在客户端访问?
①编写回调函数,示例代码如下:
package com.util;
import java.io.IOException;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;
import org.apache.wss4j.common.ext.WSPasswordCallback;
public class MyPasswordCallBack implements CallbackHandler{
@Override
public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException{
WSPasswordCallback wsPasswordCallback = (WSPasswordCallback) callbacks[0];
wsPasswordCallback.setIdentifier("cxf");
wsPasswordCallback.setPassword("wss4j");
}
}
②在create()方法前加入拦截器并设置参数,示例代码如下:
package com.test;
import java.util.HashMap;
import java.util.Map;
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
import org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor;
import org.apache.wss4j.dom.handler.WSHandlerConstants;
import com.bean.T_MALL_USER_ACCOUNT;
import com.service.UserService;
import com.util.MyPasswordCallBack;
public class WsTest {
public static void main(String[] args) {
JaxWsProxyFactoryBean jaxWsProxyFactoryBean = new JaxWsProxyFactoryBean();
jaxWsProxyFactoryBean.setAddress("http://localhost:8080/mall_0417_user_student/user?wsdl");
jaxWsProxyFactoryBean.setServiceClass(UserService.class);
//添加拦截器并在拦截器中设置参数
Map<String,Object> map = new HashMap<String,Object>();
map.put("action", "UsernameToken");
map.put("passwordType", "PasswordText");
map.put("user", "user");
map.put(WSHandlerConstants.PW_CALLBACK_CLASS, MyPasswordCallBack.class.getName());
WSS4JOutInterceptor wss4jOutInterceptor = new WSS4JOutInterceptor(map);
//将设置好的拦截器加入jaxWsProxyFactoryBean中
jaxWsProxyFactoryBean.getOutInterceptors().add(wss4jOutInterceptor);
//注意要在create()方法前添加拦截器
UserService userService = (UserService) jaxWsProxyFactoryBean.create();
T_MALL_USER_ACCOUNT user = new T_MALL_USER_ACCOUNT();
user.setYh_mch("admin");
user.setYh_mm("123456");
T_MALL_USER_ACCOUNT login = userService.login(user );
System.out.println(login);
}
}
2. 接口传输数据信息的加密问题
Rsa:公钥加密,私钥解密
Cxf:对于信息本身可以再用md5进行加密
①写一个加密工具类MyDateUtil示例代码如下:
package com.util;
import java.text.SimpleDateFormat;
import java.util.Date;
public class MyDateUtil {
public static String getMd5(String param){
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMddHHmm");
String format = simpleDateFormat.format(new Date());
String md5 = MD5Util.md5(param + format);
return md5;
}
}
package com.util;
import java.security.MessageDigest;
public class MD5Util {
public static String md5(String string) {
if (string == null || string.trim().length() < 1) {
return null;
}
try {
//注意一定要统一编码格式,否则如果客户端与服务端的编码格式不同很有可 能产生的加密串不同
byte[] bytes = string.getBytes("iso-8859-1");
String string2 = new String(bytes, "utf-8");
return getMD5(string2.getBytes());
} catch (Exception e) {
throw new RuntimeException(e.getMessage(), e);
}
}
public static String getMD5(byte[] source) {
try {
MessageDigest md5 = MessageDigest.getInstance("MD5");
StringBuffer result = new StringBuffer();
for (byte b : md5.digest(source)) {
result.append(Integer.toHexString((b & 0xf0) >>> 4));
result.append(Integer.toHexString(b & 0x0f));
}
return result.toString();
} catch (Exception e) {
throw new RuntimeException(e.getMessage(), e);
}
}
}
②在客户端的加密操作要在setPassword前,示例代码如下:
package com.util;
import java.io.IOException;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;
import org.apache.wss4j.common.ext.WSPasswordCallback;
public class MyPasswordCallBack implements CallbackHandler{
@Override
public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException{
UnsupportedCallbackException {
WSPasswordCallback wsPasswordCallback = (WSPasswordCallback) callbacks[0];
wsPasswordCallback.setIdentifier("cxf");
String password = "wss4j";
password = MyDateUtil.getMd5(password);
wsPasswordCallback.setPassword(password);
}
}
③在服务端的加密操作也要在setPassword之前,示例代码如下:
import java.io.IOException;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;
import org.apache.wss4j.common.ext.WSPasswordCallback;
public class MyPasswordCallBack implements CallbackHandler {
@Override
public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException{
WSPasswordCallback wsPasswordCallback = (WSPasswordCallback) callbacks[0];
String identifier = wsPasswordCallback.getIdentifier();
String password = "";
if (identifier.equals("cxf")) {
password = "wss4j";
password = MyDateUtil.getMd5(password);
}
wsPasswordCallback.setPassword(password);
}
}
④注意为什么客户端与服务端都是wsPasswordCallback.setPassword(password)
那是因为密码校验的工作是交由cxf框架自己来比较的,我们只需要在客户端放入密码
服务端也放入密码,框架底层自会完成两端传入的密码是否一致。
1 接口调用者身份验证问题
Rsa:私钥加密,公钥解密
Cxf:usernameToken
1 在请求中加入wsse的安全协议 2 在wsse中用安全令牌(用户名/密码)来验证用户的身份 3 cxf在发送和接受ws的soap请求时,在框架中加入回掉函数来处理安全令牌的校验 4 如何安全令牌信息放入请求信息中,和服务器上如何在调用方法时拦截并且校验请求这的身份信息 |
Cxf:安全令牌拦截器
1) 在cxf发布的接口中服务中,加入安全拦截器(在spring配置文件中发布的服务中加入拦截器)实例代码如下:
<!-- 自定义一个回调函数来处理安全令牌的校验这个类要继承CallbackHandler类 -->
<bean id="myPasswordCallBack" class="com.util.MyPasswordCallBack"></bean>
<!-- 例如在发布的UserService的服务接口中添加拦截器WSS4JInInterceptor然后进行构造注入在map中依次放入安全令牌,用户密码,以及回调函数,注意这三个属性要在ConfigurationConstants常量类中去赋值避免写错 -->
<jaxws:endpoint address="/user" implementorClass="com.service.UserService">
<jaxws:inInterceptors>
<bean class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor">
<constructor-arg>
<map>
<entry key="action" value="UsernameToken"></entry>
<entry key="passwordType" value="PasswordText"></entry>
<entry key="passwordCallbackRef" >
<ref bean="myPasswordCallBack"/>
</entry>
</map>
</constructor-arg>
</bean>
</jaxws:inInterceptors>
<jaxws:implementor>
<bean class="com.service.UserServiceImpl"></bean>
</jaxws:implementor>
</jaxws:endpoint>
2.)编写回调函数的类,示例代码如下:
package com.util;
import java.io.IOException;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;
import org.apache.wss4j.common.ext.WSPasswordCallback;
import org.eclipse.jetty.util.security.Password;
public class MyPasswordCallBack implements CallbackHandler {
@Override
public void handle(Callback[] callbacks) throws IOException,UnsupportedCallbackException {
WSPasswordCallback wsPasswordCallback = (WSPasswordCallback) callbacks[0];
String identifier = wsPasswordCallback.getIdentifier();
String password = "";
if (identifier.equals("cxf")) {
password = "wss4j";
}
wsPasswordCallback.setPassword(password);
}
}
如此一来在服务端发布的接口就带有了校验安全令牌的功能
那么现在无论是在客户端访问该接口还是用SOAPUI工具访问该接口都会失败
但是应该怎么访问?
一.SOAPUI工具访问方式:在<soapenv:Header>中加入用户名和密码
即:
<soapenv:Header>
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsse:UsernameToken >
<wsse:Username>cxf</wsse:Username>
<wsse:Password
Type= "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">wss4j</wsse:Password>
</wsse:UsernameToken>
</wsse:Security>
</soapenv:Header>
二.如何在客户端访问?
①编写回调函数,示例代码如下:
package com.util;
import java.io.IOException;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;
import org.apache.wss4j.common.ext.WSPasswordCallback;
public class MyPasswordCallBack implements CallbackHandler{
@Override
public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException{
WSPasswordCallback wsPasswordCallback = (WSPasswordCallback) callbacks[0];
wsPasswordCallback.setIdentifier("cxf");
wsPasswordCallback.setPassword("wss4j");
}
}
②在create()方法前加入拦截器并设置参数,示例代码如下:
package com.test;
import java.util.HashMap;
import java.util.Map;
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
import org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor;
import org.apache.wss4j.dom.handler.WSHandlerConstants;
import com.bean.T_MALL_USER_ACCOUNT;
import com.service.UserService;
import com.util.MyPasswordCallBack;
public class WsTest {
public static void main(String[] args) {
JaxWsProxyFactoryBean jaxWsProxyFactoryBean = new JaxWsProxyFactoryBean();
jaxWsProxyFactoryBean.setAddress("http://localhost:8080/mall_0417_user_student/user?wsdl");
jaxWsProxyFactoryBean.setServiceClass(UserService.class);
//添加拦截器并在拦截器中设置参数
Map<String,Object> map = new HashMap<String,Object>();
map.put("action", "UsernameToken");
map.put("passwordType", "PasswordText");
map.put("user", "user");
map.put(WSHandlerConstants.PW_CALLBACK_CLASS, MyPasswordCallBack.class.getName());
WSS4JOutInterceptor wss4jOutInterceptor = new WSS4JOutInterceptor(map);
//将设置好的拦截器加入jaxWsProxyFactoryBean中
jaxWsProxyFactoryBean.getOutInterceptors().add(wss4jOutInterceptor);
//注意要在create()方法前添加拦截器
UserService userService = (UserService) jaxWsProxyFactoryBean.create();
T_MALL_USER_ACCOUNT user = new T_MALL_USER_ACCOUNT();
user.setYh_mch("admin");
user.setYh_mm("123456");
T_MALL_USER_ACCOUNT login = userService.login(user );
System.out.println(login);
}
}
2. 接口传输数据信息的加密问题
Rsa:公钥加密,私钥解密
Cxf:对于信息本身可以再用md5进行加密
1 服务器与客户端双方约定加密协议 2 按照加密协议(可以加入时间戳),对密码信息进行加密 3 ①保证密码不被窃取,②保证密码过期时间,防止replay攻击 4 用时间戳固然好但是有一个问题,如果客户端的系统时间与服务端的系统时间不一致也会出现加密串不同,那此时有两种解决方案:①客户端是服务端做一个同步心跳②也可以在客户端发送的请求中携带时间戳,然后服务端根据加密协议去部分时间的内容进行加密这样一来就可以达到同步了 |
package com.util;
import java.text.SimpleDateFormat;
import java.util.Date;
public class MyDateUtil {
public static String getMd5(String param){
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMddHHmm");
String format = simpleDateFormat.format(new Date());
String md5 = MD5Util.md5(param + format);
return md5;
}
}
package com.util;
import java.security.MessageDigest;
public class MD5Util {
public static String md5(String string) {
if (string == null || string.trim().length() < 1) {
return null;
}
try {
//注意一定要统一编码格式,否则如果客户端与服务端的编码格式不同很有可 能产生的加密串不同
byte[] bytes = string.getBytes("iso-8859-1");
String string2 = new String(bytes, "utf-8");
return getMD5(string2.getBytes());
} catch (Exception e) {
throw new RuntimeException(e.getMessage(), e);
}
}
public static String getMD5(byte[] source) {
try {
MessageDigest md5 = MessageDigest.getInstance("MD5");
StringBuffer result = new StringBuffer();
for (byte b : md5.digest(source)) {
result.append(Integer.toHexString((b & 0xf0) >>> 4));
result.append(Integer.toHexString(b & 0x0f));
}
return result.toString();
} catch (Exception e) {
throw new RuntimeException(e.getMessage(), e);
}
}
}
②在客户端的加密操作要在setPassword前,示例代码如下:
package com.util;
import java.io.IOException;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;
import org.apache.wss4j.common.ext.WSPasswordCallback;
public class MyPasswordCallBack implements CallbackHandler{
@Override
public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException{
UnsupportedCallbackException {
WSPasswordCallback wsPasswordCallback = (WSPasswordCallback) callbacks[0];
wsPasswordCallback.setIdentifier("cxf");
String password = "wss4j";
password = MyDateUtil.getMd5(password);
wsPasswordCallback.setPassword(password);
}
}
③在服务端的加密操作也要在setPassword之前,示例代码如下:
import java.io.IOException;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;
import org.apache.wss4j.common.ext.WSPasswordCallback;
public class MyPasswordCallBack implements CallbackHandler {
@Override
public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException{
WSPasswordCallback wsPasswordCallback = (WSPasswordCallback) callbacks[0];
String identifier = wsPasswordCallback.getIdentifier();
String password = "";
if (identifier.equals("cxf")) {
password = "wss4j";
password = MyDateUtil.getMd5(password);
}
wsPasswordCallback.setPassword(password);
}
}
④注意为什么客户端与服务端都是wsPasswordCallback.setPassword(password)
那是因为密码校验的工作是交由cxf框架自己来比较的,我们只需要在客户端放入密码
服务端也放入密码,框架底层自会完成两端传入的密码是否一致。
相关文章推荐
- 在同一个系统里用cxf 实现SOAP 协议和RESTful风格 两种类型的webservice接口(含简单demo)
- webservice接口常见问题1:客户端使用SOAP方式调用CXF服务时异常
- webservice的soap风格的接口发布流程
- 如何在其他项目调用webservice 发布的soap风格的接口
- SOAP之WebService、JSON传值问题
- php接口安全问题
- Java 提供接口的安全问题
- python通过http请求发送soap报文进行webservice接口调用
- Android 访问Webservice接口,参数对象不能串行化问题解决(java.lang.RuntimeException: Cannot serialize)
- PHP使用SOAP调用.net的WebService问题
- webService的rest风格的接口发布流程
- APP接口设计安全问题
- Axis2 java调用.net webservice接口的问题(郑州就维)
- webservice 接口的实现和实现过程所遇到的问题!!
- SOAP WebService接口功能自动化测试
- Jmeter3.2版本发送SOAP请求测试webservice接口
- APP接口设计安全问题-app接口鉴权
- webservice接口访问频率的控制问题
- jmeter发送soap请求进行webservice接口压力测试
- WebService工作原理及传输安全问题