Webservice 的安全

Webservice为作为方便的服务被用广大领域使用的同时,也成为了黑客们的美食。在这里,本文将就目前对Webservice安全所能做的改进做简单介绍。
在Webservice中的安全主要分为以下三个方面。
传输 SSL/HTTPS 对连接加密,而不是传输数据
消息 数据加密(XML Encryption) 数字签名(XML-DSIG)
底层架构 利用应用服务安全机制

传输时的安全是最容易被加入到你的Webservice应用中的,利用现有的SSL 和HTTPS协议,就可以很容易的获得连接过程中的安全。

然而这种安全实现方法有两个弱点。一是它只能保证数据传输的安全,而不是数据本身的安全,数据一旦到达某地,那么就可以被任何人所查看。而在Webservice中,一份数据可能到达多个地方,而这份数据却不该被所有的接受者所查看。二是它提供的是要么全有要么全无的保护,你不能选择哪部分数据要被保护,而这种可选择性也是在Webservice中所常要用到的。

第二层的保护是对于消息本身的保护。你可以使用已有的XML安全扩展标准,实现数字签名的功能,从而保证你的消息是来自特定方并没有被修改过。XML文件的加密技术从更大程度上加强了WebService的安全,它能够定制数据传输到后,能否被接受者所查看,进一步完善了传输后的安全,业界也在不断的制定Webservice的安全标准,比如SAML 和 WS-Security。
一是利用WS-Security将签名和加密头加入SOAP消息;
另一个是利用数字证书和数字签名认证;

最后一层保护就是依靠底层架构的安全,这更多的来自于操作系统和某些中间件的保护。比如在J2EE中,主持WebService的应用服务器。目前很多的J2EE应用服务器都支持Java Authentication and Authorization Service (JAAS),这是最近被加入到J2SE 1.4当中的。利用主持Webservice的服务器,实现一些安全机制这是很自然的做法。另一种利用底层架构的安全方法就是,做一个独立的负责安全的服务器,Webservice的使用者和创建者都需要与之取得安全信任。

Web-Security概述

WS-Security(Web服务安全)是一种提供在Web Service上应用安全的方法的网络传输协议,协议包含了关于如何在Web Service消息上保证完整性和机密性的规约。WS-Security描述了如何将签名和加密头加入SOAP消息。除此以外,还描述了如何在消息中加入安全令牌,包括二进制安全令牌,如X.509认证证书和Kerberos门票(ticket)。WS-Security将安全特性放入SOAP消息头中在应用层处理,这样协议保证了端到端的安全。

CXF中使用Web-Security

在CXF中实现服务端或者客户端的WS-Security,需要设置WSS4J拦截器。WS-Security规范支持多种令牌方式,UserNameToken头是其中一种方式。UserNameToken头是一种把用户米和密码或者密码摘要传到另一个端点的标准方式。

服务端

在配置文件pom.xml中添加WS-Security引用。

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.rvho</groupId>
<artifactId>cxfservers</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>

<properties>
<!-- CXF版本 -->
<cxf.version>3.1.1</cxf.version>
<!-- Spring版本 -->
<spring.version>4.1.7.RELEASE</spring.version>
</properties>

<dependencies>
<!-- Spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- End Spring -->

<!-- CXF -->
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxws</artifactId>
<version>${cxf.version}</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxrs</artifactId>
<version>${cxf.version}</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http</artifactId>
<version>${cxf.version}</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-ws-security</artifactId>
<version>${cxf.version}</version>
</dependency>
<!--如果用tomcat发布,不需要引用jetty-->
<!--
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http-jetty</artifactId>
<version>${cxf.version}</version> </dependency>
-->
<!-- End CXF -->
</dependencies>
</project>
服务端回调函数ServerPasswordCallbackHandler,校验客户端请求是否合法,合法就放行,否则拒绝执行任何操作。

package com.rvho.cxfserver.callback;

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 ServerPasswordCallbackHandler implements CallbackHandler {

@Override
public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
WSPasswordCallback pc = (WSPasswordCallback) callbacks[0];

if (pc.getIdentifier().equals("admin")) {
//设置密码
//这个密码和客户端发送的密码进行比较
//如果和客户端不同将抛出org.apache.ws.security.WSSecurityException
pc.setPassword("123");
}
}

}

服务端通过输入拦截器WSS4JInInterceptor实现WS-Security的校验,如果服务端集成了spring,WSS4JInInterceptor配置如下。

<?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"
xmlns:soap="http://cxf.apache.org/bindings/soap"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://cxf.apache.org/bindings/soap http://cxf.apache.org/schemas/configuration/soap.xsd
http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">

<!-- 回调函数 -->
<bean id="serverPasswordCallback" class="com.rvho.cxfserver.callback.ServerPasswordCallbackHandler"></bean>

<jaxws:endpoint id="helloWSEndpoint" implementor="#helloWS" address="/hello">
<jaxws:inInterceptors>
<!-- WS-Security拦截器 -->
<bean class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor">
<!-- 拦截器的构造函数参数 -->
<constructor-arg>
<map>
<entry key="action" value="UsernameToken"/>
<!-- 密码类型,PasswordText表示明文 -->
<entry key="passwordType" value="PasswordText"/>
<entry key="passwordCallbackRef">
<!-- 回调函数引用 -->
<ref bean="serverPasswordCallback"/>
</entry>
</map>
</constructor-arg>
</bean>
<bean class="org.apache.cxf.interceptor.LoggingInInterceptor"></bean>
</jaxws:inInterceptors>
<jaxws:outInterceptors>
<bean class="org.apache.cxf.interceptor.LoggingOutInterceptor"></bean>
</jaxws:outInterceptors>
</jaxws:endpoint>
</beans>
如果服务端通过代码方式发布服务,可以用API添加。

JaxWsServerFactoryBean factory = new JaxWsServerFactoryBean();
factory.setServiceClass(HelloWS.class);
factory.setAddress("http://localhost:8280/cxfservers/services/hello");
factory.setServiceBean(new HelloWSImpl());

//WS-Security输入拦截器
Map<String, Object> inProps = new HashMap<String, Object>();
inProps.put(WSHandlerConstants.ACTION, WSHandlerConstants.USERNAME_TOKEN);
inProps.put(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PW_TEXT);
inProps.put(WSHandlerConstants.PW_CALLBACK_CLASS, ServerPasswordCallbackHandler.class.getName());

factory.getInInterceptors().add(new WSS4JInInterceptor(inProps));
factory.getInInterceptors().add(new LoggingInInterceptor());

factory.create();
客户端

客户端回调函数ServerPasswordCallbackHandler,回调函数在发请求时添加密码。

package com.rvho.cxfclient.callback;

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 ClientPasswordCallbackHandler implements CallbackHandler {

@Override
public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
WSPasswordCallback pc = (WSPasswordCallback) callbacks[0];
pc.setPassword("123");
}

}
客户端请求

JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
factory.setServiceClass(HelloWS.class);
factory.setAddress("http://localhost:8280/cxfservers/services/hello");
factory.getInInterceptors().add(new org.apache.cxf.interceptor.LoggingInInterceptor());

//WS-Security输出拦截器
Map<String, Object> outProps = new HashMap<String, Object>();
outProps.put(WSHandlerConstants.ACTION, WSHandlerConstants.USERNAME_TOKEN);
//添加用户名
outProps.put(WSHandlerConstants.USER, "admin");
outProps.put(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PW_TEXT);
outProps.put(WSHandlerConstants.PW_CALLBACK_CLASS, ClientPasswordCallbackHandler.class.getName());

factory.getOutInterceptors().add(new WSS4JOutInterceptor(outProps));
factory.getOutInterceptors().add(new com.rvho.cxfclient.interceptor.AuthAddInterceptor());
factory.getOutInterceptors().add(new org.apache.cxf.interceptor.LoggingOutInterceptor());

HelloWS helloWS = factory.create(HelloWS.class);
String welcome = helloWS.welcome("accountwcx@qq.com");
System.out.println(welcome);

客户端和服务端数据格式

八月 03, 2015 2:31:51 下午 org.apache.cxf.services.HelloWSService.HelloWSPort.HelloWS
信息: Outbound Message
---------------------------
ID: 1
Address: http://localhost:8280/cxfservers/services/hello
Encoding: UTF-8
Http-Method: POST
Content-Type: text/xml
Headers: {Accept=[*/*], SOAPAction=[""]}
Payload: <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Header><wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" soap:mustUnderstand="1"><wsse:UsernameToken wsu:Id="UsernameToken-581191d1-7dcb-479b-a739-0ebb063d740f"><wsse:Username>admin</wsse:Username><wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">123</wsse:Password></wsse:UsernameToken></wsse:Security><auth xmlns="http://www.tmp.com/auth"><name>admin</name><password>admin</password></auth></soap:Header><soap:Body><ns2:welcome xmlns:ns2="http://www.tmp.com/services/hello"><name>accountwcx@qq.com</name></ns2:welcome></soap:Body></soap:Envelope>
--------------------------------------

八月 03, 2015 2:31:51 下午 org.apache.cxf.services.HelloWSService.HelloWSPort.HelloWS
信息: Inbound Message
----------------------------
ID: 1
Address: http://localhost:8280/cxfservers/services/hello
Encoding: UTF-8
Http-Method: POST
Content-Type: text/xml; charset=UTF-8
Headers: {Accept=[*/*], Cache-Control=[no-cache], connection=[keep-alive], Content-Length=[847], content-type=[text/xml; charset=UTF-8], Host=[localhost:8280], Pragma=[no-cache], SOAPAction=[""], User-Agent=[Apache CXF 3.1.1]}
Payload: <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Header><wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" soap:mustUnderstand="1"><wsse:UsernameToken wsu:Id="UsernameToken-581191d1-7dcb-479b-a739-0ebb063d740f"><wsse:Username>admin</wsse:Username><wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">123</wsse:Password></wsse:UsernameToken></wsse:Security><auth xmlns="http://www.tmp.com/auth"><name>admin</name><password>admin</password></auth></soap:Header><soap:Body><ns2:welcome xmlns:ns2="http://www.tmp.com/services/hello"><name>accountwcx@qq.com</name></ns2:welcome></soap:Body></soap:Envelope>
--------------------------------------

CXF之九 WS-Security的更多相关文章

  1. WS Security 认证方式详解

    本文参考文档如下: MSDN 官方详解 : http://www.microsoft.com/china/MSDN/library/WebServices/WebServices/HowASP.NET ...

  2. CXF生成本地ws调用代码测试webservice

    package com.free.webservice.client; import java.util.List; import cn.com.webxml.*; public class Weat ...

  3. Spring Cloud 学习 (九) Spring Security, OAuth2

    Spring Security Spring Security 是 Spring Resource 社区的一个安全组件.在安全方面,有两个主要的领域,一是"认证",即你是谁:二是& ...

  4. cxf+spring+数字签名开发webservice(一)

    数字证书的准备         下面做的服务端和客户端证书在例子中无法加解密,不知道什么原因,我是使用正式环境中的客户端和服务端进行开发测试的,所以需要大家自己去准备证书,或者有人知道为什么jdk生成 ...

  5. CXF 入门:创建一个基于WS-Security标准的安全验证(CXF回调函数使用,)

    http://jyao.iteye.com/blog/1346547 注意:以下客户端调用代码中获取服务端ws实例,都是通过CXF 入门: 远程接口调用方式实现 直入正题! 以下是服务端配置 ==== ...

  6. 使用spring + cxf +tomcat构建webservice

    这里使用maven构建的项目. 首先,我们构建一个maven项目: 然后将pom.xml文件中的内容拷贝到新建项目的pon.xml文件中: <project xmlns="http:/ ...

  7. WebService--使用 CXF 开发 REST 服务

    现在您已经学会了如何使用 CXF 开发基于 SOAP 的 Web 服务,也领略了 Spring + CXF 这个强大的组合,如果您错过了这精彩的一幕,请回头看看这篇吧: Web Service 那点事 ...

  8. WebService- 使用 CXF 开发 SOAP 服务

    选框架犹如选媳妇,选来选去,最后我还是选了“丑媳妇(CXF)”,为什么是它?因为 CXF 是 Apache 旗下的一款非常优秀的 WS 开源框架,具备轻量级的特性,而且能无缝整合到 Spring 中. ...

  9. cxf的使用及安全校验-02创建简单的客户端接口

    上一篇文章中,我们已经讲了如果简单的创建一个webservice接口 http://www.cnblogs.com/snowstar123/p/3395568.html 现在我们创建一个简单客户端接口 ...

随机推荐

  1. AppWidget框架

    AppWidget 框架主要包括以下类: 1.AppWidgetProvider:继承自BroadcastReceiver,在AppWidget应用update.enable.disable和dele ...

  2. Java学习笔记之:Java JDBC

    一.介绍 JDBC(Java Data Base Connectivity,java数据库连接)是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组用java语言编写 ...

  3. android 检测工具: drozer

    1. 下载 https://www.mwrinfosecurity.com/products/drozer/community-edition/ 可以下载windows的也可以下载linux的 2. ...

  4. Sublime Text 新建文件可选类型的模版插件: SublimeTmpl

    安装方法: 1.Ctrl+Shift+P打开控制台, 2.输入IP安装插件 3.输入tmpl 回车安装 编辑模版在:SublimeTmpl\templates"文件夹修改 其他情况: htt ...

  5. Android 批量插入数据到SQLite数据库

    Android中在sqlite插入数据的时候默认一条语句就是一个事务,因此如果存在上万条数据插入的话,那就需要执行上万次插入操作,操作速度可想而知.因此在Android中插入数据时,使用批量插入的方式 ...

  6. Java I/O操作学习笔记

    书上写的有点乱,所以就自己总结了一下,主要参考:http://www.cnblogs.com/qianbi/p/3378466.html 1.从文件读出和写入: import java.io.*; i ...

  7. 大型web系统架构详解

    (如果感觉有帮助,请帮忙点推荐,添加关注,谢谢!你的支持是我不断更新文章的动力.本博客会逐步推出一系列的关于大型网站架构.分布式应用.设计模式.架构模式等方面的系列文章) 动态应用,是相对于网站静态内 ...

  8. HDU 4726 Kia's Calculation(贪心构造)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4726 题意:给出两个n位的数字,均无前缀0.重新排列两个数字中的各个数,重新排列后也无前缀0.得到的两 ...

  9. [HIHO1039]字符消除(字符串,枚举,模拟)

    题目链接:http://hihocoder.com/problemset/problem/1039 思路:枚举所有字符更新的位置和ABC三种修改方案,之后再模拟消除规则,一步一步去消除.直到无法消除, ...

  10. Hopfield模型

    1982年,J.Hopfield提出了可用作联想存储器的互连网络,这个网络称为Hopfield网络模型,也称Hopfield模型.Hopfield神经网络模型是一种循环神经网络,从输出到输入有反馈连接 ...