可靠地检查字符串是否在.Net中进行base64编码

时间:2014-10-30 02:07:54

标签: c# .net base64

在我开始之前:是的,我已经在这里和其他地方检查过这个主题的其他问题和答案。

我找到了一个示例字符串,.Net将对其进行base64解码,即使它实际上并不是base64编码的。这是一个例子:

Rhinocort水性64mcg /剂量喷鼻剂

.Net方法Convert.FromBase64String在解码此字符串时不会抛出异常,因此我的IsBase64Encoded方法很乐意为此字符串返回true。

有趣的是,如果我使用此字符串作为输入使用cygwin base64 -d命令,它将失败并显示消息无效输入

更有趣的是,我认为属于这个可执行文件的源(http://libb64.sourceforge.net/)“解码”这个相同的字符串,其结果与我从.Net Convert.FromBase64String获得的结果相同。我会继续寻找其他地方的线索,但现在我很难过。

有什么想法吗?

2 个答案:

答案 0 :(得分:1)

还有一个更好的解决方案,它还会检查输入字符串的长度。

我建议您在开始时进行检查。如果输入为null或为空,则返回false

http://www.codeproject.com/Questions/177808/How-to-determine-if-a-string-is-Base-decoded-or

答案 1 :(得分:0)

当字符串确实通过 Base64 解码并且解码后的数据具有特殊字符时,也许我们可以断定它不是有效的 Base64(这取决于编码)。此外,有时我们期望传递的数据是 Base64,但有时它可能没有正确填充“=”。因此,一种方法对 Base64 使用“严格”规则,另一种方法是“宽容”。

    [TestMethod]
    public void CheckForBase64()
    {
        Assert.IsFalse(IsBase64DataStrict("eyJhIjoiMSIsImIiOiI2N2NiZjA5MC00ZGRiLTQ3OTktOTlmZi1hMjhhYmUyNzQwYjEiLCJmIjoiMSIsImciOiIxIn0"));
        Assert.IsTrue(IsBase64DataForgiving("eyJhIjoiMSIsImIiOiI2N2NiZjA5MC00ZGRiLTQ3OTktOTlmZi1hMjhhYmUyNzQwYjEiLCJmIjoiMSIsImciOiIxIn0"));
        Assert.IsFalse(IsBase64DataForgiving("testing123"));
        Assert.IsFalse(IsBase64DataStrict("ABBA"));
        Assert.IsFalse(IsBase64DataForgiving("6AC648C9-C08F-4F9D-A0A5-3904CF15ED3E"));
    }
    public bool IsBase64DataStrict(string data)
    {
        if (string.IsNullOrWhiteSpace(data)) return false;
        if ((new Regex(@"[^A-Z0-9+\/=]", RegexOptions.IgnoreCase)).IsMatch(data)) return false;
        if (data.Length % 4 != 0) return false;
        var e = data.IndexOf('=');
        var l = data.Length;
        if (!(e == -1 || e == l - 1 || (e == l - 2 && data[l - 1] == '='))) return false;
        var decoded = string.Empty;
        try
        {
            byte[] decodedData = Convert.FromBase64String(data);
            decoded = Encoding.UTF8.GetString(decodedData);
        }
        catch(Exception)
        {
            return false;
        }
        //check for special chars that you know should not be there
        char current;
        for (int i = 0; i < decoded.Length; i++)
        {
            current = decoded[i];
            if (current == 65533) return false;
            if (!((current == 0x9 || current == 0xA || current == 0xD) ||
                ((current >= 0x20) && (current <= 0xD7FF)) ||
                ((current >= 0xE000) && (current <= 0xFFFD)) ||
                ((current >= 0x10000) && (current <= 0x10FFFF))))
            {
                return false;
            }
        }
        return true;
    }

    public bool IsBase64DataForgiving(string data)
    {
        if (string.IsNullOrWhiteSpace(data)) return false;

        //it could be made more forgiving by replacing any spaces with '+' here

        if ((new Regex(@"[^A-Z0-9+\/=]", RegexOptions.IgnoreCase)).IsMatch(data)) return false;
        
        //this is the forgiving part
        if (data.Length % 4 > 0)
            data = data.PadRight(data.Length + 4 - data.Length % 4, '=');
        
        var e = data.IndexOf('=');
        var l = data.Length;
        if (!(e == -1 || e == l - 1 || (e == l - 2 && data[l - 1] == '='))) return false;
        var decoded = string.Empty;
        try
        {
            byte[] decodedData = Convert.FromBase64String(data);
            decoded = Encoding.UTF8.GetString(decodedData);
        }
        catch (Exception)
        {
            return false;
        }
        //check for special chars that you know should not be there
        char current;
        for (int i = 0; i < decoded.Length; i++)
        {
            current = decoded[i];
            if (current == 65533) return false;
            if (!((current == 0x9 || current == 0xA || current == 0xD) ||
                ((current >= 0x20) && (current <= 0xD7FF)) ||
                ((current >= 0xE000) && (current <= 0xFFFD)) ||
                ((current >= 0x10000) && (current <= 0x10FFFF))))
            {
                return false;
            }
        }
        return true;
    }