Hướng dẫn php asymmetric encryption - mã hóa bất đối xứng php

Hướng dẫn

Xin chào! Nếu bạn đang đọc tệp này, đó là vì bạn muốn thêm mã hóa vào một trong các dự án PHP của mình. Công việc của tôi, với tư cách là người viết tài liệu này, là để giúp bạn đảm bảo rằng bạn đang làm đúng và sau đó chỉ cho bạn cách sử dụng thư viện này để làm điều đó. Để giúp tôi giúp bạn, xin vui lòng đọc tài liệu một cách cẩn thận và có chủ ý.

Nội phân chính

  • Một lời cảnh báo
  • Nhận mã
  • Sử dụng thư viện
  • Tài liệu chính thức
  • Kịch bản số 1: Giữ bí mật dữ liệu từ quản trị viên cơ sở dữ liệu
  • Kịch bản #2: Mã hóa dữ liệu tài khoản bằng mật khẩu đăng nhập của người dùng
  • Tìm sự giúp đỡ

Một lời cảnh báo

Nhận mã

Sử dụng thư viện

Tài liệu chính thức The most common use of cryptography in web applications is to protect the users' login passwords. If you're trying to use this library to "encrypt" your users' passwords, you're in the wrong place. Passwords shouldn't be encrypted, they should be hashed with a slow computation-heavy function that makes password guessing attacks more expensive. See How to Safely Store Your Users' Passwords in 2016.

Kịch bản số 1: Giữ bí mật dữ liệu từ quản trị viên cơ sở dữ liệu Likewise, if you're trying to encrypt messages sent between two parties over the Internet, you don't want to be using this library. For that, set up a TLS connection between the two points, or, if it's a chat app, use the Signal Protocol.

Kịch bản #2: Mã hóa dữ liệu tài khoản bằng mật khẩu đăng nhập của người dùng

Tìm sự giúp đỡencryption does not, and is not intended to, hide the length of the data being encrypted. For example, it is not safe to encrypt a field in which only a small number of different-length values are possible (e.g. "male" or "female") since it would be possible to tell what the plaintext is by looking at the length of the ciphertext. In order to do this safely, it is your responsibility to, before encrypting, pad the data out to the length of the longest string that will ever be encrypted. This way, all plaintexts are the same length, and no information about the plaintext can be gleaned from the length of the ciphertext.

Nhận mã

Sử dụng thư viện

Tài liệu chính thứcInstalling and Verifying documentation to get the code, and then come back here to continue the tutorial.

Sử dụng thư viện

Tài liệu chính thức

Kịch bản số 1: Giữ bí mật dữ liệu từ quản trị viên cơ sở dữ liệu

Tài liệu chính thức

Kịch bản số 1: Giữ bí mật dữ liệu từ quản trị viên cơ sở dữ liệu

Các lớp sau có sẵn để bạn sử dụng:

  • Crypto: Mã hóa và giải mã chuỗi.
  • Tệp: Mã hóa và giải mã các tệp.
  • Khóa: đại diện cho một khóa mã hóa bí mật.
  • KeyProtectedByPassword: Thể hiện khóa mã hóa bí mật cần được "mở khóa" bằng mật khẩu trước khi nó có thể được sử dụng.

Kịch bản số 1: Giữ bí mật dữ liệu từ quản trị viên cơ sở dữ liệu

Trong kịch bản này, mô hình mối đe dọa của chúng tôi như sau. Alice là quản trị viên máy chủ chịu trách nhiệm quản lý một máy chủ web đáng tin cậy. Eve là quản trị viên cơ sở dữ liệu chịu trách nhiệm quản lý máy chủ cơ sở dữ liệu. Dave là một nhà phát triển web làm việc trên mã cuối cùng sẽ chạy trên máy chủ web đáng tin cậy.

Hãy nói Alice và Dave tin tưởng lẫn nhau và Alice sẽ lưu trữ ứng dụng của Dave trên máy chủ của cô ấy. Nhưng cả Alice và Dave đều không tin tưởng Eve. Họ biết EVE là một quản trị viên cơ sở dữ liệu tốt, nhưng cô ấy có thể có động cơ đánh cắp dữ liệu từ cơ sở dữ liệu. Họ muốn giữ một số bí mật dữ liệu của ứng dụng web từ EVE.

Để làm điều đó, Alice sẽ sử dụng tập lệnh ____99 bao gồm tạo khóa mã hóa ngẫu nhiên và in nó thành đầu ra tiêu chuẩn:

$ composer require defuse/php-encryption
$ vendor/bin/generate-defuse-key

Alice sẽ chạy tập lệnh này một lần và lưu đầu ra vào tệp cấu hình, giả sử trong ____10 và đặt các quyền của tệp để chỉ người dùng mà trang web Php script chạy khi có thể truy cập nó.

Dave sẽ viết mã của mình để tải khóa từ tệp cấu hình:


use Defuse\Crypto\Key;

function loadEncryptionKeyFromConfig()
{
    $keyAscii = // ... load the contents of /etc/daveapp-secret-key.txt
    return Key::loadFromAsciiSafeString($keyAscii);
}

Sau đó, bất cứ khi nào Dave muốn tiết kiệm giá trị bí mật cho cơ sở dữ liệu, trước tiên anh ta sẽ mã hóa nó:


use Defuse\Crypto\Crypto;

// ...
$key = loadEncryptionKeyFromConfig();
// ...
$ciphertext = Crypto::encrypt($secret_data, $key);
// ... save $ciphertext into the database ...

Bất cứ khi nào Dave muốn lấy lại giá trị từ cơ sở dữ liệu, anh ta phải giải mã nó bằng cùng một khóa:


use Defuse\Crypto\Crypto;

// ...
$key = loadEncryptionKeyFromConfig();
// ...
$ciphertext = // ... load $ciphertext from the database
try {
    $secret_data = Crypto::decrypt($ciphertext, $key);
} catch (\Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException $ex) {
    // An attack! Either the wrong key was loaded, or the ciphertext has
    // changed since it was created -- either corrupted in the database or
    // intentionally modified by Eve trying to carry out an attack.

    // ... handle this case in a way that's suitable to your application ...
}

Lưu ý rằng nếu bất cứ ai từng đánh cắp khóa từ máy chủ của Alice, họ có thể giải mã tất cả các mã hóa được lưu trữ trong cơ sở dữ liệu. Là một phần của mô hình mối đe dọa của chúng tôi, chúng tôi giả định rằng các kỹ năng quản trị máy chủ của Alice và các kỹ năng mã hóa an toàn của Dave là đủ tốt để ngăn Eve không thể đánh cắp chìa khóa. Theo các giả định đó, giải pháp này sẽ ngăn EVE xem dữ liệu được lưu trữ trong cơ sở dữ liệu.

Tuy nhiên, lưu ý rằng mô hình mối đe dọa của chúng tôi không nói gì về những gì có thể xảy ra nếu EVE muốn sửa đổi dữ liệu. Với giải pháp này, EVE sẽ không thể thay đổi bất kỳ bản quyền riêng lẻ nào (vì mỗi bản mã có kiểm tra tính toàn vẹn mật mã riêng), nhưng EVE sẽ có thể hoán đổi mã hóa cho nhau và hoàn nguyên các mã hóa thành những gì họ đã từng là những thời điểm trước đó . Nếu chúng ta cần bảo vệ chống lại các cuộc tấn công như vậy, chúng ta sẽ phải thiết kế lại mô hình mối đe dọa của chúng ta và đưa ra một giải pháp khác.

Kịch bản #2: Mã hóa dữ liệu tài khoản bằng mật khẩu đăng nhập của người dùng

Kịch bản này giống như kịch bản 1, nhưng khác biệt một cách tinh tế. Mô hình mối đe dọa như sau. Chúng tôi có Alice, một quản trị viên máy chủ và Dave, nhà phát triển. Alice và Dave tin tưởng lẫn nhau và Alice muốn lưu trữ ứng dụng web của Dave, bao gồm cả cơ sở dữ liệu của nó, trên máy chủ của cô. Alice lo lắng về việc máy chủ của cô bị hack. Ứng dụng sẽ lưu trữ số thẻ tín dụng của người dùng và Alice muốn bảo vệ họ trong trường hợp máy chủ bị hack.

Chúng ta có thể mô hình hóa tình huống như thế này: sau khi máy chủ bị hack, kẻ tấn công sẽ đọc và ghi quyền truy cập vào tất cả dữ liệu trên đó cho đến khi phát hiện cuộc tấn công và Alice xây dựng lại máy chủ. Chúng tôi sẽ gọi thời gian kẻ tấn công có quyền truy cập vào máy chủ cửa sổ phơi sáng. Một ý tưởng để giảm thiểu tổn thất là mã hóa số thẻ tín dụng của người dùng bằng cách sử dụng khóa được tạo từ mật khẩu đăng nhập của họ. Sau đó, miễn là người dùng đều có mật khẩu mạnh và họ không bao giờ đăng nhập trong cửa sổ phơi sáng, thẻ tín dụng của họ sẽ được bảo vệ khỏi kẻ tấn công.

Để thực hiện điều này, Dave sẽ sử dụng lớp


use Defuse\Crypto\Key;

function loadEncryptionKeyFromConfig()
{
    $keyAscii = // ... load the contents of /etc/daveapp-secret-key.txt
    return Key::loadFromAsciiSafeString($keyAscii);
}
1. Khi tài khoản người dùng mới được tạo, Dave sẽ lưu một khóa mới vào tài khoản của họ, tài khoản được bảo vệ bằng mật khẩu đăng nhập của họ:


use Defuse\Crypto\KeyProtectedByPassword;

function CreateUserAccount($username, $password)
{
    // ... other user account creation stuff, including password hashing

    $protected_key = KeyProtectedByPassword::createRandomPasswordProtectedKey($password);
    $protected_key_encoded = $protected_key->saveToAsciiSafeString();
    // ... save $protected_key_encoded into the user's account record
}

CẢNH BÁO: Do cách thực hiện


use Defuse\Crypto\Key;

function loadEncryptionKeyFromConfig()
{
    $keyAscii = // ... load the contents of /etc/daveapp-secret-key.txt
    return Key::loadFromAsciiSafeString($keyAscii);
}
1, biết

use Defuse\Crypto\Key;

function loadEncryptionKeyFromConfig()
{
    $keyAscii = // ... load the contents of /etc/daveapp-secret-key.txt
    return Key::loadFromAsciiSafeString($keyAscii);
}
3 là đủ để giải mã

use Defuse\Crypto\Key;

function loadEncryptionKeyFromConfig()
{
    $keyAscii = // ... load the contents of /etc/daveapp-secret-key.txt
    return Key::loadFromAsciiSafeString($keyAscii);
}
1. Để được bảo mật, ứng dụng của bạn không được tính toán

use Defuse\Crypto\Key;

function loadEncryptionKeyFromConfig()
{
    $keyAscii = // ... load the contents of /etc/daveapp-secret-key.txt
    return Key::loadFromAsciiSafeString($keyAscii);
}
3 và sử dụng hoặc lưu trữ nó vì bất kỳ lý do gì. Bạn cũng phải đảm bảo rằng các thư viện khác mà ứng dụng của bạn đang sử dụng cũng không tính toán.
Because of the way

use Defuse\Crypto\Key;

function loadEncryptionKeyFromConfig()
{
    $keyAscii = // ... load the contents of /etc/daveapp-secret-key.txt
    return Key::loadFromAsciiSafeString($keyAscii);
}
1 is implemented, knowing

use Defuse\Crypto\Key;

function loadEncryptionKeyFromConfig()
{
    $keyAscii = // ... load the contents of /etc/daveapp-secret-key.txt
    return Key::loadFromAsciiSafeString($keyAscii);
}
3 is enough to decrypt a

use Defuse\Crypto\Key;

function loadEncryptionKeyFromConfig()
{
    $keyAscii = // ... load the contents of /etc/daveapp-secret-key.txt
    return Key::loadFromAsciiSafeString($keyAscii);
}
1. To be secure, your application MUST NOT EVER compute

use Defuse\Crypto\Key;

function loadEncryptionKeyFromConfig()
{
    $keyAscii = // ... load the contents of /etc/daveapp-secret-key.txt
    return Key::loadFromAsciiSafeString($keyAscii);
}
3 and use or store it for any reason. You must also make sure that other libraries your application is using don't compute it either.

Sau đó, khi người dùng đăng nhập, mã của Dave sẽ tải khóa được bảo vệ từ bản ghi tài khoản của người dùng, mở khóa để nhận đối tượng


use Defuse\Crypto\Key;

function loadEncryptionKeyFromConfig()
{
    $keyAscii = // ... load the contents of /etc/daveapp-secret-key.txt
    return Key::loadFromAsciiSafeString($keyAscii);
}
6 và lưu đối tượng

use Defuse\Crypto\Key;

function loadEncryptionKeyFromConfig()
{
    $keyAscii = // ... load the contents of /etc/daveapp-secret-key.txt
    return Key::loadFromAsciiSafeString($keyAscii);
}
6 ở đâu đó an toàn (như lưu trữ phiên được hỗ trợ bộ nhớ tạm thời hoặc cookie). Lưu ý rằng bất cứ nơi nào mã của Dave lưu khóa, nó phải bị phá hủy khi người dùng đăng xuất, nếu không kẻ tấn công có thể tìm thấy các khóa của người dùng ngay cả khi chúng không bao giờ đăng nhập trong cuộc tấn công.


use Defuse\Crypto\KeyProtectedByPassword;

// ... authenticate the user using a good password hashing scheme
// keep the user's password in $password

$protected_key_encoded = // ... load it from the user's account record
$protected_key = KeyProtectedByPassword::loadFromAsciiSafeString($protected_key_encoded);
$user_key = $protected_key->unlockKey($password);
$user_key_encoded = $user_key->saveToAsciiSafeString();
// ... save $user_key_encoded in a cookie

// ... when the user is logging out ...
// ... securely wipe the saved $user_key_encoded from the system ...

Khi người dùng thêm số thẻ tín dụng của họ, mã của Dave sẽ nhận khóa từ phiên hoặc cookie được hỗ trợ bộ nhớ và sử dụng nó để mã hóa số thẻ tín dụng:


use Defuse\Crypto\Crypto;
use Defuse\Crypto\Key;

// ...

$user_key_encoded = // ... get it out of the cookie ...
$user_key = Key::loadFromAsciiSafeString($user_key_encoded);

// ...

$credit_card_number = // ... get credit card number from the user
$encrypted_card_number = Crypto::encrypt($credit_card_number, $user_key);
// ... save $encrypted_card_number in the database

Khi ứng dụng cần sử dụng số thẻ tín dụng, nó sẽ giải mã nó:


use Defuse\Crypto\Crypto;
use Defuse\Crypto\Key;

// ...

$user_key_encoded = // ... get it out of the cookie
$user_key = Key::loadFromAsciiSafeString($user_key_encoded);

// ...

$encrypted_card_number = // ... load it from the database ...
try {
    $credit_card_number = Crypto::decrypt($encrypted_card_number, $user_key);
} catch (Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException $ex) {
    // Either there's a bug in our code, we're trying to decrypt with the
    // wrong key, or the encrypted credit card number was corrupted in the
    // database.

    // ... handle this case ...
}

Với tất cả các cảnh báo cẩn thận, giải pháp này hạn chế tiếp xúc với số thẻ tín dụng trong trường hợp máy chủ của Alice bị hack trong một khoảng thời gian ngắn.Hãy nhớ nghĩ về các cuộc tấn công không bao gồm trong mô hình mối đe dọa của chúng tôi.Kẻ tấn công vẫn tự do thực hiện tất cả các loại có hại như sửa đổi dữ liệu của máy chủ có thể không bị phát hiện nếu Alice không có bản sao lưu an toàn để so sánh với.

Tìm sự giúp đỡ

Nếu bạn gặp khó khăn khi sử dụng thư viện, hãy xem liệu vấn đề của bạn đã được giải quyết bằng câu trả lời trong Câu hỏi thường gặp.