这种签名 URL 的实现是否相当安全?

Sho*_*nte 6 c# security signing hmac .net-core

我正在尝试实现签名 URL 以实现对静态文件的短期访问。这个想法是:

  • 生成带有过期时间戳的 URL(例如https://example.com/file.png?download=false&expires=1586852158
  • 使用 HMACSHA256 和共享密钥对其进行签名,并将签名附加在 URL 末尾(例如https://example.com/file.png?download=false&expires=1586852158&signature=6635ea14baeeaaffe71333cf6c7fa1f0af9f6cd1a17abb4e75ca275dec5906d1

当我在服务器上收到请求时,我取出signature参数并验证使用 HMACSHA256 签名的 URL 的其余部分以及相同的共享密钥是否会产生相同的签名。

实现如下:

    public static class URLSigner
    {
        private static string GetSignatureForUri(string uri, byte[] key)
        {
            var hmac = new HMACSHA256(key);
            var signature = hmac.ComputeHash(Encoding.UTF8.GetBytes(uri));
            var hexSignature = BitConverter.ToString(signature).Replace("-", string.Empty).ToLowerInvariant();
            return hexSignature;
        }

        public static string SignUri(string uri, byte[] key)
        {
            var hexSignature = GetSignatureForUri(uri, key);
            return QueryHelpers.AddQueryString(uri, new Dictionary<string, string> { { "signature", hexSignature }});
        }

        public static bool VerifyUri(string uri, byte[] key)
        {
            var signatureRegex = "[\\?&]signature=([a-z0-9]+)$";
            var signatureMatch = Regex.Match(uri, signatureRegex);
            if (!signatureMatch.Success || signatureMatch.Groups.Count != 2)
                return false;
            var parsedSignature = signatureMatch.Groups[1].Value;

            var originalUri = Regex.Replace(uri, signatureRegex, "");
            var hexSignature = GetSignatureForUri(originalUri, key);
            return hexSignature == parsedSignature;
        }
    }
Run Code Online (Sandbox Code Playgroud)

它的用法如下:

var signedUri = URLSigner.SignUri("https://example.com/file.png?download=false", secretKey);
var isVerified = URLSigner.VerifyUri(signedUri, secretKey);
Run Code Online (Sandbox Code Playgroud)

这种签名 URL 的实现是否相当安全?

Mat*_*ice 4

您的实现似乎缺少过期时间的验证,因此任何一个密钥当前都可以无限期地工作。

除此之外,我认为这种方法总体上没有任何问题。不过,您可能希望添加一个超出时间戳的密钥,以便以某种方式识别用户或请求。

这是一篇关于如何将一般方法用于一次性密码的好文章,这基本上就是您正在做的事情。

https://www.freecodecamp.org/news/how-time-based-one-time-passwords-work-and-why-you-should-use-them-in-your-app-fdd2b9ed43c3/