代码之家  ›  专栏  ›  技术社区  ›  Randal Schwartz

使用对称加密保护Perl中不可篡改的URL组件?

  •  10
  • Randal Schwartz  · 技术社区  · 14 年前

    好吧,我可能只是星期一过得不好,但我有以下需要,我看到了很多部分的解决方案,但我确信我不是第一个需要这个的人,所以我想知道我是否错过了明显的问题。

    $client有50到500个字节的二进制数据,必须插入到URL中间并往返于客户的浏览器中。因为它是URL的一部分,所以我们遇到了get URL的1K“理论”限制。另外,$client不希望他们的客户解码数据,或者在没有检测到的情况下篡改数据。$client也不希望存储任何服务器端的内容,因此这必须是完全独立的。必须是Perl代码,并且在编码和解码中都是快速的。

    我认为最后一步可以是base64。但是,加密和散列最有意义的步骤是什么?

    4 回复  |  直到 14 年前
        1
  •  5
  •   perigrin    14 年前

    我在一个使用 Crypt::Util 为电子邮件验证链接编码/解码用户的电子邮件地址。

    我建立了一个 隐窝::UTIL 模型应用 Catalyst::Model::Adaptor 用一把密匙。然后在我的控制器中,我在发送端具有以下逻辑:

    my $cu = $c->model('CryptUtil');
    my $token = $cu->encode_string_uri_base64( $cu->encode_string( $user->email ) );
    my $url = $c->uri_for( $self->action_for('verify'), $token );
    

    我将此链接发送到 $user->email 当它被点击时,我使用下面的内容。

    my $cu = $c->model('CryptUtil');
    if ( my $id = $cu->decode_string( $cu->decode_string_uri_base64($token) ) ) {
        # handle valid link
    } else { 
        # invalid link
    }
    

    这基本上是什么 edanite 刚刚在另一个答案中提出。你只需要确保你所使用的任何数据都能形成最终的标记。 $url 不要超过你的任意限制。

        2
  •  4
  •   gmacon    14 年前

    创建一个密钥并将其存储在服务器上。如果有多个服务器,并且不能保证请求返回到同一个服务器;您需要在每个服务器上使用相同的密钥。此键应定期旋转。

    如果在CBC(密码块链接)模式下加密数据(请参阅crypt::cbc模块),则加密的开销最多为两个块(一个用于IV,另一个用于填充)。128位(即16字节)块是常见的,但不是通用的。我建议使用aes(aka rijndael)作为块密码。

    您需要对数据进行身份验证,以确保它没有被修改。根据应用程序的安全性,只需散列消息并将散列包含在您加密的纯文本中就足够了。这取决于攻击者无法在不知道对称加密密钥的情况下更改哈希以匹配消息。如果您使用128位密钥进行密码,请使用像sha-256这样的256位哈希(您可以使用摘要模块进行此操作)。您还可能希望在数据中包含一些其他内容,如时间戳,以防止请求重复多次。

        3
  •  3
  •   Schwern    14 年前

    我看到这里有三个台阶。首先,尝试压缩数据。由于数据太少,bzip2可能会为您节省5-20%。我会派一个警卫来确保数据不会变大。这一步可能不值得。

    use Compress::Bzip2 qw(:utilities);
    $data = memBzip $data;
    

    您还可以尝试手动减少数据中任何键和值的长度。例如, first_name 可以减少到 fname .

    其次,加密它。选择您最喜欢的密码并使用crypt::cbc。在这里我使用Rijndael是因为它对国家安全局足够好。您将希望进行基准测试,以找到性能和安全性之间的最佳平衡。

    use Crypt::CBC;
    my $key = "SUPER SEKRET";
    my $cipher = Crypt::CBC->new($key, 'Rijndael');
    my $encrypted_data = $cipher->encrypt($data);
    

    您必须将密钥存储在服务器上。把它放在一个受保护的文件中就足够了,确保该文件的安全是一个练习。当你说你不能在服务器上存储任何东西时,我想这不包括密钥。

    最后,base 64对其进行编码。我将使用修改后的url safe base 64,它使用-和u而不是+和/来避免您在base 64字符串中花费空间来编码这些字符。 MIME::Base64::URLSafe 涵盖这一点。

    use MIME::Base64::URLSafe;
    my $safe_data = urlsafe_b64encode($encrypted_data);
    

    然后把它贴到你想要的URL上。颠倒读取过程。

    你的尺寸应该是安全的。加密将增加数据的大小,但可能不到25%。Base 64将使数据大小增加三分之一(编码为2^6而不是2^8)。这将使编码500字节在1K内保持舒适。

        4
  •  -1
  •   bigiain    14 年前

    它需要多安全?你能用一个长的随机字符串XOR数据,然后用另一个秘密的salt添加整个批次的MD5散列来检测篡改吗?

    我不会将其用于银行数据,但它可能对大多数Web内容都很好…

    大的