【问题标题】:Encrypt in Nodejs and Decrypt in PHP在 Nodejs 中加密和在 PHP 中解密
【发布时间】:2019-06-26 21:22:50
【问题描述】:

我正在尝试解密 PHP 中最初在 NodeJS 中加密的字符串。

PHP:

openssl_decrypt($raw_id, "aes-128-cbc", "s7UbmJpfm56r6CAC6mz7KVZdRc3Fxc4m", 0, null)

这似乎总是返回false

Nodejs 中的加密:

function encrypt(text) {
    var cipher = crypto.createCipher('aes-128-cbc', 's7UbmJpfm56r6CAC6mz7KVZdRc3Fxc4m');
    var encrypted = cipher.update(text, 'utf8', 'hex')
    encrypted  += cipher.final('hex')

    return encrypted; 
}

function decrypt(text) {
    var cipher = crypto.createDecipher('aes-128-cbc', 's7UbmJpfm56r6CAC6mz7KVZdRc3Fxc4m');
    var decrypted = cipher.update(text, 'hex', 'utf8')
    decrypted += cipher.final('utf8');

    return decrypted;
}

我基本上是想加密,例如Nodejs中的encrypt("Pizza"),发送到PHP页面(3879f91a59e9a458db62f905b0a488a1),然后从那里解密(openssl_decrypt: return Pizza)。

我知道这段代码不安全,因为我没有使用静脉注射,但我不知道如何添加。

【问题讨论】:

    标签: php encryption openssl node-crypto


    【解决方案1】:

    您的方法不安全,也可能成为中间人攻击的受害者,您应该始终使用 IV 和 HMAC
    你可以像这样在php中加密

    $key = substr('encyptionsec123342',0,32)
    function encrypt ($message, $method, $secret, &$hmac) {
        $iv = substr(bin2hex(openssl_random_pseudo_bytes(16)),0,16);
        $encrypted = base64_encode($iv) . openssl_encrypt($message, $method, $secret, 0, $iv);
        $hmac = hash_hmac('md5', $encrypted, $secret);
        return $encrypted;
    }
    
    function decrypt ($encrypted, $method, $secret, $hmac) {
        if (hash_hmac('md5', $encrypted, $secret) == $hmac) {
            $iv = base64_decode(substr($encrypted, 0, 24));
            return openssl_decrypt(substr($encrypted, 24), $method, $secret, 0, $iv);
        }
    }
    
    function encryptWithTSValidation ($message, $method, $secret, &$hmac) {
        date_default_timezone_set('UTC');
        $message = substr(date('c'),0,19) . "$message";
        return encrypt($message, $method, $secret, $hmac);
    }
    
    function decryptWithTSValidation ($encrypted, $method, $secret, $hmac, $intervalThreshold) {
        $decrypted = decrypt($encrypted, $method, $secret, $hmac);
        $now = new DateTime();
        $msgDate = new DateTime(str_replace("T"," ",substr($decrypted,0,19)));
        if (($now->getTimestamp() - $msgDate->getTimestamp()) <= $intervalThreshold) {
            return substr($decrypted,19);
        }
    }
    

    这是一种安全的 AES-256-CBC 方法,并使用 HMAC 来阻止中间人攻击。
    Node.js

    var secret = "encyptionsec123342";
    secret = secret.substr(0, 32);
    var method = 'AES-256-CBC';
    var encrypt = function(message, method, secret, hmac) {
        var iv = crypto.randomBytes(16).toString('hex').substr(0, 16);
        var encryptor = crypto.createCipheriv(method, secret, iv);
        var encrypted = new Buffer.alloc(iv).toString('base64') + encryptor.update(message, 'utf8', 'base64') + encryptor.final('base64');
        hmac = crypto.createHmac('md5', secret).update(encrypted).digest('hex');
        return encrypted;
    };
    var decrypt = function(encrypted, method, secret, hmac) {
        if (crypto.createHmac('md5', secret).update(encrypted).digest('hex') == hmac) {
            var iv = new Buffer.from(encrypted.substr(0, 24), 'base64').toString();
            var decryptor = crypto.createDecipheriv(method, secret, iv);
            return decryptor.update(encrypted.substr(24), 'base64', 'utf8') + decryptor.final('utf8');
        }
    };
    var encryptWithTSValidation = function(message, method, secret, hmac) {
        var messageTS = new Date().toISOString().substr(0, 19) + message;
        return encrypt(messageTS, method, secret, hmac);
    }
    var decryptWithTSValidation = function(encrypted, method, secret, hmac, intervalThreshold) {
        var decrypted = decrypt(encrypted, method, secret, hmac);
        var now = new Date();
        var year = parseInt(decrypted.substr(0, 4)),
            month = parseInt(decrypted.substr(5, 2)) - 1,
            day = parseInt(decrypted.substr(8, 2)),
            hour = parseInt(decrypted.substr(11, 2)),
            minute = parseInt(decrypted.substr(14, 2)),
            second = parseInt(decrypted.substr(17, 2));
        var msgDate = new Date(Date.UTC(year, month, day, hour, minute, second))
        if (Math.round((now - msgDate) / 1000) <= intervalThreshold) {
            return decrypted.substr(19);
        }
    }
    

    在php中进行加解密,

    $encrypted = encryptWithTSValidation($recipent, $method, $key, $hmac);
    $decrypted = decryptWithTSValidation($encrypted,$method,$key, $hmac, 60*60*12)//this is 12 hours 
    

    要生成 hmac,您可以使用简单的 md5 散列

    $hmac = hash_hmac('md5', $recipent, $key);
    

    在 node.js 中

    var decrypted = decryptWithTSValidation(encString, method, secret, hmac, 60 * 60);
    var encrypted = decryptWithTSValidation(string, method, secret, hmac);
    

    注意:确保在 nodejs 和 php 中加密和解密时创建一个 32 位的唯一密钥并且相同。还要保持安全,切勿将其存储在数据库中。
    代码参考:Encrypt string in PHP and decrypt in Node.js

    【讨论】:

    • @AppelFlap 乐于助人
    • 这里的中间人攻击是什么?如果您想提出更好的替代方案,建议将 Authenticated Encryption as AES-GCM 包含在 TLS 1.4 中
    • @kelalaka nodejs 用于“实时”应用程序,用户可能在网络套接字等中使用它。
    • @kelalaka 不,我的意思是操作员可能会在像 webscokets 这样的直接通信中使用它,也许这就是他像我以前那样集成 node.js 和 php 的原因
    猜你喜欢
    • 2021-07-08
    • 2018-09-27
    • 2013-02-12
    • 1970-01-01
    • 1970-01-01
    • 2015-02-05
    • 2018-07-04
    • 1970-01-01
    • 2013-02-06
    相关资源
    最近更新 更多