`
wanjianfei
  • 浏览: 319273 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

UsernameToken

阅读更多

使用用户名和密码来验证用户的身份是最普通也最常见的方法,虽然在安全性方面也比较弱,由于其运用的广泛性还是成为了WS-Security目前所支持的Security Token之一。其原理非常简单,用户在发送请求的时候,在Soap head中加入自己的用户名以及密码,接受请求的Service通过之前与Client建立的共享密码来验证密码的合法性从而实现鉴别用户的功能。

不过实际运用起来就不能考虑的那么简单了,该方法主要存在两个问题:
1.在SOAP包中传输密码怎么保证密码的安全性?
2.怎么从用户名密码中获得签名和加密所需要的密钥?

针对第一个问题有三种解决方案:
1.使用运输层的安全协议(如SSL)来保证明文密码的安全性。
2.对明文密码做摘要后再传送给Service。
3.利用从密码派生出来的密钥来代替直接使用密码来实现身份鉴别。

第一种方法采用了WS-Security结合运输层的安全协议(SSL)来保证密码的安全,在本系列一开始的文章已经描述过运输层安全协议的缺点,所以在此不对该方法做详细介绍。

第二种方法类似于HTTP Digest Authentication,先来看一段使用该方法的示例:

<wsse:UsernameToken>
<wsse:Username>NNK</wsse:Username>
<wsse:Password Type="...#PasswordDigest">
weYI3nXd8LjMNVksCKFV8t3rgHh3Rw==
</wsse:Password>
<wsse:Nonce>WScqanjCEAC4mQoBE07sAQ==</wsse:Nonce>
<wsu:Created>2003-07-16T01:24:32Z</wsu:Created>
</wsse:UsernameToken>

从中看出这里使用了PasswordDigest类型的Password,从Password的内容也可以看出这里没有使用明文密码的形式。另外还多出了wsse:Nonce和wsu:Created两个元素。
其中Password的内容的计算公式如下:
Password_Digest = Base64 ( SHA-1 ( nonce + created + password ) )

读者可能比较奇怪wsse:Nonce和wsu:Created这两个元素的作用。为什么不直接SHA-1(password) ? 这样做是为了避免重放(Replay)攻击。假设Alice以摘要的形式向Service发送了密码,如果Bob此时截获了Alice发送的密码摘要,然后再用它向Service发送请求,那么Service将误认为Bob也是合法用户。当我们加入Nonce和Created元素之后,Service可以检查收到的消息中的Nonce是否已经收到过了,或者在一段时间(5min)内是否收到了相同用户名密码,从而避免重复攻击的危险。不过使用PasswordDigest方式要求Service必须拥有密码的明文形式,也就是说Service可以看到每个用户的密码,这对用户来说增加了风险。因为通常情况下用户的密码是以hash的形式保存在Service端的,从而保证用户的信息不被泄漏。
尽管通过PasswordDigest可以避免密码的明文传播,而且通过引入wsse:Nonce和wsu:Created可以避免重放攻击的危险。但是如果Bob能够把传送中的密码摘要完全的拦截下来(使它无法传送到Service),然后利用拦截下来的密码去冒充Alice去请求Service,那么Service将束手无策。因此引入了第三种方法的介绍。

第三种方法和Kerberos协议中KDC向Client传送TGT的方式类似。
我们可以看出前两种方式用户都将自己的密码发送给Service用于身份鉴别,难道为了证明自己的身份就必须把密钥(这里是密码)直接告诉别人吗?其实问题的关键在于Client能向Service证明它拥有只有C与S知道的密钥。而证明拥有的最直接方法就是告诉对方这个密钥,然后由Service比较这个密钥是否和它所知道的密钥一致,从而鉴别用户的身份。但是这种方法如前所述有各种缺陷。既然仅仅需要Client证明它知道这个密钥,那么Client可以用这个密钥对一段消息做一个签名,然后将消息和签名同时发送给Service,Service用它所知道的Client的密钥也对同样的消息做一次签名,通过比较两个签名是否一致就可以确认Client是否真的拥有它的密钥。同样通过加密的方法Client也可以向Service证明自己是否真的拥有密钥(因为只有C与S密钥一致Service才能解密出用C密钥加密的消息)。这样一旦Client在消息中加入自己的一些特有信息(比如IP),即便Bob截获了消息但是由于他并不知道真正的密钥,看不到那些特有信息,也就无法冒充Alice。

通过这种间接证明拥有密钥的方法,我们同时解决了文章一开始提出的第二个问题:
怎么从用户名密码中获得签名和加密所需要的密钥?

只要对密码做一些处理就可以从中派生出密钥。当然为了安全起见我们希望每次派生出来的密钥都不一样,这样就可以避免多次使用同一密钥而导致密钥被破解。下面就是WS-Security对密钥派生的元素定义:

<wsse:UsernameToken wsse:Id=”…”>
<wsse:Username></wsse:Username>
<wsse11:Salt></wsse11:Salt>
<wsse11:Iteration></wsse11:Iteration>
</wsse:UsernameToken>

其中Salt是导致密钥变化的因子,Iteration是密钥派生时Hash的次数。
密码的派生公式如下:
K1 = SHA1( password + Salt)
K2 = SHA1( K1 )

Kn = SHA1 ( Kn-1)

可以看到此时在UsernameToken已经不再包含Password元素,因为Client将通过使用从Password派生出密钥做签名做加密的方式来证明它拥有密钥,从而证明自己的身份。

由此看出第三种办法相对来说安全性大大提高了,但是在实际应用中以上介绍的三种的方法都不被推荐使用。
第三种方法仍旧有两个缺陷:
1.直接使用密码派生密钥,同以往临时产生的会话密钥相比,密码一旦破解,所有由改密码派生的密钥也被破解。由于密码长期不变, 那么随后所有使用该密码加密的消息都没有安全性可言。而且该密码可能还被用于Client与其他Service的交互,那么被破解后带来的损失就大多了。
2.用户密码必须以明文形式保存在Service端。

因此,在微软的WSE对安全的默认支持方式中采用了UsernameToken和Service端Certification的组合的方式来表示Security Token。下图就是WSE中已经实现的UsernameForCertificate对SOAP Envelop的扩展结构。

从中可以看到SOAP Head中的wsse:UsernameToken已经被加密,被xenc:EncryptedData所替代,查看其Token Reference发现加密使用的Key来自xenc:EncryptedKey。如果你完整阅读了本系列的文章,你将不会对它太陌生,在XML Encryption中曾经对它的来由做了详细介绍。

Note由于使用对称密钥加密效率高,所以通常会使用对称密钥来加密数据,但是如何让消息的接受也获得对称密钥则成了一个问题。消息发送方不可能将对称密钥也随消息传递给消息接收方,此时利用非对称密钥来实现加密所用的对称密钥的传递成为了一个比较好的选择。EncrptedKey就是实现此种功能的扩展元素。


Client随机产生的一个对称密钥并用它来加密和签名SOAP Envelop中的其他元素(如UsernameToken),并通过使用Service(消息接受方)的公钥(由于是公钥可以方便获取)来加密该对称密钥,以保证只有Service能够获得Client随机产生的对称密钥,从而达到验证消息完整性,解密数据并鉴别用户身份的目的。以下是采用这种方式保证安全的SOAP Envelop的示例:

<?xml version="1.0" encoding="utf-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://www.w3.org/2001/12/soap-envelope"
xmlns:ds="http://www.w3.org/2000/09/xmldsig#"
xmlns:xenc="http://www.w3.org/2001/04/xmlenc"
xmlns:wsu="http://schemas.xmlsoap.org/ws/2002/07/utility">
<SOAP-ENV:Header>
<wsse:Security
xmlns:wsse="http://schemas.xmlsoap.org/ws/2002/secext">
<wsse:UsernameToken>
<wsse:Username>HotelService</wsse:Username>
<wsse:Password>myword</wsse:Password>
</wsse:UsernameToken>
<xenc:EncryptedKey wsu:id="userSysmetricKey">
<xenc:EncryptionMethod
Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-1_5"/>
<ds:KeyInfo>
<wsse:SecurityTokenReference>
<wsse:KeyIdentifier
ValueType="...oasis-wss-soap-message-security-1.1#ThumbPrintSHA1">
LKiQ/CmFrJDJqCLFcjlhIsmZ/+0=
</wsse:KeyIdentifier>
</wsse:SecurityTokenReference>
</ds:KeyInfo>
<xenc:CipherData>
<xenc:CipherValue>G2wDCq24FsgBGerE...</xenc:CipherValue>
</xenc:CipherData>
<xenc:ReferenceList>
<xenc:DataReference URI="#DiscountResponse"/>
</xenc:ReferenceList>
</xenc:EncryptedKey>
<ds:Signature>
<ds:SignedInfo>
<ds:CanonicalizationMethod
Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
<ds:SignatureMethod
Algorithm="http://www.w3.org/2000/09/xmldsig#hmac-sha1"/>
<ds:Reference URI="#DiscountedBookingForPartnersResponse">
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#hmac-sha1"/>
<ds:DigestValue>JwFsd3eQc0iXlJm5PkLh7...</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue>BSxlJbSiFdm5Plhk...</ds:SignatureValue>
<ds:KeyInfo>
<wsse:SecurityTokenReference>
<wsse:Reference URI="#userSysmetricKey"
ValueType="...oasis-wss-soap-message-security-1.1#EncryptedKey"/>
</wsse:SecurityTokenReference>
</ds:KeyInfo>
</ds:Signature>
</wsse:Security>
</SOAP-ENV:Header>
<SOAP-ENV:Body wsu:Id="DiscountedBookingForPartnersResponse">
<s:GetSpecialDiscountedBookingForPartnersResponse
xmlns:s="http://www.MyHotel.com/partnerservice ">
<xenc:EncryptedData
wsu:Id="DiscountResponse"
type="http://www.w3.org/2001/04/xmlenc#Element">
<xenc:EncryptionMethod
Algorithm="http://www.w3.org/2001/04/xmlenc#aes256-cbc "/>
<CipherData>
<CipherValue>XD6sFa0DrWsHdehrHdhcW0x...</CipherValue>
</CipherData>
</xenc:EncryptedData>
</s:GetSpecialDiscountedBookingForPartnersResponse>
</SOAP-ENV:Body>

</SOAP-ENV:Envelope>

Note以上介绍的方法UsernameForCertificate仅被WS-Security1.1支持。因为在1.1中才支持使用对称密钥签名。

如此,之前所提到的问题都可以解决了,让我们回顾一下:
Q: 在SOAP包中传输密码怎么保证密码的安全性?
A: 使用密钥加密,只有接受方能解密密码。

Q: 怎么从用户名密码中获得签名和加密所需要的密钥?
A: 随机产生密钥,并通过接受方的公钥加密,保证密钥不被别人所知。

Q: 如何避免重放攻击?
A: 由于其他人无法获得密钥,所以即便截获消息也无法冒充。

Q: 直接使用密码派生密钥被破解了怎么办?
A: 密钥不再从密码派生,而是每次随机产生,即便被破解也不会影响其他的消息和其他的服务。

Q: 用户密码必须以明文形式保存在Service端?
A: 由于密码被加密而不是做摘要所以不需要Service拥有明文密码。

应用场景:
B2C网上购物,每个用户都有各自的用户名密码,而且可以方便的获得Server端的Certification。(比如Amazon)


参考资料:
OASIS Kerberos Token Profile 1.1
Protect Your Web Services Through The Extensible Policy Framework In WSE 3.0


分享到:
评论

相关推荐

    Sample WS-Security UsernameToken身份验证

    "Sample WS-Security UsernameToken身份验证" 这个标题表明我们要讨论的是一个示例项目,它利用了WS-Security标准中的UsernameToken机制进行身份验证。WS-Security,全称Web Services Security,是用于在Web服务中...

    arm-linux实现onvif server+WS-UsernameToken令牌验证

    在本文中,我们将深入探讨如何在ARM Linux平台上实现ONVIF服务器,并结合WS-UsernameToken令牌验证机制。ONVIF(开放网络视频接口论坛)是一个国际标准,旨在推动网络视频设备之间的互操作性。它定义了一套通信协议...

    UsernameToken WSE30

    【UsernameToken WSE30】是一个关于Web服务安全(WSE,Web Services Enhancements)3.0版本中UsernameToken身份验证机制的应用实例。在Web服务领域,安全性是至关重要的,而UsernameToken是一种基本的身份验证方式,...

    onvif 1.02 c/c++源代码,有简单使用说明,特别加入了onvif 权限(wsse)认证实现说明

    标题中的"onvif 1.02"指的是ONVIF...使用时,需理解SOAP协议,熟悉WS-Security的Usernametoken认证,并遵循提供的使用说明。同时,gSOAP库的使用也是关键,它简化了SOAP消息的构建和处理,以及WS-Security的集成。

    Microsoft.Web.Services2.rar

    描述中提到的"Microsoft.Web.Services2.Security.Tokens.UsernameToken",这是微软Web服务库中的一个安全模块,涉及到SOAP安全令牌,特别是用户名令牌(UsernameToken)。在Web服务的安全认证中,UsernameToken是一...

    net调用javawebservie

    本文主要介绍如何使用.NET(C#)通过WSE3.0来调用Java Web服务,特别是在WSI(Web Services Interoperability)协议的UserNameToken验证机制下的调用方式。 1. **WSE3.0(Web Services Enhancements)**: WSE是...

    Web Service SOAP Client set SOAP Header

    SOAPElement usernameToken = security.addChildElement("UsernameToken", "wsse"); usernameToken.addAttribute(new QName(...

    IBM WebSphere 开发者技术期刊: 通过 WebSphe…

    【描述】:虽然原始描述为空,但可以推测这篇博客文章可能详细阐述了WebSphere中的安全性,包括如何使用UsernameToken进行用户身份验证,以及如何配置权限和角色以实现不同级别的访问控制。 【标签】:“源码”、...

    CXF 通过用户名和密码进行验证

    Apache CXF是一个开源的Java框架,它用于创建和消费SOAP和RESTful Web服务。这里的验证过程通常涉及到安全控制,确保只有经过授权的用户才能访问服务。 在Web服务中,认证是确保用户身份的过程,而授权则是决定用户...

    WebService之XFire和Jax实现身份验证

    例如,可以使用XFire的WS-Security支持,结合UsernameToken或X509证书来进行用户身份验证。UsernameToken方式通常涉及到用户名和密码的传递,而X509证书则基于公钥基础设施(PKI),使用数字证书进行身份验证。为了...

    ws 加验证消息头

    例如,可以使用`&lt;wsse:Security&gt;`元素来包含认证信息,如用户名令牌(UsernameToken)、X.509证书或 Kerberos 令牌。 对于"简单易懂"的描述,这可能意味着我们将探讨一种相对基础的验证方法,如...

    Python SOAP 客户端.zip

    Python 3.9、3.10、3.11、3.12、3.13 和 PyPy3基于 lxml、requests 和 httpx 构建支持 Soap 1.1、Soap 1.2 和 HTTP 绑定支持 WS-Addressing 标头支持 WSSE (UserNameToken/x.509 签名)使用 httpx 模块支持 asyncio对...

    SOAPHEADER方法增强WebService安全性代码

    SOAPElement usernameToken = security.addChildElement("UsernameToken"); usernameToken.addChildElement("Username").addTextNode("myUsername"); usernameToken.addChildElement("Password").addTextNode(...

    CXF V3.2.4 实现的WebService调用(带安全认证)

    props.put("action", "UsernameToken"); props.put("user", "your_username"); props.put("passwordType", "PasswordText"); props.put("passwordCallbackClass", YourPasswordCallbackClass.class.getName()); ...

    Cxf客户端及服务器端,实现客户端和服务器端的权限验证

    对于WS-Security,可能需要创建和配置`UsernameToken`或加载X.509证书。 3. **代码实现**: - 在服务器端,创建自定义认证和授权类,实现Spring Security的`AuthenticationProvider`和`AccessDecisionManager`接口...

    cxf与spring整合,以及webservice传输验证demo

    至此,我们已经创建了一个使用CXF和Spring集成的Web服务,同时实现了基于UsernameToken的传输验证。这个简单的例子展示了如何在实际项目中部署和调用Web服务,并添加安全层以确保通信的安全性。通过这种方式,开发者...

    ONVIF20协议中文原版.doc

    ONVIF2.0协议考虑了网络安全,采用了如HTTP基本认证、Digest认证以及基于OASIS Web Services Security UsernameToken Profile 1.0的用户令牌,确保通信过程的安全性。 6. **兼容性和扩展性**: ONVIF2.0协议设计...

    ONVIF2.0协议珍藏版

    OASIS Web Services Security UsernameToken Profile 1.0规定了用户名令牌的使用,增强了身份验证机制。此外,它还涉及Web服务发现(WS-Discovery)和Web服务话题,以支持更复杂的网络环境和服务交互。 总的来说,...

Global site tag (gtag.js) - Google Analytics