数字证书
Ø
相当于身份证件,数字证书是在IE中做为一种身份标识的。
Ø
由于Internet网电子商务系统技术使在网上购物的顾客能够极其方便轻松地获得商家和企业的信息,但同时也增加了对某些敏感或有价值的数据被滥用的风险. 为了保证互联网上电子交易及支付的安全性,保密性等,防范交易及支付过程中的欺诈行为,必须在网上建立一种信任机制。这就要求参加电子商务的买方和卖方都必须拥有合法的身份,并且在网上能够有效无误的被进行验证。数字证书是一种权威性的电子文档。它提供了一种在Internet上验证您身份的方式,其作用类似于司机的驾驶执照或日常生活中的身份证。它是由一个由权威机构----CA证书授权(Certificate Authority)中心发行的,人们可以在互联网交往中用它来识别对方的身份。当然在数字证书认证的过程中,证书认证中心(CA)作为权威的、公正的、可信赖的第三方,其作用是至关重要的。
Ø
数字证书也必须具有唯一性和可靠性。为了达到这一目的,需要采用很多技术来实现。通常,数字证书采用公钥体制,即利用一对互相匹配的密钥进行加密、解密。每个用户自己设定一把特定的仅为本人所有的私有密钥(私钥),用它进行解密和签名;同时设定一把公共密钥(公钥)并由本人公开,为一组用户所共享,用于加密和验证签名。当发送一份保密文件时,发送方使用接收方的公钥对数据加密,而接收方则使用自己的私钥解密,这样信息就可以安全无误地到达目的地了。通过数字的手段保证加密过程是一个不可逆过程,即只有用私有密钥才能解密。公开密钥技术解决了密钥发布的管理问题,用户可以公开其公开密钥,而保留其私有密钥。
Ø
数字证书颁发过程一般为:用户首先产生自己的密钥对,并将公共密钥及部分个人身份信息传送给认证中心。认证中心在核实身份后,将执行一些必要的步骤,以确信请求确实由用户发送而来,然后,认证中心将发给用户一个数字证书,该证书内包含用户的个人信息和他的公钥信息,同时还附有认证中心的签名信息。用户就可以使用自己的数字证书进行相关的各种活动。数字证书由独立的证书发行机构发布。数字证书各不相同,每种证书可提供不同级别的可信度。可以从证书发行机构获得您自己的数字证书。
Ø
目前的数字证书类型主要包括:个人数字证书、单位数字证书、单位员工数字证书、服务器证书、VPN证书、WAP证书、代码签名证书和表单签名证书。
Ø
随着Internet的普及、各种电子商务活动和电子政务活动的飞速发展,数字证书开始广泛地应用到各个领域之中,目前主要包括:发送安全电子邮件、访问安全站点、网上招标投标、网上签约、网上订购、安全网上公文传送、网上缴费、网上缴税、网上炒股、网上购物和网上报关等。
数字签名
相当于在现实社会中给文件签名那种。
简单地说,所谓数字签名就是附加在数据单元上的一些数据,或是对数据单元所作的密码变换。这种数据或变换允许数据单元的接收者用以确认数据单元的来源和数据单元的完整性并保护数据,防止被人(例如接收者)进行伪造。它是对电子形式的消息进行签名的一种方法,一个签名消息能在一个通信网络中传输。基于公钥密码体制和私钥密码体制都可以获得数字签名,目前主要是基于公钥密码体制的数字签名。包括普通数字签名和特殊数字签名。普通数字签名算法有RSA、ElGamal、Fiat-Shamir、Guillou- Quisquarter、Schnorr、Ong-Schnorr-Shamir数字签名算法、Des/DSA,椭圆曲线数字签名算法和有限自动机数字签名算法等。特殊数字签名有盲签名、代理签名、群签名、不可否认签名、公平盲签名、门限签名、具有消息恢复功能的签名等,它与具体应用环境密切相关。显然,数字签名的应用涉及到法律问题,美国联邦政府基于有限域上的离散对数问题制定了自己的数字签名标准(DSS)。一些国家如法国和德国已经制定了数字签名法。
Handler功能简介
●
Handler提供了
对客户端进行认证、授权;
● 把用户的访问写入系统日志;
● 对请求的 SOAP消息进行加密,解密;
● 为Web Services对象做缓存。
● SOAP消息Handler能够访问代表RPC请求或者响应的SOAP消息。
● 把用户的访问写入系统日志;
● 对请求的 SOAP消息进行加密,解密;
● 为Web Services对象做缓存。
● SOAP消息Handler能够访问代表RPC请求或者响应的SOAP消息。
Apache axis
是我们当前开发Web服务的较好的选择,使用axisWeb服务开发工具,可以使用Handler来对服务端的请求和响应进行处理。在JAX-RPC技术中,SOAP消息Handler可以部署在服务端,也可以在客户端使用。
Handler日志
通过
Handler日志可以记录用户的操作,用户的登陆时间,将该信息保存至文本文件中或者其他可写入文件中,相当于Struts中的log4j的功能。
package
zpf;
import
java.io.FileOutputStream;
import
java.io.PrintWriter;
import
java.util.Date;
import
org.apache.axis.AxisFault;
import
org.apache.axis.Handler;
import
org.apache.axis.MessageContext;
import
org.apache.axis.handlers.BasicHandler;
public
class LogHandler extends BasicHandler {
/**invoke
,每一个handler都必须实现的方法。
*/
public void invoke(MessageContext msgContext) throws AxisFault {
//
每当web服务被调用,都记录到log中。
try {
Handler handler = msgContext.getService();
String filename = (String) getOption("filename");
if ((filename == null) || (filename.equals("")))
throw new AxisFault("Server.NoLogFile",
"No log file configured for the LogHandler!", null,
null);
FileOutputStream fos = new FileOutputStream(filename, true);
PrintWriter writer = new PrintWriter(fos);
Integer counter = (Integer) handler.getOption("accesses");
if (counter == null)
counter = new Integer(0);
counter = new Integer(counter.intValue() + 1);
Date date = new Date();
msgContext.getMessage().writeTo(System.out);
String result = "
在" + date + ": Web 服务 "
+ msgContext.getTargetService() + "
被调用,现在已经共调用了 "
+ counter + "
次.";
handler.setOption("accesses", counter);
writer.println(result);
writer.close();
} catch (Exception e) {
throw AxisFault.makeFault(e);
}
}
}
<requestFlow>
<handler name="logging" type="java:zpf.LogHandler">
<parameter name="filename" value="c://MyService.log"/>
</handler>
</requestFlow>
Axis Handler (对用户的访问认证)
package
zpf;
import
java.io.FileOutputStream;
import
java.io.PrintWriter;
import
java.util.Date;
import
org.apache.axis.AxisFault;
import
org.apache.axis.Handler;
import
org.apache.axis.MessageContext;
import
org.apache.axis.handlers.BasicHandler;
import
org.apache.axis.security.SecurityProvider;
import
org.apache.axis.security.simple.SimpleSecurityProvider;
import
org.apache.axis.utils.Messages;
public
class AuthenticationHandler extends BasicHandler {
/**invoke
,每一个handler都必须实现的方法。
*/
public void invoke(MessageContext msgContext) throws AxisFault {
SecurityProvider provider = (SecurityProvider) msgContext
.getProperty("securityProvider");
if (provider == null) {
provider = new SimpleSecurityProvider();
msgContext.setProperty("securityProvider", provider);
}
if (provider != null) {
String userId = msgContext.getUsername();
String password = msgContext.getPassword();
//
对用户进行认证,如果authUser==null,表示没有通过认证,抛出Server.Unauthenticated异常。
org.apache.axis.security.AuthenticatedUser authUser = provider
.authenticate(msgContext);
if (authUser == null)
throw new AxisFault("Server.Unauthenticated", Messages
.getMessage("cantAuth01", userId), null, null);
//
用户通过认证,把用户的设置成认证了的用户。
msgContext.setProperty("authenticatedUser", authUser);
}
}
}
<handler name="authen" type="java:zpf.AuthenticationHandler"/>
//
设置用户名和密码
call.getMessageContext().setUsername("caoxiang");
call.getMessageContext().setPassword("caoxiang");
Axis Handler (用户的访问授权)
package com.hellking.webservice;
import…
// 此handler的目的是对认证的用户授权,只有授权的用户才能访问目标服务。
public class AuthorizationHandler extends BasicHandler
{
/**invoke,每一个handler都必须实现的方法。
*/
public void invoke(MessageContext msgContext)
throws AxisFault
{
AuthenticatedUser user = (AuthenticatedUser)msgContext.getProperty("authenticatedUser");
if(user == null)
throw new AxisFault("Server.NoUser", Messages.getMessage("needUser00"), null, null);
String userId = user.getName();
Handler serviceHandler = msgContext.getService();
import…
// 此handler的目的是对认证的用户授权,只有授权的用户才能访问目标服务。
public class AuthorizationHandler extends BasicHandler
{
/**invoke,每一个handler都必须实现的方法。
*/
public void invoke(MessageContext msgContext)
throws AxisFault
{
AuthenticatedUser user = (AuthenticatedUser)msgContext.getProperty("authenticatedUser");
if(user == null)
throw new AxisFault("Server.NoUser", Messages.getMessage("needUser00"), null, null);
String userId = user.getName();
Handler serviceHandler = msgContext.getService();
String serviceName = serviceHandler.getName();
String allowedRoles = (String)serviceHandler.getOption("allowedRoles");
if(allowedRoles == null)
{
return;
}
SecurityProvider provider = (SecurityProvider)msgContext.getProperty("securityProvider");
if(provider == null)
throw new AxisFault(Messages.getMessage("noSecurity00"));
for(StringTokenizer st = new StringTokenizer(allowedRoles, ","); st.hasMoreTokens();)
{
String thisRole = st.nextToken();
if(provider.userMatches(user, thisRole))
{
return;// 访问授权通过。
}
}
//没有通过授权,不能访问目标服务,抛出Server.Unauthorized异常。
throw new AxisFault("Server.Unauthorized",
Messages.getMessage("cantAuth02", userId, serviceName), null, null);
}
}
String allowedRoles = (String)serviceHandler.getOption("allowedRoles");
if(allowedRoles == null)
{
return;
}
SecurityProvider provider = (SecurityProvider)msgContext.getProperty("securityProvider");
if(provider == null)
throw new AxisFault(Messages.getMessage("noSecurity00"));
for(StringTokenizer st = new StringTokenizer(allowedRoles, ","); st.hasMoreTokens();)
{
String thisRole = st.nextToken();
if(provider.userMatches(user, thisRole))
{
return;// 访问授权通过。
}
}
//没有通过授权,不能访问目标服务,抛出Server.Unauthorized异常。
throw new AxisFault("Server.Unauthorized",
Messages.getMessage("cantAuth02", userId, serviceName), null, null);
}
}
<parameter name="allowedRoles" value="caoxiang,caoxiang"/>
//
设置用户名和密码
call.getMessageContext().setUsername("caoxiang");
call.getMessageContext().setPassword("caoxiang");
Axis Handler (传输过程中的加密和解密)
由于
SOAP消息在HTTP协议中传输,而HTTP协议的安全度是比较低的,怎么保证信息安全到达对方而不泄漏或中途被撰改,将是Web服务必须解决的问题。围绕Web服务的安全,有很多相关的技术,比如WS-Security,WS-Trace等,另外,还有以下相关技术:
(XML数字签名)
XML Encryption (XML加密)
XKMS (XML Key Management Specification)
XACML (eXtensible Access Control Markup Language) XML Digital Signature
(XML数字签名)
XML Encryption (XML加密)
XKMS (XML Key Management Specification)
XACML (eXtensible Access Control Markup Language) XML Digital Signature
SAML (Secure Assertion Markup Language)
eb XML Message Service Security
Identity Management & Liberty Project
eb XML Message Service Security
Identity Management & Liberty Project
不管使用什么技术,要使信息
安全到达对方,必须把它进行加密,然后在对方收到信息后解密。为了提供开发的方便,可以使用Handler技术,在客户端发送信息前,使用客户端的Handler对SOAP消息中的关键信息进行加密;在服务端接收到消息后,有相应的Handler把消息进行解密,然后才把SOAP消息派发到目标服务。
下面我们来看一个具体的例子。加入使用
SOAP消息发送订单的信息,订单的信息如下:
<soap-env:Envelope xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/">
<soap-env:Header/>
<soapenv:Body>
<ns1:orderProduct soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encod
ing/" xmlns:ns1="HandleredService">
<arg0 xsi:type="xsd:string">hellking</arg0>
<arg1 xsi:type="xsd:string">beijing</arg1>
<arg2 xsi:type="xsd:string">music-100</arg2>
<arg3 xsi:type="xsd:int">10</arg3>
<arg4 href="#id0"/>
</ns1:orderProduct>
<multiRef id="id0" soapenc:root="0" soapenv:encodingStyle="http://schemas.xmls
oap.org/soap/encoding/" xsi:type="ns2:card" xmlns:soapenc="http://schemas.xmlsoa
p.org/soap/encoding/" xmlns:ns2="card">
<cardId xsi:type="xsd:string">234230572</cardId>
<cardType xsi:type="xsd:string">visa</cardType>
<password xsi:type="xsd:string">234kdsjf</password>
</multiRef>
</soapenv:Body>
</soap-env:Envelope>
<soap-env:Header/>
<soapenv:Body>
<ns1:orderProduct soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encod
ing/" xmlns:ns1="HandleredService">
<arg0 xsi:type="xsd:string">hellking</arg0>
<arg1 xsi:type="xsd:string">beijing</arg1>
<arg2 xsi:type="xsd:string">music-100</arg2>
<arg3 xsi:type="xsd:int">10</arg3>
<arg4 href="#id0"/>
</ns1:orderProduct>
<multiRef id="id0" soapenc:root="0" soapenv:encodingStyle="http://schemas.xmls
oap.org/soap/encoding/" xsi:type="ns2:card" xmlns:soapenc="http://schemas.xmlsoa
p.org/soap/encoding/" xmlns:ns2="card">
<cardId xsi:type="xsd:string">234230572</cardId>
<cardType xsi:type="xsd:string">visa</cardType>
<password xsi:type="xsd:string">234kdsjf</password>
</multiRef>
</soapenv:Body>
</soap-env:Envelope>
上面的黑体字是传输的敏感信息,故需要加密。我们可以使用
Message Digest之类的方法进行加密。
<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope …
<soapenv:Body>
<ns1:orderProduct …>
…
<arg4 href="#id0"/>
</ns1:orderProduct>
<multiRef …>
<ns3:EncryptedData xmlns:ns3="http://www.w3.org/2000/11/temp-xmlenc">
<ns3:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
<ns3:DigestValue>rO0ABXQAkyA8Y2FyZ…….
<soapenv:Envelope …
<soapenv:Body>
<ns1:orderProduct …>
…
<arg4 href="#id0"/>
</ns1:orderProduct>
<multiRef …>
<ns3:EncryptedData xmlns:ns3="http://www.w3.org/2000/11/temp-xmlenc">
<ns3:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
<ns3:DigestValue>rO0ABXQAkyA8Y2FyZ…….
</ns3:DigestValue>
</ns3:EncryptedData>
</multiRef>
</soapenv:Body>
</soapenv:Envelope>
通过使用加密、解密的 Handler,可以确保消息的安全传递。进一步说,如果把这种Handler做成通用的组件,那么就可以灵活地部署到不同的服务端和客户端。
客户端的Handler的功能是把SOAP消息使用一定的规则加密,假如使用Message Digest加密方式。
</ns3:EncryptedData>
</multiRef>
</soapenv:Body>
</soapenv:Envelope>
通过使用加密、解密的 Handler,可以确保消息的安全传递。进一步说,如果把这种Handler做成通用的组件,那么就可以灵活地部署到不同的服务端和客户端。
客户端的Handler的功能是把SOAP消息使用一定的规则加密,假如使用Message Digest加密方式。
SOAPElement ele= soapBodyElement.addChildElement(envelope.createName
("EncryptedData","","http://www.w3.org/2000/11/temp-xmlenc"));
ele.addChildElement("DigestMethod").addAttribute(envelope.createName
("Algorithm"),"http://www.w3.org/2000/09/xmldsig#sha1");
byte[] digest=new byte[100];
ByteArrayOutputStream out=new ByteArrayOutputStream (100);
MessageDigest md = MessageDigest.getInstance("SHA");
ObjectOutputStream oos = new ObjectOutputStream(out);
//要加密的信息
String data = " <cardId xsi:type='xsd:string'>234230572
</cardId><cardType xsi:type='xsd:string'>visa</cardType>
<password xsi:type='xsd:string'>234kdsjf</password>";
byte buf[] = data.getBytes();
md.update(buf);
oos.writeObject(data);
oos.writeObject(md.digest());
digest=out.toByteArray();
out.close();
ele.addChildElement("DigestValue").addTextNode(new
sun.misc.BASE64Encoder().encode(digest));//对加密的信息编码在客户端发送出SOAP消息时,客户端的Handler拦截发送的SOAP消息,然后对它们进行加密,最后把加密的信息传送到服务端。
服务端接收到加密的信息后,解密的Handler会把对应的加密信息解密。
("EncryptedData","","http://www.w3.org/2000/11/temp-xmlenc"));
ele.addChildElement("DigestMethod").addAttribute(envelope.createName
("Algorithm"),"http://www.w3.org/2000/09/xmldsig#sha1");
byte[] digest=new byte[100];
ByteArrayOutputStream out=new ByteArrayOutputStream (100);
MessageDigest md = MessageDigest.getInstance("SHA");
ObjectOutputStream oos = new ObjectOutputStream(out);
//要加密的信息
String data = " <cardId xsi:type='xsd:string'>234230572
</cardId><cardType xsi:type='xsd:string'>visa</cardType>
<password xsi:type='xsd:string'>234kdsjf</password>";
byte buf[] = data.getBytes();
md.update(buf);
oos.writeObject(data);
oos.writeObject(md.digest());
digest=out.toByteArray();
out.close();
ele.addChildElement("DigestValue").addTextNode(new
sun.misc.BASE64Encoder().encode(digest));//对加密的信息编码在客户端发送出SOAP消息时,客户端的Handler拦截发送的SOAP消息,然后对它们进行加密,最后把加密的信息传送到服务端。
服务端接收到加密的信息后,解密的Handler会把对应的加密信息解密。
package com.hellking.webservice;
import…
//此 handler的目的是把加密的SOAP消息解密成目标服务可以使用的SOAP消息。
public class MessageDigestHandler extends BasicHandler
{
/**invoke,每一个handler都必须实现的方法。
*/
public void invoke(MessageContext msgContext)throws AxisFault
{
try
{
//从messageContext例取得SOAPMessage对象。
import…
//此 handler的目的是把加密的SOAP消息解密成目标服务可以使用的SOAP消息。
public class MessageDigestHandler extends BasicHandler
{
/**invoke,每一个handler都必须实现的方法。
*/
public void invoke(MessageContext msgContext)throws AxisFault
{
try
{
//从messageContext例取得SOAPMessage对象。
SOAP是soapbody的最后一个child。
}
String value="";//value表示加密后的值。
SOAPElement digestValue=null;
Iterator it2=multi.getChildElements();
while(it2.hasNext())
{
SOAPElement temp=(SOAPElement)it2.next();
Iterator it3=temp.getChildElements(env.createName("DigestValue",
"ns3","http://www.w3.org/2000/11/temp-xmlenc"));
if(it3.hasNext())
value=((SOAPElement)it3.next()).getValue();//获得加密的值
}
//把加密的SOAPMessage解密成目标服务可以调用的SOAP消息。
SOAPMessage msg2=convertMessage(msg,this.decrypte(value));
msgContext.setMessage(msg2);
}
catch(Exception e)
{
e.printStackTrace();
}
}
//这个方法是把加密的数据进行解密,返回明文。
public String decrypte(String value)
{
String data=null;
try
{
ByteArrayInputStream fis = new
ByteArrayInputStream(new sun.misc.BASE64Decoder().decodeBuffer(value));
ObjectInputStream ois = new ObjectInputStream(fis);
Object o = ois.readObject();
if (!(o instanceof String)) {
System.out.println("Unexpected data in string");
System.exit(-1);
}
data = (String) o;
System.out.println("解密后的值:" + data);
o = ois.readObject();
if (!(o instanceof byte[])) {
System.out.println("Unexpected data in string");
System.exit(-1);
}
byte origDigest[] = (byte []) o;
MessageDigest md = MessageDigest.getInstance("SHA");
md.update(data.getBytes());
}
…
return data;Message msg=msgContext.getMessage();
SOAPEnvelope env=msg.getSOAPPart().getEnvelope();
Iterator it=env.getBody().getChildElements();
SOAPElement multi=null;
while(it.hasNext())
{
multi=(SOAPElement)it.next();//multi
}
String value="";//value表示加密后的值。
SOAPElement digestValue=null;
Iterator it2=multi.getChildElements();
while(it2.hasNext())
{
SOAPElement temp=(SOAPElement)it2.next();
Iterator it3=temp.getChildElements(env.createName("DigestValue",
"ns3","http://www.w3.org/2000/11/temp-xmlenc"));
if(it3.hasNext())
value=((SOAPElement)it3.next()).getValue();//获得加密的值
}
//把加密的SOAPMessage解密成目标服务可以调用的SOAP消息。
SOAPMessage msg2=convertMessage(msg,this.decrypte(value));
msgContext.setMessage(msg2);
}
catch(Exception e)
{
e.printStackTrace();
}
}
//这个方法是把加密的数据进行解密,返回明文。
public String decrypte(String value)
{
String data=null;
try
{
ByteArrayInputStream fis = new
ByteArrayInputStream(new sun.misc.BASE64Decoder().decodeBuffer(value));
ObjectInputStream ois = new ObjectInputStream(fis);
Object o = ois.readObject();
if (!(o instanceof String)) {
System.out.println("Unexpected data in string");
System.exit(-1);
}
data = (String) o;
System.out.println("解密后的值:" + data);
o = ois.readObject();
if (!(o instanceof byte[])) {
System.out.println("Unexpected data in string");
System.exit(-1);
}
byte origDigest[] = (byte []) o;
MessageDigest md = MessageDigest.getInstance("SHA");
md.update(data.getBytes());
}
…
return data;Message msg=msgContext.getMessage();
SOAPEnvelope env=msg.getSOAPPart().getEnvelope();
Iterator it=env.getBody().getChildElements();
SOAPElement multi=null;
while(it.hasNext())
{
multi=(SOAPElement)it.next();//multi