【问题标题】:Base64 Encoding safe for filenames?Base64 编码对文件名安全吗?
【发布时间】:2010-10-15 19:42:50
【问题描述】:

Base64 编码是否可以安全地用于 Windows 和 Linux 系统上的文件名?根据我的研究,我发现用- 或_ 替换结果中的所有/ 字符应该可以解决任何问题。

谁能提供更多细节?

目前在 Java 中,我正在使用以下代码:

MessageDigest md5Digest = MessageDigest.getInstance("MD5");
md5Digest.reset();
md5Digest.update(plainText.getBytes());

byte[] digest = md5Digest.digest();

BASE64Encoder encoder = new BASE64Encoder();
hash = encoder.encode(digest);
hash.replace('/','_');

【问题讨论】:

  • / 似乎是一个有效的 base64 字符(第 63 位),但我从未在现实世界中见过它:en.wikipedia.org/wiki/Base64
  • 请注意,Windows 文件系统不区分大小写。你不能指望一个唯一的哈希映射到一个唯一的文件。

标签: java hash encoding base64 filenames


【解决方案1】:

修改后的 Base64(当 /、= 和 + 被替换时)可以安全地创建名称,但由于许多文件系统和 URL 不区分大小写,因此不能保证反向转换。

Base64 区分大小写,因此在不区分大小写的文件系统(所有 Windows 文件系统,忽略 POSIX 子系统情况)的情况下,它不能保证一对一的映射。大多数 url 也不区分大小写,防止一对一映射。

在这种情况下,我会使用 Base32 - 你会得到更长的名称,但 Base32 编码值对于文件/uri 的使用是 100% 安全的,无需替换任何字符,并且即使在不敏感的情况下也能保证 1 对 1 映射环境(FAT/Win32 NTFS 访问)。

不幸的是,框架中通常没有对这种编码的内置支持。另一方面,代码相对简单,可以自己编写或在线查找。

http://en.wikipedia.org/wiki/Base32.

【讨论】:

  • 可以在php中使用base_encode函数,见stackoverflow.com/questions/1848601/…
  • @Mark base_encode 仅适用于可以在 PHP 中表示为数字的值,并且确切的精度取决于平台,但是任何超过 14 位十进制数字(大约 9 个 base32 位)的值可能不会保留整数精度,使其不适合字符串/哈希。
  • Guava 现在支持Base32 encoding。
  • 修改后的 Base64(当 /、= 和 + 被替换时)可以安全地创建名称,但由于许多文件系统和 URL 不区分大小写,因此不能保证反向转换。 可以你解释的详细吗?
  • @gstackoverflow Base64 区分大小写,因此如果您想将转换回字节,则必须保留大小写(“Baaa”->“05 A6 9A”,但“BAAA”=>“04 00 00”)。在 FAT/FAT32 上,文件名被规范化为大写 - 因此您无法将从文件系统读取的文件名转换回字节数组。同样,Urls 的参数经常被标准化(通常是由于误解,但仍然)导致同样的问题。此外,一些文件系统 (NTFS) 区分大小写,但不允许名称因大小写而异 - 因此您不能从不同的字节构造“唯一”NTFS 名称。
【解决方案2】:

RFC 3548 建议不仅要替换 / 字符。 URL 和文件名安全 字母替换:

  • 63:nd / 带有下划线 _ 的字符
  • 第 62:nd + 字符加上减号 -。

但也许你最好使用 HEX-String。已经有一段时间了,我在文件名中存储了一个哈希值。我开始使用 Base64 字符串,但切换到十六进制字符串。我不记得我为什么切换了,可能是因为 Windows 没有像 AndiDog 所说的那样区分“a”和“A”。

【讨论】:

    【解决方案3】:

    我不确定您使用的编码是什么,但请考虑percent encoding 文件名。

    • 它适用于每个文件系统
    • 只要文件名在 ASCII 范围内,它就会使文件名易于阅读

    【讨论】:

      【解决方案4】:

      通常 MD5 哈希(通常是哈希)表示为十六进制字符串而不是 Base64,后者仅包含 [a-f0-9]。所有文件系统都支持这些名称。

      如果您真的想使用 Base64,您的解决方案(替换斜杠)将无法正常工作,因为 Windows 文件系统不会在“A”和“a”之间产生差异。也许您想改用 Base32?但请注意,Base32 使 4 位中有 8 位,因此仅采用十六进制表示会更容易。

      一般情况下,Windows 和/或 Linux 中不允许使用以下字符:\ / : * ? " |

      【讨论】:

      • 在 actuality 中,Linux(和许多 UNIX 衍生产品)中唯一被禁止的字符是它们本机文件系统上的 / 和 NUL。通常没有必要(并且令人困惑)远离更具限制性的 Windows 设置。这是一个breakdown by filesystem(并假设程序根据目标限制正确编写;然后,即使是 Windows 资源管理器也未能通过对有效 FAT32 和 NTFS 文件名的测试多年..)。
      【解决方案5】:

      用于 C# 的单行代码:

      String filename = Convert.ToBase64String(new SHA256Managed().ComputeHash(Encoding.UTF8.GetBytes("UTF-8 string with snowmen"))).Replace("+", "_").Replace("/", "-").Replace("=","");
      

      文件开头需要以下内容:

      using System.Security.Cryptography
      using System.Text
      

      【讨论】:

      • 这并没有解决不区分大小写的问题。
      • 我不会称之为单行.. 阅读代码时需要水平滚动
      【解决方案6】:

      Base64 创建的文件名只有在使用与 / 不同的字符时才是安全的,因为 NTFS 不允许在文件名中使用该字符。只要你这样做,几乎常用的all commonly used file systems 都可以。

      但是,如果文件系统不区分大小写,就像在 Windows 上一样,您可能会发生冲突,因为 Base64 字母表同时包含大写和小写。

      您可能需要考虑使用 MD5 哈希的十六进制表示,因为这是将它们表示为字符串的一种相当标准的方式。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-01-23
        • 1970-01-01
        • 1970-01-01
        • 2014-09-12
        • 1970-01-01
        • 2020-08-29
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多