【问题标题】:Hashing Query String containing Special Characters not working包含特殊字符的哈希查询字符串不起作用
【发布时间】:2013-06-05 19:25:49
【问题描述】:

我发布了一些关于令牌和密码重置的问题,并最终设法解决了这一切。谢谢大家!

因此,在阅读某些字符在查询字符串中不起作用之前,我决定对查询字符串进行哈希处理,但正如您所猜到的那样,加号已被删除.

如何保护或散列查询字符串?

这是我收到的一封公司电子邮件的示例,字符串如下所示:

AweVZe-LujIAuh8i9HiXMCNDIRXfSZYv14o4KX0KywJAGlLklGC1hSw-bJWCYfia-pkBbessPNKtQQ&t=pr&ifl

在我的设置中,我只是使用 GUID。但这有关系吗?

在我的场景中,即使没有 GIUD,用户也无法访问密码页面。那是因为如果查询字符串与会话变量不匹配,页面设置为重定向 onload?

有没有办法处理查询字符串以给出上述结果?

这个问题更多的是关于获取知识。

更新:

这是哈希码:

    public static string QueryStringHash(string input)
    {
        byte[] inputBytes = Encoding.UTF8.GetBytes();
        SHA512Managed sha512 = new SHA512Managed();

        byte[] outputBytes = sha512.ComputeHash(inputBytes);
        return Convert.ToBase64String(outputBytes);
    }

然后我将 HASH (UserID) 传递给 SESSION,然后将其作为查询字符串发送: 在下一页上,Session HASH 与 Query 不同,导致值不匹配并导致查询字符串无效。

注意:我创建了一个名为 Encryption 的类来处理所有的哈希和加密。

Session["QueryString"] = Encryption.QueryStringHash(UserID);

Response.Redirect("~/public/reset-password.aspx?uprl=" +
  HttpUtility.UrlEncode(Session["QueryString"].ToString())); 

我也尝试了此页面上提到的所有内容,但没有运气:

How do I replace all the spaces with %20 in C#

感谢阅读。

【问题讨论】:

  • Mads Kristensen 有blogged 的相关内容,您可能想查看一下。
  • 那是因为页面设置为重定向 onload ... 那么,如果用户禁用 JavaScript,他们可以查看受限页面吗? (您永远不应该依赖客户端脚本来确保安全。)
  • 你知道UrlEncode/UrlDecode吗?
  • 我没有使用 JavaScript,也不打算为任何与安全相关的事情这样做。即使用户访问该页面,他们也需要有一个用户名。进入该页面需要回答密码问题并输入 12 位帐号或通过电子邮件发送链接。密码重置不提供用户名。顺便说一句,如果关闭 JS,页面仍然会重定向。
  • Aristos,我尝试了几种 Url Encoding 仍然无法正常工作。查询字符串不同。请参阅上面的更新代码:谢谢!

标签: c# asp.net


【解决方案1】:

在我必须在查询字符串中传递哈希之前,我做了一些事情。正如您所经历的那样,Base 64 与 URL 混合时可能会非常讨厌,因此我决定将其作为十六进制字符串传递。它有点长,但更容易处理。这是我的做法:

首先一种将二进制转换为十六进制字符串的方法。

    private static string GetHexFromData(byte[] bytes)
    {
        var output = new StringBuilder();
        foreach (var b in bytes)
        {
            output.Append(b.ToString("X2"));
        }
        return output.ToString();
    }

然后反向将十六进制字符串转换回二进制。

    private static byte[] GetDataFromHex(string hex)
    {
        var bytes = new List<byte>();
        for (int i = 0; i < hex.Length; i += 2)
        {
            bytes.Add((byte)int.Parse(hex.Substring(i, 2), System.Globalization.NumberStyles.HexNumber));
        }
        return bytes.ToArray();
    }

或者,如果您只需要验证哈希是否相同,只需将两者都转换为十六进制字符串并比较字符串(不区分大小写)。希望这会有所帮助。

【讨论】:

    【解决方案2】:

    问题在于 base64 编码使用 '+' 和 '/' 字符,它们在 URL 中具有特殊含义。如果要对查询参数进行 base64 编码,则必须更改这些字符。通常,这是通过将“+”和“/”分别替换为“-”和“_”(破折号和下划线)来完成的,如 RFC 4648 中所述。

    那么,在你的代码中,你会这样做:

    public static string QueryStringHash(string input)
    {
        byte[] inputBytes = Encoding.UTF8.GetBytes();
        SHA512Managed sha512 = new SHA512Managed();
    
        byte[] outputBytes = sha512.ComputeHash(inputBytes);
        string b64 = Convert.ToBase64String(outputBytes);
        b64 = b64.Replace('+', '-');
        return b64.Replace('/', '_');
    }
    

    当然,在接收端,您需要将“-”和“_”替换为相应的“+”和“/”,然后再调用从 base 64 转换的方法。

    他们建议不要使用填充字符 ('='),但如果你这样做,它应该是 URL 编码的。如果您始终知道编码字符串的长度,则无需传达填充字符。您可以在接收端添加所需的填充字符。但是如果你可以有可变长度的字符串,那么你就需要填充字符。

    每当您看到查询参数中使用 base 64 编码时,它就是这样做的。它无处不在,也许最常见于 YouTube 视频 ID。

    【讨论】:

    • 谢谢Jay:这些都是我可以研究和学习的资源。嘿吉姆。我正在研究替换的想法,但不知道其他角色偷偷溜进来了。我只是没精力了。我会对此进行更多研究,但我认为解决方案已经临近。再次感谢!
    • 为什么不直接对特殊字符进行 url 编码,而不是将它们更改为 - 和 _?
    • @JoePhillips 多种原因。首先,它增加了尺寸。其次,您必须对它们进行解码,这比单字符转换更耗时。与标准 base64 编码相比,它与仅更改字符有更大的不同。
    猜你喜欢
    • 2019-08-08
    • 2011-09-04
    • 2020-12-25
    • 2011-02-19
    • 2010-12-20
    • 1970-01-01
    • 1970-01-01
    • 2020-07-12
    • 2016-08-24
    相关资源
    最近更新 更多