此Web服务安全方案存在哪些潜在问题?

时间:2008-09-30 14:34:14

标签: web-services security

我们有一项服务,可根据用户名和密码处理授权。我们将其放在SOAP标头中,而不是将用户名和密码作为调用的一部分。

在典型情况下,Web Service在执行开始时调用Authorization服务以检查是否允许调用者调用它。问题是,这些Web服务中的一些相互调用,这意味着在每个子调用中都会检查用户的权限,这可能非常昂贵。

我想做的是让授权服务在第一次调用后返回安全令牌。然后,Web服务不必每次都调用授权服务,而是可以在本地验证安全标头。

安全标题看起来像这样(C#代码 - 修剪以说明基本概念):

public sealed class SecurityHeader : SoapHeader
{
    public string UserId;     // Encrypted   
    public string Password;   // Encrypted; Just realized this field isn't necessary [thanks CJP]

    public DateTime TimeStamp;   // Used for calculating header Expiry
    public string SecurityToken;
}

一般的想法是每次调用都会检查SecurityHeader。如果它存在,但尚未过期,并且SecurityToken有效,则Web方法将正常进行。否则它将返回错误,或者它将尝试重新授权并生成新的SecurityHeader

SecurityToken基于UserId,Password和TimeStamp的盐渍哈希。每天更换盐以防止重播。

我看到的一个问题是用户可能有权访问Web服务A,但不能访问Web服务B.如果他调用A并收到安全令牌,就像现在一样,这意味着B会让他通过如果他使用相同的标记。我必须更改它,以便安全令牌仅在从Web服务到Web服务,而不是用户到Web服务,即。如果用户调用A调用B,则应该没有问题,但如果用户调用服务A然后调用服务D则不行。解决方法是将公共密钥(或一组密钥)分配给逻辑相关的服务。 (即如果客户可以做A,那么逻辑上他也可以做​​B)。

或者,我必须将用户的整个权限集编码为安全头的一部分。我将不得不调查开销会是什么。

编辑:

有些人提到了其他安全方案,比如WS-Security和SAML等。我已经有了。事实上,我从WS-Security那里得到了这个想法。问题是其他方案不提供我需要的功能(缓存授权信息并防止在没有中间数据库的情况下重放)。如果有人知道一个方案,那么我会用它来替代它。此外,这是关于身份验证的 。这是由我无法控制的另一种机制来处理的。

如果事实证明无法缓存授权数据,那么这意味着我只需要承担每个级别的授权开销。

4 个答案:

答案 0 :(得分:4)

您的方案的根本问题在于您没有使用标准框架或实现。这与您的计划本身的任何特殊优点无关。

原因很简单,安全性(特别是加密)非常非常复杂,几乎不可能做到正确。使用一个强大,易于理解和证明的通用工具。

有关WS-Security的更多信息,请参阅: http://www.oasis-open.org/committees/tc_home.php?wg_abbrev=wss

大多数框架(.NET / JavaEE等)都将为WS-Security提供内置支持(在某种程度上)。

如果您认为您的计划在某种程度上比标准更好,我建议您将其作为一篇论文写出并提交给同行评审(以及参考实施),但不要用它来确保应用

编辑以响应OP编辑: 我认为你很容易混淆认证和授权的角色,这很容易做到......

计划中的安全令牌(或类似)的滚动是验证邮件的发件人 - 基本上,他们应该是发件人。正如您正确指出的那样,身份验证并不意味着要授予发件人访问哪些底层资源。

授权是您获取经过身份验证的发件人并应用一组权限的过程,以便您可以限制访问范围。通常,框架默认情况下不会进行授权,您必须通过创建某种形式的ACL或通过扩展某种“安全管理器”类型的界面来启用它。

实际上,我们的想法是,身份验证层会告诉您谁正在尝试访问Page A,并由您决定是否有权访问Page A.

您永远不应该在消息本身中存储有关权限和权限的信息 - 接收方应针对每条消息验证其ACL(或数据库或其他)的权限。如果有人弄清楚如何修改消息,这会限制您的曝光。

答案 1 :(得分:2)

好的,用希望更好的答案取代我的旧答案。

如果您有办法在服务之间安全地共享数据,那么您所描述的内容应该有效。例如,如果您的服务与授权服务共享密钥,则可以使用此密钥获取盐。

顺便说一句,我不知道足够的密码学来说是否足够安全添加秘密盐+哈希(虽然看起来很好);我非常确定HMAC使用密钥或私钥是安全的。旋转键是一个好主意,因此您仍然可以使用主密钥并传播新的签名密钥。

您的方法的其他问题是(a)您在每个服务中硬编码哈希逻辑,以及(b)服务可能希望从授权服务获得更多详细数据,而不仅仅是是/否答案。例如,您可能希望授权服务插入此用户属于角色A和B但不属于C的标头中。

作为替代方案,您可以让授权服务使用其拥有的任何有趣信息创建新标头,并签署该块。

此时,我们正在讨论单点登录实施。您已经了解WS-Security规范。我描述的这个标题听起来很像SAML断言。

Here's an article关于使用WS-Security和SAML进行单点登录。

现在,我不知道你是否需要这一切......还有中间解决方案。例如,授权服务可以签署原始用户名块;如果你担心公共/私人加密性能,并且你可以共享密钥,你也可以使用密钥来签名而不是公钥/私钥。

答案 2 :(得分:1)

就个人而言,只要你有一个集中的底层框架来支持SecurityToken值的验证,我个人认为你没有任何问题。

答案 3 :(得分:0)

首先,阅读@CJP的帖子,他提出了一个非常有效的观点 如果你想继续自己滚动(也许你确实有充分的理由),我会提出以下几点:

  • 您所说的是身份验证服务,而不是授权服务。只是为了确保你知道你在说什么......?
  • 其次,您需要将盐(非秘密)和密钥(即)密钥分开。你应该有一个键控哈希(例如HMAC),以及盐(或一个带键的盐渍哈希。听起来像一个三明治。)。如上所述,盐并不是秘密,但应该更改为FOR EACH TOKEN,并且可以包含在标题中;关键必须是秘密的,每天都要改变是好的。当然,请确保您使用强哈希(例如SHA-256),正确的密钥管理技术等。

再一次,我敦促你重新考虑自己,但如果你必须自己出去......