Laravel 4 加密:需要多少个字符

Laravel 4 Encryption: how many characters to expect

我刚刚遇到了一个有趣的小问题。

使用Laravel 4,我在将一些条目添加到数据库之前对其进行了加密,包括电子邮件地址。

数据库设置为默认 varchar 长度 255。

我刚刚有一个加密为 309 个字符的条目,通过切断数据库中的最后 50 多个字符来破坏加密。

我已经(暂时)通过简单地将 varchar 长度增加到 500 来解决这个问题,这在理论上应该可以保护我免受此问题的影响,但我想确定一下。

我不确定加密是如何工作的,但是为了设置我的数据库,有没有办法判断加密输出的最大字符长度?

我是否应该将我的字段类型从 varchar 更改为其他类型以确保不再发生这种情况?

@MaartenBodewes 很好地解释了实际字符串 可能 的长度。但是你永远无法确定,所以这里有两种方法来处理这种情况。

1。让你的领域 text

将字段从有限的 varchar 更改为 "self-expanding" text。这可能是更简单的一个,特别是如果您希望输入相当长的内容,我绝对会推荐这个。

2。让你的 varchar 更长

正如您已经做的那样,根据您 expect/allow 的输入长度使您的 varchar 更长。我会乘以 5 倍。

但不要就此止步!在您的代码中添加检查以确保数据不会被截断:

$encrypted = Crypt::encrypt($input);
if(strlen($encrypted) > 500){
   // do something about it
}

你能做什么

您可以将错误写入日志并添加加密数据(这样您可以在扩展数据库字段的长度后手动重新插入它)

Log::error('An encrypted value was too long for the DB field xy. Length: '.strlen($encrypted).' Data: '.$encrypted);

显然,这意味着您必须经常检查日志(或通过邮件将日志发送给您),并且用户在使用应用程序时可能会遇到错误,因为您的数据库中的数据不正确。

另一种方法是抛出异常(并向用户显示错误),当然还将其写入日志以便您修复它...

无论如何

无论您选择选项 1 还是选项 2,您都应该始终限制输入字段的可接受长度。服务器端和客户端。

结论

首先请注意,4.0.0 和 4.2.16(似乎是最新版本)之间有不少变化。

该方案以 4.2 的 188 个字符和 4.0 的大约 244 个字符的惊人开销开始(假设我没有忘记任何换行符等)。所以为了安全起见,你可能需要 4.2 的 200 个字符和 4.0 的 256 个字符加上纯文本大小的 1.8 倍,if 明文中的字符被编码为单个字节.

分析

我刚刚研究了 source code of Laravel 4.0 and Laravel 4.2 关于此功能的内容。让我们先进入尺寸:

  1. 数据是序列化的,所以加密大小取决于值类型的大小(可能是字符串);
  2. 序列化数据是 PKCS#7 填充使用 Rijndael 256 或 AES,因此这意味着添加 1 到 32 字节或 1 到 16 字节 - 取决于使用 4.0 或4.2;
  3. 此数据使用密钥和 IV 加密;
  4. 密文和IV分别转base64;
  5. 在 base64 编码密文上使用 SHA-256 计算 HMAC,返回 64 字节的小写十六进制字符串
  6. 那么密文由base64_encode(json_encode(compact('iv', 'value', 'mac')))组成(这里的值当然是base 64密文,mac当然是HMAC值)。

PHP is serialized as s:<i>:"<s>"; 中的字符串,其中 <i> 是字符串的大小,<s> 是字符串(我假设 PHP 平台编码在这里大小)。请注意,我不是 100% 确定 Laravel 不会对字符串值使用任何环绕,也许有人可以帮我解决这个问题。

计算

总而言之,一切都在很大程度上取决于字符编码,我做出一个好的估计是相当危险的。现在假设字节和字符之间存在 1:1 关系(例如 US-ASCII):

  1. 对于最多999个字符的字符串,序列化最多添加9个字符
  2. padding 加起来为 16 或 32 个字节,我们假设它们也是字符
  3. 加密使数据保持相同大小
  4. PHP 中的
  5. base64 创建 ceil(len / 3) * 4 个字符 - 但让我们将其简化为 (len * 4) / 3 + 4,base 64 编码的 IV 是 44 个字符
  6. 完整的 HMAC 是 64 个字符
  7. JSON 编码为引号和冒号添加 3*5 个字符,加上 4 个字符用于括号和逗号,总共 19 个字符(我假设 json_encode 不以white space 这里,base 64 再次增加相同的开销

好的,所以我在这里有点累了,但是你可以看到它至少两次使用 base64 编码扩展明文。最后,这是一个增加了大量开销的方案;他们本可以使用 base64(IV|ciphertext|mac) 来大幅减少开销。

备注

  • 如果你现在不是 4.2,我会认真考虑升级到最新版本,因为 4.2 修复了很多安全问题
  • 示例代码中使用了字符串作为key,不知道用bytes代替是否方便;
  • 文档 确实 对除 Rijndael 默认值以外的密钥大小发出警告,但忘记提及字符串编码问题;
  • 总是执行填充,即使使用 CTR 模式,这也违背了目的;
  • Laravel 填充使用 PKCS#7 填充,但由于序列化似乎总是以 ; 结尾,这并不是真正必要的;
  • 很高兴看到将经过身份验证的加密用于数据库加密(未使用 IV,已在 4.2 中修复)。