是否应该使用相同的密钥进行签名和加密?Azure 培训实验室正在采用这种方法

信息安全 应用安全 密码学 密钥管理 wcf 天蓝色
2021-08-13 16:46:01

我正在使用 WCF 进行 Azure 实验室 LoadBalancing,并从安全角度认识到我被告知的内容很糟糕,但我不确定它是否适用于此。

有人可以查看此代码并告诉我是否应该在生产代码中使用不同的证书?

public class RsaSessionSecurityTokenHandler : SessionSecurityTokenHandler
    {
        public RsaSessionSecurityTokenHandler(X509Certificate2 certificate)
        {
            List<CookieTransform> transforms = new List<CookieTransform>();
            transforms.Add(new DeflateCookieTransform());
            transforms.Add(new RsaEncryptionCookieTransform(certificate));
            transforms.Add(new RsaSignatureCookieTransform(certificate));
            this.SetTransforms(transforms);
        }

        public override ClaimsIdentityCollection ValidateToken(SessionSecurityToken token, string endpointId)
        {
            if (token == null)
            {
                throw new ArgumentNullException("token");
            }
            if (String.IsNullOrEmpty(endpointId))
            {
                throw new ArgumentException("endpointId");
            }

            // in active cases where absolute uris are used check the all parts of the token's 
            // endpoint id and this endpoint's id for equality except the port number
            Uri listenerEndpointId;
            bool listenerHasUri = Uri.TryCreate(endpointId, UriKind.Absolute, out listenerEndpointId);
            Uri tokenEndpointId;
            bool tokenHasUri = Uri.TryCreate(token.EndpointId, UriKind.Absolute, out tokenEndpointId);
            if (listenerHasUri && tokenHasUri)
            {
                if (listenerEndpointId.Scheme != tokenEndpointId.Scheme ||
                    listenerEndpointId.DnsSafeHost != tokenEndpointId.DnsSafeHost ||
                    listenerEndpointId.AbsolutePath != tokenEndpointId.AbsolutePath)
                {
                    throw new SecurityTokenValidationException(String.Format("The incoming token for '{0}' is not scoped to the endpoint '{1}'.", tokenEndpointId, listenerEndpointId));
                }
            }
            // in all other cases, fall back to string comparison
            else if (String.Equals(endpointId, token.EndpointId, StringComparison.Ordinal) == false)
            {
                throw new SecurityTokenValidationException(String.Format("The incoming token for '{0}' is not scoped to the endpoint '{1}'.", token.EndpointId, endpointId));
            }

            return this.ValidateToken(token);
        }
    }
4个回答

一般的最佳实践是使用两个单独的密钥对(以及证书)进行签名与加密。我刚刚刷新了自己的原因:

  • 当使用密钥进行加密时,将其托管通常是明智的,这样即使丢失了,加密的内容也不会丢失。但是,与签名证书相关的不可否认性对于周围的密钥对的多个副本是不可行的。所以你不想托管签名证书。来自 维基百科

这是我听说过的最好的一个。很多时候我被告知的是“做它”,并且考虑到一个人经常必须在 PKI 的约束范围内工作,一个人被迫使用,这是一个足够公平的说法。

就个人而言,我认为对于一个简单的 PKI,将两者捆绑在一起 - 特别是如果您将密钥的“加密”功能用于 SSL 之类的东西 - 一种用于点对点通信的临时加密类型 - 那么安全风险不是这么高。

但是——有时您必须准备好使用任何出现的 PKI。因此,如果代码硬编码了加密证书和签名证书总是相同的假设,那么我认为您存在互操作性问题。

最后一件事——我对代码有点困惑——我假设“ValidateToken”会验证令牌上的签名,对吧?它不能同时使用相同的密钥对解密和验证签名......加密用于发送给密钥对持有者,签名用于验证来自密钥对持有者的信息。它只是在这里进行签名验证吗?

许多人指出密钥托管是分离加密密钥和签名密钥的一个原因。许多人还提到,在这种特殊情况下,这种密钥的共享使用很好。但是没有人提到共享密钥以进行签名和加密的加密问题

如果您查看密码学的官方标准,它们中的大多数都指定不同的密钥用于不同的算法。对于 X509 证书,密钥使用部分对密钥的用途有非常具体的控制。例如,NIST 对椭圆曲线键有这样的说法:

ECDSA 密钥只能用于 ECDSA 数字签名的生成和验证

这样做的原因是,如果多个不同的算法与同一个密钥一起使用,那么必须证明所有算法组合在一起的安全性,而不仅仅是一个算法。否则,攻击者可能会使用一种算法产生一个他自己无法计算的值来攻击另一种算法的安全性。

例如,假设,签署任意远程值的密钥协商协议可用于伪造有效签名。或者,发送要签名的公钥可能会揭示对攻击密钥协议有用的值。或者具体来说,在 RSA 的情况下,如果不使用安全填充,如果使用相同的密钥,发送要签名的值可以解密密文。

因此,除非您可以非常确定签名和加密算法确实可以与相同的密钥一起使用,否则您不应该这样做。即使您非常确定,这也是不好的密码实践。而且,如果您需要遵循标准,无论如何,他们不会让您这样做。

在这种特殊情况下,这种技术很好。

您使用相同的加密密钥(在本例中为 X.509 证书)进行自我加密。您提到的示例实现了一个会话令牌(简单地说是一个受保护的 cookie),它在位于负载均衡器后面的多个类似 Web 服务之间共享。因此,“签名”(在此特定场景中)的安全目标不是提供不可否认性,而是提供数据源身份验证,即基本上确定会话令牌是否由对等服务之一创建。

注意:在签名服务于不可否认目标的其他情况下,您应该使用单独的密钥材料(正如此处其他答案正确指出的那样)。

有人可以查看此代码并告诉我是否应该在生产代码中使用不同的证书?

首先,任何用于安全功能的代码都应该在投入生产环境之前进行设计、设计审查、实施、代码审查和测试。仅仅因为代码来自 MSDN 并不意味着它是安全的。即使您决定使用编写的代码,也请不要跳过设计。该设计可能会帮助您发现更大的系统范围问题。

正如 bethlakshmi 和 Rook 所指出的,该证书被用于加密(机密性)和数字签名(识别和身份验证)。一般来说,您应该为不同的功能使用不同的证书(或密钥)。或者更简单地说,证书应该只用于一个功能。

在这种情况下,对这两个功能使用相同的证书看起来没问题。即使其中一项操作失败并且消息仍然被发送出去,证书的任何部分看起来都不会暴露,除非RsaEncryptionCookieTransformRsaEncryptionCookieTransform有错误。并且发送一条加密成功但没有签名或签名但没有加密的消息看起来没问题。

如果您决定为这两个功能使用一个证书,请确保在您的密钥管理计划和威胁模型中突出显示它。