12.3 实例:Web Service应用开发安全

相信大多数读者对于开发Web Service系统并不陌生。通过Web Service我们可以获得天气预报、火车时刻表、股票行情、电视节目预告等相应数据。公司之间的合作也常常通过Web Service系统完成数据同步等。

如何保护这样一个基于明文协议(WSDL、SOAP协议等)的系统是每一个架构师不容忽视的安全问题。

如果对传输的对象加密,或者对传输数据做加密处理,虽然可以保证在接口开放的前提下保护敏感数据,但却加大了安全开发的工作量,同时也将带来许多新问题:密钥的管理、数据交互双方算法的商榷、敏感数据范围的定义等。

使用数字证书构建SSL/TLS协议,最终构建HTTPS服务是保护Web Service系统的最佳方案。

开源组织Apache为我们提供了非常丰富的Web Service框架(http://ws.apache.org/),其中尤以Axis和CXF最为常用。Axis框架包含两个分支:Axis(http://ws.apache.org/axis/)和Axis2(http://ws.apache.org/axis2/)。CXF框架(http://cxf.apache.org/)由Celtix(http://celtix.ow2.org/)和XFire(http://xfire.codehaus.org/)发展而来,准确地说,CXF=Celtix+XFire。Spring也提供了自己的Web Service产品—Spring Web Service。

本文以开源Web Service架构Axis 1.4为例,介绍如何构建单向认证服务和双向认证服务,确保Web Service开发安全。

12.3.1 Web Service应用基本实现

我们在Eclipse中构建一个动态Web项目,用于构建简单的Web Service应用。

1.准备工作

根据Axis官方文档说明,我们将用到以下jar包:

❑axis.jar:Axis核心包。

❑activation.jar和mail.jar:用于电子邮件操作。

❑jaxrpc.jar:用于基于XML的远程过程调用。

❑commons-discovery.jar:用最佳的算法查找某个接口的所有已知的实现。

❑commons-logging.jar:用于日志控制。

❑wsdl4j.jar:生成/解析WSDL协议。

请读者朋友在Axis官方网站下载完整Axis发行包,上述jar包均可以在该发行包中找到。

接下来,我们需要配置web.xml文件,完整内容如代码清单12-29所示。

代码清单12-29 web.xml文件


<?xml version="1.0"encoding="UTF-8"?>

<web-app

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xmlns="http://java.sun.com/xml/ns/javaee"

xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"

xsi:schemaLocation="http://java.sun.com/xml/ns/javaee

http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"

id="WebApp_ID"

version="2.5">

<display-name>Apache-Axis</display-name>

<servlet>

<display-name>Apache-Axis Servlet</display-name>

<servlet-name>axis</servlet-name>

<servlet-class>org.apache.axis.transport.http.AxisServlet</servlet-class>

<load-on-startup>0</load-on-startup>

</servlet>

<servlet-mapping>

<servlet-name>axis</servlet-name>

<url-pattern>/services/*</url-pattern>

</servlet-mapping>

</web-app>


org. apache.axis.transport.http.AxisServlet类是我们唯一需要配置的Servlet。这里我们将请求路径位于“/services/”下的任何请求都交给AxisServlet类处理。

org. apache.axis.Version类提供了一个用于获得Axis版本信息的静态方法getVersion()。我们可以将该方法暴露在Web Service中,构建一个简单的Web Service。当我们访问地址http://localhost:8080/axis/services/Version?wsdl时,将得到相应的WSDL(Web Service Definition Language, Web Service描述语言)协议。

Axis Web Service相关配置位于WEB-INF目录下的server-config.wsdd文件中。文件详情如代码清单12-30所示。

代码清单12-30 server-config.wsdd文件


<?xml version="1.0"encoding="UTF-8"?>

<deployment

xmlns="http://xml.apache.org/axis/wsdd/"

xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">

<transport

name="http">

<requestFlow>

<handler

type="java:org.apache.axis.handlers.http.URLMapper"/>

</requestFlow>

</transport>

<transport

name="local">

<responseFlow>

<handler

type="java:org.apache.axis.transport.local.LocalResponder"/>

</responseFlow>

</transport>

<service

name="Version"

provider="java:RPC">

<parameter

name="allowedMethods"

value="getVersion"/>

<parameter

name="className"

value="org.apache.axis.Version"/>

</service>

</deployment>


注意上述配置中的“service”节点,这里我们将暴露一个名为“Version”的服务。该服务指向org.apache.axis.Version类,仅允许使用getVersion()方法完成相应操作。

现在,我们启动Tomcat并访问地址http://localhost:8080/axis/services,将得到Web Service列表,如图12-18所示。

figure_0435_0158

图 12-18 Web Service列表1

继续点击上述页面链接(wsdl)获得Version对应WSDL协议,如图12-19所示。

通过上述页面的描述,我们已经很清楚:可以通过调用getVersion()方法获得String类型的返回值。

figure_0436_0159

图 12-19 WSDL协议1

2.验证服务

现在,我们构建相应的SOAP(Simple Object Access Protocol,简单对象访问协议)响应测试用例,验证上述服务。

Axis框架提供的Web Service客户端访问需要先构建Service实现类,并通过该类的createCall()方法创建调用对象Call类实例化对象。完整代码如代码清单12-31所示。

代码清单12-31 构建调用对象


//创建调用对象

Service service=new Service();

Call call=(Call)service.createCall();


接下来,我们需要对Call类实例化对象call做相应设置:配置远程调用的方法(通过调用setOperationName()方法)和设置访问URL(通过调用setTargetEndpointAddress()方法)。完整代码如代码清单12-32所示。

代码清单12-32 配置远程调用对象


//调用远程方法

call.setOperationName(new QName(namespaceUri,"getVersion"));

//设置URL

call.setTargetEndpointAddress(new URL(wsdlUrl));


最后,我们需要通过invoke()方法完成调用,并获得返回值。完整代码如代码清单12-33所示。

代码清单12-33 执行远程调用


//执行远程调用,同时获得返回值

String version=(String)call.invoke(new Object[]{});


有关Axis框架的相关实现,请读者查阅相关API文档。测试用例完整代码如代码清单12-34所示。

代码清单12-34 SOAP响应测试用例


import static org.junit.Assert.*;

import java.net.URL;

import javax.xml.namespace.QName;

import org.apache.axis.client.Call;

import org.apache.axis.client.Service;

import org.junit.Before;

import org.junit.Test;

/**

*WebService测试

*@author梁栋

*@version 1.0

*@since 1.0

*/

public class WebServiceTest{

//Namespace URL

private String namespaceUri="http://localhost:8080/axis/services/Version";

//WSDL URL

private String wsdlUrl="http://localhost:8080/axis/services/Version?wsdl";

/**

*测试

*@throws Exception

*/

@Test

public final void test()throws Exception{

//创建调用对象

Service service=new Service();

Call call=(Call)service.createCall();

//调用远程方法

call.setOperationName(new QName(namespaceUri,"getVersion"));

//设置URL

call.setTargetEndpointAddress(new URL(wsdlUrl));

//执行远程调用,同时获得返回值

String version=(String)call.invoke(new Object[]{});

//打印信息

System.err.println(version);

//验证

assertNotNull(version);

}

}


如果调用验证通过,我们将在控制台得到Axis的版本信息,如图12-20所示。

figure_0438_0160

figure_0438_0161

图 12-20 Axis版本信息

3.网络监测

在这里,作者为方便通过Wireshark监测网络传输信息,将Tomcat应用部署在虚拟机(IP为192.168.184.131),并通过IP直接访问。

首先,我们需要找到要绑定的网卡,并单击“Start”按钮进行绑定监听。作者使用的虚拟机网卡IP为192.168.184.1,请读者根据实际情况绑定对应网卡。网卡绑定如图12-21所示。

figure_0438_0162

图 12-21 网卡绑定

完成网卡绑定后,在过滤器地址栏中输入过滤信息,如代码清单12-35所示。

代码清单12-35 过滤拦截1


(ip.src==192.168.184.131&&ip.dst==192.168.184.1)||(ip.dst==192.168.184.131

&&ip.src==192.168.184.1)&&http


其中

(ip. src==192.168.184.131&&ip.dst==192.168.184.1)指限定由本机请求虚拟机

(ip. dst==192.168.184.131&&ip.src==192.168.184.1)指限定由虚拟机回复本机

http 指定HTTP协议

重新执行SOAP请求,我们将在Wireshark中获得详细的SOAP请求和回应信息,如图12-22所示。

右键点击图12-22中任意一条数据包(No.298或No.300),在弹出的菜单中选择“Follow TCP Stream”菜单项。

在弹出的窗口(Follow TCP Stream)中单击下拉列表框,选择请求和回复信息,分别得到SOAP请求和SOAP回复内容,如图12-23和图12-24所示。

figure_0439_0163

图 12-22 SOAP请求和回应信息

figure_0439_0164

图 12-23 SOAP请求

figure_0439_0165

图 12-24 SOAP回复

如果我们仅仅将列车时刻表、天气预报和电视节目预报等公开服务通过Web Service系统暴露服务,将无须考虑任何安全问题。但如果我们需要通过Web Service系统与合作伙伴交互商业数据,这将是一件可怕的事情。