Mã hóa hai chiều: Tôi cần lưu trữ mật khẩu có thể được truy xuất


174

Tôi đang tạo một ứng dụng sẽ lưu trữ mật khẩu mà người dùng có thể truy xuất và xem. Mật khẩu dành cho một thiết bị phần cứng, vì vậy việc kiểm tra chống băm là không cần thiết.

Điều tôi cần biết là:

  1. Làm cách nào để mã hóa và giải mã mật khẩu trong PHP?

  2. Thuật toán an toàn nhất để mã hóa mật khẩu là gì?

  3. Tôi lưu trữ khóa riêng ở đâu?

  4. Thay vì lưu trữ khóa riêng, có nên yêu cầu người dùng nhập khóa riêng bất cứ khi nào họ cần mật khẩu được giải mã không? (Người dùng của ứng dụng này có thể được tin cậy)

  5. Mật khẩu có thể bị đánh cắp và giải mã theo những cách nào? Tôi cần phải nhận thức được gì?


1
Lưu ý: Libsodium hiện được biên dịch vào lõi PHP với giá trị = = 7.2. Đây sẽ là giải pháp "đi đến" ngay bây giờ vì nó có đầy đủ các phương thức hiện đại không giống như mcrypt bị coi là không dùng nữa và đã bị xóa.
triển lãm

Câu trả lời:


212

Cá nhân, tôi sẽ sử dụng mcryptnhư những người khác đăng. Nhưng còn nhiều điều cần lưu ý ...

  1. Làm cách nào để mã hóa và giải mã mật khẩu trong PHP?

    Xem bên dưới để biết một lớp học mạnh mẽ chăm sóc mọi thứ cho bạn:

  2. Thuật toán an toàn nhất để mã hóa mật khẩu là gì?

    an toàn nhất ? bất kỳ trong số họ. Phương pháp an toàn nhất nếu bạn sẽ mã hóa là bảo vệ chống lại các lỗ hổng tiết lộ thông tin (XSS, bao gồm từ xa, v.v.). Nếu nó thoát ra, kẻ tấn công cuối cùng có thể bẻ khóa mã hóa (không mã hóa nào không thể đảo ngược 100% nếu không có khóa - Như @NullUserException chỉ ra điều này không hoàn toàn đúng. Có một số lược đồ mã hóa không thể bẻ khóa như OneTimePad ) .

  3. Tôi lưu trữ khóa riêng ở đâu?

    Những gì tôi sẽ làm là sử dụng 3 phím. Một là do người dùng cung cấp, một là dành riêng cho ứng dụng và một là dành riêng cho người dùng (như muối). Khóa cụ thể của ứng dụng có thể được lưu trữ ở bất cứ đâu (trong tệp cấu hình bên ngoài gốc web, trong biến môi trường, v.v.). Người dùng cụ thể sẽ được lưu trữ trong một cột trong db bên cạnh mật khẩu được mã hóa. Người dùng được cung cấp sẽ không được lưu trữ. Sau đó, bạn sẽ làm một cái gì đó như thế này:

    $key = $userKey . $serverKey . $userSuppliedKey;

    Lợi ích ở đây là bất kỳ 2 trong số các khóa đều có thể bị xâm phạm mà dữ liệu không bị xâm phạm. Nếu có một cuộc tấn công SQL Injection, họ có thể có được $userKey, nhưng không phải là khác 2. Nếu có một máy chủ địa phương khai thác, họ có thể nhận được $userKey$serverKey, nhưng không phải là thứ ba $userSuppliedKey. Nếu họ đi đánh người dùng bằng cờ lê, họ có thể lấy $userSuppliedKey, nhưng không phải 2 người kia (nhưng sau đó, nếu người dùng bị đánh bằng cờ lê, dù sao bạn cũng đã quá muộn).

  4. Thay vì lưu trữ khóa riêng, có nên yêu cầu người dùng nhập khóa riêng bất cứ khi nào họ cần mật khẩu được giải mã không? (Người dùng của ứng dụng này có thể được tin cậy)

    Chắc chắn rồi. Trên thực tế, đó là cách duy nhất tôi sẽ làm. Nếu không, bạn cần lưu trữ một phiên bản không được mã hóa ở định dạng lưu trữ lâu bền (bộ nhớ dùng chung như APC hoặc memcached hoặc trong tệp phiên). Đó là phơi bày bản thân với những thỏa hiệp bổ sung. Không bao giờ lưu trữ phiên bản mật khẩu không được mã hóa trong bất kỳ thứ gì ngoại trừ một biến cục bộ.

  5. Mật khẩu có thể bị đánh cắp và giải mã theo những cách nào? Tôi cần phải nhận thức được gì?

    Bất kỳ hình thức thỏa hiệp nào của hệ thống của bạn sẽ cho phép họ xem dữ liệu được mã hóa. Nếu họ có thể tiêm mã hoặc truy cập vào hệ thống tệp của bạn, họ có thể xem dữ liệu được giải mã (vì họ có thể chỉnh sửa các tệp giải mã dữ liệu). Bất kỳ hình thức tấn công Replay hoặc MITM nào cũng sẽ cung cấp cho họ quyền truy cập đầy đủ vào các khóa liên quan. Đánh hơi lưu lượng HTTP thô cũng sẽ cung cấp cho họ các khóa.

    Sử dụng SSL cho tất cả lưu lượng. Và đảm bảo không có gì trên máy chủ có bất kỳ loại lỗ hổng nào (CSRF, XSS, SQL Injection, Đặc quyền nâng cao, Thi hành mã từ xa, v.v.).

Chỉnh sửa: Đây là một triển khai lớp PHP của một phương thức mã hóa mạnh:

/**
 * A class to handle secure encryption and decryption of arbitrary data
 *
 * Note that this is not just straight encryption.  It also has a few other
 *  features in it to make the encrypted data far more secure.  Note that any
 *  other implementations used to decrypt data will have to do the same exact
 *  operations.  
 *
 * Security Benefits:
 *
 * - Uses Key stretching
 * - Hides the Initialization Vector
 * - Does HMAC verification of source data
 *
 */
class Encryption {

    /**
     * @var string $cipher The mcrypt cipher to use for this instance
     */
    protected $cipher = '';

    /**
     * @var int $mode The mcrypt cipher mode to use
     */
    protected $mode = '';

    /**
     * @var int $rounds The number of rounds to feed into PBKDF2 for key generation
     */
    protected $rounds = 100;

    /**
     * Constructor!
     *
     * @param string $cipher The MCRYPT_* cypher to use for this instance
     * @param int    $mode   The MCRYPT_MODE_* mode to use for this instance
     * @param int    $rounds The number of PBKDF2 rounds to do on the key
     */
    public function __construct($cipher, $mode, $rounds = 100) {
        $this->cipher = $cipher;
        $this->mode = $mode;
        $this->rounds = (int) $rounds;
    }

    /**
     * Decrypt the data with the provided key
     *
     * @param string $data The encrypted datat to decrypt
     * @param string $key  The key to use for decryption
     * 
     * @returns string|false The returned string if decryption is successful
     *                           false if it is not
     */
    public function decrypt($data, $key) {
        $salt = substr($data, 0, 128);
        $enc = substr($data, 128, -64);
        $mac = substr($data, -64);

        list ($cipherKey, $macKey, $iv) = $this->getKeys($salt, $key);

        if (!hash_equals(hash_hmac('sha512', $enc, $macKey, true), $mac)) {
             return false;
        }

        $dec = mcrypt_decrypt($this->cipher, $cipherKey, $enc, $this->mode, $iv);

        $data = $this->unpad($dec);

        return $data;
    }

    /**
     * Encrypt the supplied data using the supplied key
     * 
     * @param string $data The data to encrypt
     * @param string $key  The key to encrypt with
     *
     * @returns string The encrypted data
     */
    public function encrypt($data, $key) {
        $salt = mcrypt_create_iv(128, MCRYPT_DEV_URANDOM);
        list ($cipherKey, $macKey, $iv) = $this->getKeys($salt, $key);

        $data = $this->pad($data);

        $enc = mcrypt_encrypt($this->cipher, $cipherKey, $data, $this->mode, $iv);

        $mac = hash_hmac('sha512', $enc, $macKey, true);
        return $salt . $enc . $mac;
    }

    /**
     * Generates a set of keys given a random salt and a master key
     *
     * @param string $salt A random string to change the keys each encryption
     * @param string $key  The supplied key to encrypt with
     *
     * @returns array An array of keys (a cipher key, a mac key, and a IV)
     */
    protected function getKeys($salt, $key) {
        $ivSize = mcrypt_get_iv_size($this->cipher, $this->mode);
        $keySize = mcrypt_get_key_size($this->cipher, $this->mode);
        $length = 2 * $keySize + $ivSize;

        $key = $this->pbkdf2('sha512', $key, $salt, $this->rounds, $length);

        $cipherKey = substr($key, 0, $keySize);
        $macKey = substr($key, $keySize, $keySize);
        $iv = substr($key, 2 * $keySize);
        return array($cipherKey, $macKey, $iv);
    }

    /**
     * Stretch the key using the PBKDF2 algorithm
     *
     * @see http://en.wikipedia.org/wiki/PBKDF2
     *
     * @param string $algo   The algorithm to use
     * @param string $key    The key to stretch
     * @param string $salt   A random salt
     * @param int    $rounds The number of rounds to derive
     * @param int    $length The length of the output key
     *
     * @returns string The derived key.
     */
    protected function pbkdf2($algo, $key, $salt, $rounds, $length) {
        $size   = strlen(hash($algo, '', true));
        $len    = ceil($length / $size);
        $result = '';
        for ($i = 1; $i <= $len; $i++) {
            $tmp = hash_hmac($algo, $salt . pack('N', $i), $key, true);
            $res = $tmp;
            for ($j = 1; $j < $rounds; $j++) {
                 $tmp  = hash_hmac($algo, $tmp, $key, true);
                 $res ^= $tmp;
            }
            $result .= $res;
        }
        return substr($result, 0, $length);
    }

    protected function pad($data) {
        $length = mcrypt_get_block_size($this->cipher, $this->mode);
        $padAmount = $length - strlen($data) % $length;
        if ($padAmount == 0) {
            $padAmount = $length;
        }
        return $data . str_repeat(chr($padAmount), $padAmount);
    }

    protected function unpad($data) {
        $length = mcrypt_get_block_size($this->cipher, $this->mode);
        $last = ord($data[strlen($data) - 1]);
        if ($last > $length) return false;
        if (substr($data, -1 * $last) !== str_repeat(chr($last), $last)) {
            return false;
        }
        return substr($data, 0, -1 * $last);
    }
}

Lưu ý rằng tôi đang sử dụng một hàm được thêm vào trong PHP 5.6 : hash_equals. Nếu bạn ở mức thấp hơn 5,6, bạn có thể sử dụng chức năng thay thế này để thực hiện chức năng so sánh an toàn theo thời gian bằng cách sử dụng xác minh hai lần HMAC :

function hash_equals($a, $b) {
    $key = mcrypt_create_iv(128, MCRYPT_DEV_URANDOM);
    return hash_hmac('sha512', $a, $key) === hash_hmac('sha512', $b, $key);
}

Sử dụng:

$e = new Encryption(MCRYPT_BLOWFISH, MCRYPT_MODE_CBC);
$encryptedData = $e->encrypt($data, $key);

Sau đó, để giải mã:

$e2 = new Encryption(MCRYPT_BLOWFISH, MCRYPT_MODE_CBC);
$data = $e2->decrypt($encryptedData, $key);

Lưu ý rằng tôi đã sử dụng $e2lần thứ hai để hiển thị cho bạn các trường hợp khác nhau vẫn sẽ giải mã dữ liệu đúng cách.

Bây giờ, làm thế nào nó hoạt động / tại sao sử dụng nó trên một giải pháp khác:

  1. Chìa khóa

    • Các phím không được sử dụng trực tiếp. Thay vào đó, khóa được kéo dài bởi một dẫn xuất PBKDF2 tiêu chuẩn.

    • Khóa được sử dụng để mã hóa là duy nhất cho mọi khối văn bản được mã hóa. Do đó, khóa được cung cấp trở thành "khóa chính". Do đó, lớp này cung cấp xoay vòng khóa cho các khóa mật mã và xác thực.

    • LƯU Ý QUAN TRỌNG , $roundstham số được cấu hình cho các khóa ngẫu nhiên thực sự có đủ cường độ (tối thiểu 128 bit Bảo mật mã hóa ở mức tối thiểu). Nếu bạn định sử dụng mật khẩu hoặc khóa không ngẫu nhiên (hoặc ít ngẫu nhiên hơn 128 bit ngẫu nhiên CS), bạn phải tăng tham số này. Tôi sẽ đề xuất tối thiểu 10000 cho mật khẩu (bạn càng có đủ khả năng thì càng tốt, nhưng nó sẽ thêm vào thời gian chạy) ...

  2. Toàn vẹn dữ liệu

    • Phiên bản cập nhật sử dụng ENCRYPT-THEN-MAC, đây là một phương pháp tốt hơn nhiều để đảm bảo tính xác thực của dữ liệu được mã hóa.
  3. Mã hóa:

    • Nó sử dụng mcrypt để thực sự mã hóa. Tôi sẽ đề nghị sử dụng một trong hai MCRYPT_BLOWFISHhoặc MCRYPT_RIJNDAEL_128cyphers và MCRYPT_MODE_CBCcho chế độ. Nó đủ mạnh và vẫn khá nhanh (một chu kỳ mã hóa và giải mã mất khoảng 1/2 giây trên máy của tôi).

Bây giờ, như điểm 3 từ danh sách đầu tiên, những gì sẽ cung cấp cho bạn là một chức năng như thế này:

function makeKey($userKey, $serverKey, $userSuppliedKey) {
    $key = hash_hmac('sha512', $userKey, $serverKey);
    $key = hash_hmac('sha512', $key, $userSuppliedKey);
    return $key;
}

Bạn có thể kéo dài nó trong makeKey()hàm, nhưng vì nó sẽ được kéo dài sau đó, nên thực sự không phải là một điểm rất lớn để làm điều đó.

Theo kích thước lưu trữ, nó phụ thuộc vào văn bản đơn giản. Blowfish sử dụng kích thước khối 8 byte, vì vậy bạn sẽ có:

  • 16 byte cho muối
  • 64 byte cho hmac
  • chiều dài dữ liệu
  • Đệm sao cho độ dài dữ liệu% 8 == 0

Vì vậy, đối với nguồn dữ liệu 16 ký tự, sẽ có 16 ký tự dữ liệu được mã hóa. Vì vậy, điều đó có nghĩa là kích thước dữ liệu được mã hóa thực tế là 16 byte do phần đệm. Sau đó thêm 16 byte cho muối và 64 byte cho hmac và tổng kích thước được lưu trữ là 96 byte. Vì vậy, có tối đa 80 ký tự trên đầu, và tệ nhất là trên 87 ký tự ...

Tôi hy vọng điều đó sẽ giúp ...

Lưu ý: 12/11/12: Tôi vừa cập nhật lớp này với phương thức mã hóa tốt hơn NHIỀU, sử dụng các khóa có nguồn gốc tốt hơn và sửa lỗi tạo MAC ...


3
Ai đó không hiểu ý nghĩa của nó là "phá vỡ". @IRC công việc tốt trên lớp, đó là mã khá đẹp.
jcolebrand

1
Sau đây trả về false. Bất cứ ý tưởng tại sao? $ x = Mã hóa mới (MCRYPT_BlOWFISH, MCRYPT_MODE_CBC); $ test = $ x-> mã hóa ("kiểm tra", "a"); echo var_dump ($ x-> decrypt ($ test, "a"));
Bước sóng

2
Oh và một lần nữa trong chức năng giải mã thay đổi hai -64s thành -128trợ giúp (để bạn có được $enc = substr($data, 128, -128)$mac = substr($data, -128);
vũ trụ

4
@ircmaxell Đã khá lâu kể từ khi mã được sửa đổi lần cuối nên tôi tự hỏi liệu nó có cập nhật không. Tôi cần sử dụng một cái gì đó tương tự cho một ứng dụng tài chính và thật tuyệt nếu bạn đã đồng ý với lớp này :-)
nt.bas 22/03/2015

2
Cảnh báo! Phần mở rộng mcrypt đã bị từ bỏ trong gần một thập kỷ nay và cũng khá phức tạp để sử dụng. Do đó, nó đã không được ủng hộ đối với OpenSSL, nơi nó sẽ bị xóa khỏi lõi và vào PECL trong PHP 7.2. th1.php.net/manual/en/migration71.deprecated.php
vee

15

Làm cách nào để mã hóa và giải mã mật khẩu trong PHP? Bằng cách thực hiện một trong nhiều thuật toán mã hóa. (hoặc sử dụng một trong nhiều thư viện)

Thuật toán an toàn nhất để mã hóa mật khẩu là gì? Có hàng tấn thuật toán khác nhau, không có thuật toán nào an toàn 100%. Nhưng nhiều trong số chúng đủ an toàn cho thương mại và thậm chí cả mục đích quân sự

Tôi lưu trữ khóa riêng ở đâu? Nếu bạn đã quyết định triển khai khóa công khai - thuật toán mã hóa (ví dụ RSA), bạn không lưu trữ khóa riêng. người dùng có khóa riêng. hệ thống của bạn có khóa công khai có thể được lưu trữ bất cứ nơi nào bạn muốn.

Thay vì lưu trữ khóa riêng, có nên yêu cầu người dùng nhập khóa riêng bất cứ khi nào họ cần mật khẩu được giải mã không? (Người dùng của ứng dụng này có thể được tin cậy) Vâng nếu người dùng của bạn có thể nhớ các số nguyên tố dài một cách lố bịch thì - vâng, tại sao không. Nhưng nhìn chung, bạn sẽ cần phải đưa ra hệ thống cho phép người dùng lưu trữ khóa của họ ở đâu đó.

Mật khẩu có thể bị đánh cắp và giải mã theo những cách nào? Tôi cần phải nhận thức được gì? Điều này phụ thuộc vào thuật toán được sử dụng. Tuy nhiên, luôn đảm bảo rằng bạn không gửi mật khẩu không được mã hóa đến hoặc từ người dùng. Mã hóa / giải mã nó ở phía máy khách hoặc sử dụng https (hoặc người dùng các phương tiện mã hóa khác để bảo mật kết nối giữa máy chủ và máy khách).

Tuy nhiên, nếu tất cả những gì bạn cần là lưu trữ mật khẩu theo cách được mã hóa, tôi sẽ đề nghị bạn sử dụng một Mật mã XOR đơn giản. Vấn đề chính với thuật toán này là nó có thể dễ dàng bị phá vỡ bởi phân tích tần số. Tuy nhiên, vì thông thường mật khẩu không được tạo từ các đoạn văn bản tiếng Anh dài, tôi không nghĩ bạn nên lo lắng về nó. Vấn đề thứ hai với XOR Coding là nếu bạn có một tin nhắn ở cả dạng được mã hóa và giải mã, bạn có thể dễ dàng tìm ra mật khẩu mà nó được mã hóa. Một lần nữa, không phải là một vấn đề lớn trong trường hợp của bạn vì nó chỉ ảnh hưởng đến người dùng đã bị xâm phạm bởi các phương tiện khác.


Ở câu trả lời 3, khi bạn nói người dùng có khóa riêng, tôi không hiểu điều đó có nghĩa là gì. Bạn không khuyên người dùng chuyển khóa riêng vào ứng dụng theo cách thủ công, vậy làm thế nào khác khóa riêng được chuyển đến ứng dụng?
Parafan

Vâng, đó là một chút vấn đề. Khóa riêng có thể được lưu trong tệp văn bản và sau đó sao chép vào ứng dụng. Khóa cũng có thể được lưu trữ trên máy chủ nhưng trong trường hợp này vẫn phải được mã hóa bằng một số thuật toán mã hóa khác như XOR. Sử dụng XOR ở đây trong trường hợp này là đủ an toàn vì chỉ có một cặp thông báo mật khẩu và tin nhắn khá ngẫu nhiên nên không thể sử dụng phân tích tần số lạnh.
Ivan

4
Tôi chắc chắn sẽ không khuyên bạn nên tự mình thực hiện một thuật toán mã hóa, có quá nhiều cạm bẫy tiềm tàng và các thư viện hiện có đã được kiểm tra và phân tích bởi nhiều người.
Tai dài

Vấn đề chính với XOR là nếu ai đó đánh cắp dữ liệu ứng dụng của bạn và chỉ biết một trong những mật khẩu của người dùng, họ có thể giải mã tất cả các mật khẩu khác cho người dùng đó.
Tai dài

1
@Ivan: có, nhưng đây là một trong những trường hợp khi tôi nghĩ DIY thực sự rất tệ trừ khi bạn THỰC SỰ hiểu về mật mã. Có những mật mã mạnh tồn tại, tại sao không sử dụng chúng?
ircmaxell

13
  1. Hàm PHP mà bạn đang theo đuổi là Mcrypt ( http://www.php.net/manual/en/intro.mcrypt.php ).

Ví dụ từ hướng dẫn được chỉnh sửa một chút cho ví dụ này):

<?php
$iv_size = mcrypt_get_iv_size(MCRYPT_BLOWFISH, MCRYPT_MODE_ECB);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
$key = "This is a very secret key";
$pass = "PasswordHere";
echo strlen($pass) . "\n";

$crypttext = mcrypt_encrypt(MCRYPT_BLOWFISH, $key, $pass, MCRYPT_MODE_ECB, $iv);
echo strlen($crypttext) . "\n";
?>

Bạn sẽ sử dụng mcrypt_decrypt để giải mã mật khẩu của mình.

  1. Thuật toán tốt nhất là khá chủ quan - hỏi 5 người, nhận 5 câu trả lời. Cá nhân nếu mặc định (blowfish) không đủ tốt cho bạn, bạn có thể có vấn đề lớn hơn!

  2. Cho rằng PHP cần mã hóa - không chắc bạn có thể ẩn nó ở bất cứ đâu - hoan nghênh các bình luận về điều này. Tất nhiên thực hành mã hóa PHP tốt nhất áp dụng!

  3. Cho rằng khóa mã hóa sẽ nằm trong mã của bạn, không chắc chắn bạn sẽ đạt được gì, cung cấp phần còn lại của ứng dụng của bạn là an toàn.

  4. Rõ ràng, nếu mật khẩu được mã hóa và khóa mã hóa bị đánh cắp, thì trò chơi kết thúc.

Tôi đã đặt một người lái vào câu trả lời của tôi - Tôi không phải là chuyên gia về tiền điện tử PHP, nhưng, tôi nghĩ những gì tôi đã trả lời là thông lệ tiêu chuẩn - tôi hoan nghênh những bình luận khác có thể có.


$pass = $text. Tôi nghĩ anh ấy đã thay đổi điều đó để phục vụ cho câu hỏi và không để ý đến lần xuất hiện thứ hai.
Parafan

3
Hai điều cần lưu ý. Đầu tiên, MCRYPT_MODE_ECBkhông sử dụng IV. Thứ hai, nếu có, bạn cần lưu trữ IV vì bạn không thể giải mã dữ liệu mà không có nó ...
ircmaxell

"Thuật toán tốt nhất là khá chủ quan - hỏi 5 người, nhận 5 câu trả lời. Cá nhân nếu mặc định (blowfish) không đủ tốt cho bạn, bạn có thể gặp vấn đề lớn hơn!" Điều này là hoàn toàn sai. Bất kỳ chuyên gia về tiền điện tử nào cũng sẽ ít nhiều đồng ý với gist.github.com/tqbf/be58d2d39490c3b366ad , đặc biệt loại trừ cá kiếm
Scott Arciszewski

6

Rất nhiều người dùng đã đề xuất sử dụng mcrypt ... điều này là chính xác, nhưng tôi muốn tiến thêm một bước để làm cho nó dễ dàng được lưu trữ và chuyển (vì đôi khi các giá trị được mã hóa có thể khiến họ khó gửi bằng các công nghệ khác như curl hoặc json) .

Sau khi bạn đã mã hóa thành công bằng mcrypt, hãy chạy nó qua base64_encode và sau đó chuyển đổi nó thành mã hex. Khi đã ở trong mã hex, thật dễ dàng để chuyển theo nhiều cách khác nhau.

$td = mcrypt_module_open('tripledes', '', 'ecb', '');
$iv = mcrypt_create_iv (mcrypt_enc_get_iv_size($td), MCRYPT_RAND);
$key = substr("SUPERSECRETKEY",0,mcrypt_enc_get_key_size($td));
mcrypt_generic_init($td, $key, $iv);
$encrypted = mcrypt_generic($td, $unencrypted);
$encrypted = $ua."||||".$iv;
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
$encrypted = base64_encode($encrypted);
$encrypted = array_shift(unpack('H*', $encrypted));

Và ở phía bên kia:

$encrypted = pack('H*', $encrypted);
$encrypted = base64_decode($encrypted);
list($encrypted,$iv) = explode("||||",$encrypted,2);
$td = mcrypt_module_open('tripledes', '', 'ecb', '');
$key = substr("SUPERSECRETKEY",0,mcrypt_enc_get_key_size($td));
mcrypt_generic_init($td, $key, $iv);
$unencrypted = mdecrypt_generic($td, $encrypted);
mcrypt_generic_deinit($td);
mcrypt_module_close($td);


2
Chà - đó là vào năm 2011: P
Bradley

5

Tôi chỉ đề xuất mã hóa khóa công khai nếu bạn muốn khả năng đặt mật khẩu của người dùng mà không cần tương tác của họ (điều này có thể hữu ích cho việc đặt lại và chia sẻ mật khẩu).

Khóa công khai

  1. Phần mở rộng OpenSSL , cụ thể openssl_public_encryptopenssl_private_decrypt
  2. Đây sẽ là RSA thẳng, giả sử mật khẩu của bạn sẽ phù hợp với kích thước khóa - phần đệm, nếu không bạn cần một lớp đối xứng
  3. Lưu trữ cả hai khóa cho mỗi người dùng, cụm mật khẩu của khóa riêng là mật khẩu ứng dụng của họ

Đối xứng

  1. Phần mở rộng Mcrypt
  2. AES-256 có thể là một đặt cược an toàn, nhưng đây có thể là một câu hỏi SO
  3. Bạn không - đây sẽ là mật khẩu ứng dụng của họ

Cả hai

4. Có - người dùng sẽ phải nhập mật khẩu ứng dụng của họ mỗi lần, nhưng lưu trữ nó trong phiên sẽ gây ra các vấn đề khác

5.

  • Nếu ai đó đánh cắp dữ liệu ứng dụng, nó sẽ an toàn như mật mã đối xứng (đối với sơ đồ khóa chung, nó được sử dụng để bảo vệ khóa riêng bằng cụm mật khẩu.)
  • Ứng dụng của bạn chắc chắn chỉ có thể truy cập qua SSL, tốt nhất là sử dụng chứng chỉ ứng dụng khách.
  • Xem xét thêm yếu tố thứ hai để xác thực chỉ được sử dụng một lần mỗi phiên, như mã thông báo được gửi qua SMS.

Tránh mcrypt, hãy cẩn thận với openssl_private_decrypt().
Scott Arciszewski

2

Tôi đã thử một cái gì đó như thế này nhưng xin lưu ý rằng tôi không phải là nhà mật mã học và tôi cũng không có kiến ​​thức chuyên sâu về phphoặc bất kỳ ngôn ngữ lập trình nào. Đó chỉ là một ý tưởng. Ý tưởng của tôi là lưu trữ keytrong một số tệp hoặc database(hoặc nhập thủ công) mà (vị trí) không thể dự đoán dễ dàng (Và tất nhiên mọi thứ sẽ được giải mã vào một ngày nào đó, khái niệm là kéo dài thời gian giải mã) và mã hóa thông tin nhạy cảm.

$iv_size = mcrypt_get_iv_size(MCRYPT_BLOWFISH , MCRYPT_MODE_ECB);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
$key = "evenifyouaccessmydatabaseyouwillneverfindmyemail";
$text = "myemail@domain.com";
echo "Key : ".$key."<br/>";
echo "Text : ".$text . "<br/>";
echo "Md5 : ".md5($text). "<br/>";
echo "Sha1 : ".sha1($text). "<br/>";



$crypttext = mcrypt_encrypt(MCRYPT_BLOWFISH , $key, $text, MCRYPT_MODE_ECB, $iv);
echo "Crypted Data : ".$crypttext."<br>";

$base64 = base64_encode($crypttext);
echo "Encoded Data : ".$base64."<br/>";
$decode =  base64_decode($base64);


$decryptdata = mcrypt_decrypt(MCRYPT_BLOWFISH , $key, $crypttext, MCRYPT_MODE_ECB, $iv);

echo "Decoded Data : ".ereg_replace("?", null ,  $decryptdata); 
//event if i add '?' to the sting to the text it works, I don't know why.

Xin lưu ý rằng nó chỉ là một khái niệm. Bất kỳ cải thiện về mã này sẽ được đánh giá cao.


2

Mật khẩu dành cho một thiết bị phần cứng, vì vậy việc kiểm tra chống băm là điều không cần thiết

Hở? Tôi không hiểu Bạn chỉ có nghĩa là mật khẩu phải được phục hồi?

Như những người khác đã nói, tiện ích mở rộng mcrypt cung cấp quyền truy cập vào rất nhiều chức năng mã hóa - tuy nhiên bạn đang mời người dùng của mình đặt tất cả trứng vào một giỏ - một thứ sẽ có khả năng là mục tiêu cho những kẻ tấn công - và nếu bạn thậm chí không biết Làm thế nào để bắt đầu giải quyết vấn đề thì bạn đang làm cho người dùng của mình không hài lòng. Bạn không ở trong một vị trí để hiểu làm thế nào để bảo vệ dữ liệu.

Hầu hết các lỗ hổng bảo mật xuất hiện không phải vì thuật toán cơ bản bị thiếu sót hoặc không an toàn - mà là do các vấn đề với cách sử dụng thuật toán trong mã ứng dụng.

Phải nói rằng, có thể xây dựng một hệ thống an toàn hợp lý.

Bạn chỉ nên xem xét mã hóa bất đối xứng nếu bạn có yêu cầu người dùng tạo một tin nhắn an toàn mà người dùng (cụ thể) có thể đọc được. Lý do là nó đắt tiền tính toán. Nếu bạn chỉ muốn cung cấp một kho lưu trữ để người dùng nhập và truy xuất dữ liệu của riêng họ, mã hóa đối xứng là đủ.

Tuy nhiên, nếu bạn lưu trữ khóa để giải mã tin nhắn ở cùng một nơi với tin nhắn được mã hóa (hoặc nơi lưu trữ tin nhắn được mã hóa) thì hệ thống không an toàn. Sử dụng cùng một mã thông báo để xác thực người dùng như đối với khóa giải mã (hoặc trong trường hợp mã hóa giả định, sử dụng mã thông báo làm cụm từ khóa riêng tư). Vì bạn sẽ cần lưu trữ mã thông báo trên máy chủ nơi giải mã ít nhất là tạm thời, bạn có thể muốn xem xét sử dụng chất nền lưu trữ phiên không thể tìm kiếm hoặc chuyển mã thông báo trực tiếp đến trình nền được liên kết với phiên sẽ lưu trữ mã thông báo trong bộ nhớ và thực hiện giải mã tin nhắn theo yêu cầu.


1

Sử dụng password_hashpassword_verify

<?php
/**
 * In this case, we want to increase the default cost for BCRYPT to 12.
 * Note that we also switched to BCRYPT, which will always be 60 characters.
 */
$options = [
    'cost' => 12,
];
echo password_hash("rasmuslerdorf", PASSWORD_BCRYPT, $options)."\n";
?>

Và để giải mã:

<?php
// See the password_hash() example to see where this came from.
$hash = '$2y$07$BCryptRequires22Chrcte/VlQH0piJtjXl.0t1XkA8pw9dMXTpOq';

if (password_verify('rasmuslerdorf', $hash)) {
    echo 'Password is valid!';
} else {
    echo 'Invalid password.';
}
?>
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.