如何使用 PHP 加密 URL(或者更确切地说是其中的 GET 参数部分)


How can I encrypt an URL (or rather the GET parameter part of it) using PHP?

我正在开发一个函数,通过我们应用程序的内置电子邮件发件人将表单链接整体发送,我计划只发送一个 url,其中包含它被发送到的实体的 id 和类型、表单的 ID 和一个告诉我在哪个数据库中查找的标识符(我们有多个包含客户端数据的数据库)。我正在寻找一种简单的方法来编码此信息。

我考虑过只发送一个 ID 并将所有内容保存在数据库中,但由于这些电子邮件可能会被集体发送用于营销或忠诚度活动,我认为这不是一个好主意。

用谷歌搜索了一些加密功能,但我尝试的加密功能有时会返回带有非法字符的结果,例如"?"和"&",这会破坏我的链接。

如果需要加密,请查找像 AES 这样的对称加密,然后对结果进行 base64 编码。

如果您只需要编码,那么通过 Base64 编码,这是您最好的选择。

并非在这两种情况下,您都需要注意某些浏览器 URL 长度或 Web 服务器 GET 支持是有限的......到一定长度(在 2000 到 80000 之间,具体取决于浏览器和 Web 服务器)

还要考虑链路需要如何传输。很长的网址不方便。您可以非常轻松地安装 yourls.org 或类似的方式来缩短您的 URL。

在我的所有应用程序中,我都使用base64_encode对 URL 进行编码,并在另一端使用base64_decode。

我相信这是最好的方法,因为您不会将敏感数据传输到客户端。

否则,您应该将这些URL保存在数据库中(或者可能是参数),然后发送一个ID

由于您不希望客户端可以解码信息,这意味着您不需要完整的URL - 执行线程必须返回到服务器进行处理。在这种情况下,为什么要为加密费用而烦恼 - 只需分配一个引用原始 id 的随机数(检查冲突)。显然,随机数集越稀疏,发生碰撞的可能性就越小。

在我自行开发的 CMS 控制面板中,如果您尝试访问 URL 并且未登录,则会重定向到如下所示的 URL(例如): /?return=Epf7psjPeRHeEsCoa56xvvF9QiaT%2B02P5FUSbA0Ttl%2Bv3LalZ26sqzSAV6WrNKNWK%2FDD%2FngSbVjJ%2FyUuG9QIWA%3D%3D

成功进行身份验证后,您将返回到正确的 URL。如果您试图篡改此一团数据,它将(以压倒性的几率)将您踢到主页。

如果这就是你要找的,这就是我实现它的方式:

if ($_SERVER['REQUEST_URI'] !== '/') {
    if (empty($_SESSION['cms_user_id_key_here'])) {
        $encrypted = 'Defuse'Crypto'Crypto::encrypt(
            $_SERVER['REQUEST_URI'],
            URL_KEY_CONST
        );
        header('Location: /?return='.urlencode(base64_encode($encrypted)));
        exit;
    }
}

然后,成功登录后:

if (isset($_GET['return'])) {
    try {
        $decrypted = 'Defuse'Crypto'Crypto::encrypt(
            base64_decode($_GET['return'],
            URL_KEY_CONST
        );
        // Defense-in-depth; we always want a relative URL:
        if ($decrypted[0] === '/') {
            header('Location: '.$decrypted);
        } else {
            header('Location: /');
        }
    } catch ('Defuse'Crypto'Exception'CryptoException $e) {
        header('Location: /');
    }
    exit;
}

你问这个神秘的'Defuse'Crypto'Crypto::encrypt()'Defuse'Crypto'Crypto::decrypt()是什么?当然,它是 defuse/php 加密。

在几乎所有情况下,您应该优先使用提供经过身份验证的加密的库,而不是滚动您自己的未经身份验证的加密。