PHP 与 JavaScript 端之间的加密解密
只是为了好玩,让我们在客户端JavaScript中加密一些内容,然后让PHP服务器对其进行解密。请注意这个 不会取代TLS (HTTPS).
使用 Nadium Plus 的 JavaScript 加密
你需要 最新版的 sodium-plus (在撰写本文时,它是 version 0.4.0.)
<script
src="/static/js/sodium-plus.min.js"
integrity="sha384-lv7SVE0eb0bXA3fgK6PwlhViiUwG6tBuMAhS8XX7RvBvyRcdEdJ8HKtFgs4vHTUh"
></script>
接下来,您将要编写一些JavaScript代码来加密消息并将其发送到服务器。我将在此示例中使用jQuery,但是您可以轻松地使其适应使用XMLHttpRequest
对象。
让我们定义两个函数。人们从硬编码的字符串中加载了一个CryptographyKey
对象(n.b.您从不想真正这样做,但是为了简单易用的示例,我们使用了硬编码的秘密)。另一个实际上加密了一条消息。
/**
* 获取示例密钥。在现实世界中,你需要随机生成这些。
*/
async function getExampleKey() {
if (!window.sodium) window.sodium = await SodiumPlus.auto();
return CryptographyKey.from(
'e9897cea109576c2f8088c277125d553e4f83afbc0abbb92cfb1f7b776b4fee0',
'hex'
);
// return await sodium.crypto_secretbox_keygen();
}
/**
* 加密传入的 message.
*/
async function encryptMessage(message, key) {
if (!window.sodium) window.sodium = await SodiumPlus.auto();
let nonce = await sodium.randombytes_buf(24);
let encrypted = await sodium.crypto_secretbox(message, nonce, key);
return nonce.toString('hex') + encrypted.toString('hex');
}
接下来,您将要编写一个函数来收集用户输入,对其进行加密,然后将其发送到服务器。
async function sendEncryptedMessage() {
let key = await getExampleKey();
let message = $("#user-input").val();
let encrypted = await encryptMessage(message, key);
$.post("/send-message", {"message": encrypted}, function (response) {
console.log(response);
$("#output").append("<li><pre>" + response.message + "</pre></li>");
});
}
...以及一些支持HTML的内容:
<label for="user-input">Type a message to encrypt and send:</label>
<textarea id="user-input"></textarea>
<button id="send-it" type="button">Send Encrypted Message</button>
<hr />
<ol id="output"></ol>
<script type="text/javascript">
$("#send-it").on('click', sendEncryptedMessage);
</script>
使用 Sodium 解密 PHP
如果您使用的是 PHP 7.2 ,则很有可能只使用内置的 sodium_*
函数。但是,默认情况下某些发行版 可能 错误地禁用了钠扩展名。因此,为了安全起见,无论如何都要安装sodium_compat。
如果您使用的是框架(Symfony,Laravel),您的代码看起来会干净很多,但是为了说明起见,解密代码如下所示:
<?php
declare(strict_types=1);
require 'vendor/autoload.php'; // Composer
header('Content-Type: application/json');
$key = sodium_hex2bin('e9897cea109576c2f8088c277125d553e4f83afbc0abbb92cfb1f7b776b4fee0');
$encrypted = $_POST['message'] ?? null;
if (!$encrypted) {
echo json_encode(
['message' => null, 'error' => 'no message provided'],
JSON_PRETTY_PRINT
);
exit(1);
}
$nonce = sodium_hex2bin(substr($encrypted, 0, 48));
$ciphertext = sodium_hex2bin(substr($encrypted, 48));
$plaintext = sodium_crypto_secretbox_open($ciphertext, $nonce, $key);
echo json_encode(
['message' => $plaintext, 'original' => $encrypted],
JSON_PRETTY_PRINT
);
把它放在一起
当您键入一条消息并按下按钮时,它将对其进行加密并将十六进制编码的字符串发送到服务器。
然后,PHP代码将解密消息并以JSON响应返回纯文本。
然后,JavaScript代码将从JSON响应中获取纯文本,并将其附加到表单下方的输出字段。
安全考虑因素
这只是一个示例,用来说明如何使用 sodium-plus(JavaScript)和 libsodium(PHP)来加密/解密消息.
我们使用了很多的快捷方式,这些快捷方式是您在实际系统中不希望使用的(例如:对加密密钥进行硬编码,并为了简洁而避免进行错误检查)。
如果您想做更高级的事情 (JavaScript中的公钥加密 和 一致的PHP函数), 该文档可在线免费获得。
进一步阅读
本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。