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 关于此功能的内容。让我们先进入尺寸:
- 数据是序列化的,所以加密大小取决于值类型的大小(可能是字符串);
- 序列化数据是 PKCS#7 填充使用 Rijndael 256 或 AES,因此这意味着添加 1 到 32 字节或 1 到 16 字节 - 取决于使用 4.0 或4.2;
- 此数据使用密钥和 IV 加密;
- 密文和IV分别转base64;
- 在 base64 编码密文上使用 SHA-256 计算 HMAC,返回 64 字节的小写十六进制字符串
- 那么密文由
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):
- 对于最多999个字符的字符串,序列化最多添加9个字符
- padding 加起来为 16 或 32 个字节,我们假设它们也是字符
- 加密使数据保持相同大小
PHP 中的 - base64 创建
ceil(len / 3) * 4
个字符 - 但让我们将其简化为 (len * 4) / 3 + 4
,base 64 编码的 IV 是 44 个字符
- 完整的 HMAC 是 64 个字符
- 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 中修复)。
我刚刚遇到了一个有趣的小问题。
使用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 关于此功能的内容。让我们先进入尺寸:
- 数据是序列化的,所以加密大小取决于值类型的大小(可能是字符串);
- 序列化数据是 PKCS#7 填充使用 Rijndael 256 或 AES,因此这意味着添加 1 到 32 字节或 1 到 16 字节 - 取决于使用 4.0 或4.2;
- 此数据使用密钥和 IV 加密;
- 密文和IV分别转base64;
- 在 base64 编码密文上使用 SHA-256 计算 HMAC,返回 64 字节的小写十六进制字符串
- 那么密文由
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):
- 对于最多999个字符的字符串,序列化最多添加9个字符
- padding 加起来为 16 或 32 个字节,我们假设它们也是字符
- 加密使数据保持相同大小 PHP 中的
- base64 创建
ceil(len / 3) * 4
个字符 - 但让我们将其简化为(len * 4) / 3 + 4
,base 64 编码的 IV 是 44 个字符 - 完整的 HMAC 是 64 个字符
- 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 中修复)。