1

更新 (解決策)

この投稿はかなりの注目を集めているように思われるので、解決策は宣言で適切なenctype(コンテンツ タイプ) パラメーターを提供することになったことをお知らせしたいと思います。デフォルトの enctype を使用して行われるエンコードを防止するに<FORM>は、値を に設定する必要があります。w3.orgのForms in HTML Documentsからの抜粋:multipart/form-dataapplication/x-www-form-urlencoded

コンテンツ タイプ「application/x-www-form-urlencoded」は、非 ASCII 文字を含む大量のバイナリ データまたはテキストを送信するのに非効率的です。ファイル、非 ASCII データ、およびバイナリ データを含むフォームを送信するには、コンテンツ タイプ「multipart/form-data」を使用する必要があります。

そして、ここに適切な FORM 宣言があります:

<FORM method="POST" action="/path/to/file/" name="encryptedForm" enctype="multipart/form-data">

最初の質問

私は、フォーム フィールド名を mcrypt を使用して暗号化された値に本質的に置き換えるフォーム スパム保護クラスに取り組んでいます。これに関する問題は、mcrypt 暗号化がフォーム フィールドを無効にする英数字だけに限定されないことです。 以下のコードを考えると、既に暗号化された配列の値を復号化する際に問題が発生する理由を思いつきますか?

/**
 * Two way encryption function to encrypt/decrypt keys with
 * the DES encryption algorithm.
 */
public static function encryption($text, $encrypt = true)
{
    $encrypted_data = '';
    $td = mcrypt_module_open('des', '', 'ecb', '');
    $iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($td), MCRYPT_RAND);
    if (mcrypt_generic_init($td, substr(self::$randomizer, 16, 8), $iv) != -1) {
        if ($encrypt) {
            // attempt to sanitize encryption for use as a form element name
            $encrypted_data = mcrypt_generic($td, $text);
            $encrypted_data = base64_encode($encrypted_data);
            $encrypted_data = 'i' . strtr($encrypted_data, '+/=', '-_.');
            self::$encrypted[] = $encrypted_data;
        } else {
            // reverse form element name sanitization and decrypt
            $text = substr($text, 1);
            $text = strtr($text, '-_.', '+/=');
            $text = base64_decode($text);
            $encrypted_data = mdecrypt_generic($td, $text);
        }
        mcrypt_generic_deinit($td);
        mcrypt_module_close($td);
    }
    return $encrypted_data;
}

後で、次を使用して非表示のフォーム要素の値を設定する呼び出しを行います。

base64_encode(serialize(self::$encrypted))

基本的に隠しフィールドには、暗号化された値で暗号化されたすべてのフォーム フィールドの配列が含まれます。これは、バックエンドでどのフィールドを復号化する必要があるかを知るためです。フォームの送信時に、このフィールドはバックエンドで次のコードを使用して解析されます。

    // load the mapping entry
    $encrypted_fields = $input->post('encrypted', '');
    if (empty($encrypted_fields)) {
        throw new AppException('The encrypted form field was empty.');
    }

    // decompress array of encrypted fields
    $encrypted_fields = @unserialize(base64_decode($encrypted_fields));
    if ($encrypted_fields === false) {
        throw new AppException('The encrypted form field was not valid.');
    }

    // get the mapping of encrypted keys to key
    $data = array();
    foreach ($_POST as $key => $val) {
        // if the key is encrypted, add to data array decrypted
        if (in_array($key, $encrypted_fields)) {
            $decrypted = self::encryption($key, false);
            $data[$decrypted] = $val;
            unset($_POST[$key]);
        } else {
            $data[$key] = $val;
        }
    }

    // merge $_POST array with decrypted key array
    $_POST += $data;

暗号化されたフォーム フィールド キーを復号化しようとすると失敗します。$_POST配列に新しい文字化けしたキーを作成するだけです。私の推測では、base64_encodingorserializationが から文字を削除してい$encrypted_dataます。 これが原因であるかどうか、およびフォーム キーをエンコードするための代替方法があるかどうかを誰かが確認できますか?

4

1 に答える 1

1

だから私はあなたのコードを取り、それを少し修正して、投稿リクエストの要素を削除できるようにしました。あなたの機能は正常に動作しているようです。私が投稿したコードを使用してスクリプトを作成すると、cli で実行され、フィールドが正しく暗号化/復号化されていることがわかります。これは、投稿リクエストが、暗号化/シリアル化/エンコードされたデータをいくらか混乱させていることを意味する必要があります。フレームワークを使用している場合、キー/値が変更されて一致しなくなる可能性があるため、ポスト配列の処理方法を詳しく調べます。あなたが投稿したコードは問題ないようです。

<?php
    /**
     * Two way encryption function to encrypt/decrypt keys with
     * the DES encryption algorithm.
     */
    function encryption($text, $encrypt = true, &$encryptedFields = array())
    {
        $encrypted_data = '';
        $td = mcrypt_module_open('des', '', 'ecb', '');
        $iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($td), MCRYPT_RAND);
        if (mcrypt_generic_init($td, substr('sdf234d45)()*5gf512/?>:LPIJ*&U%&^%NBVFYUT^5hfhgvkjtIUUYRYT', 16, 8), $iv) != -1) {
            if ($encrypt) {
                // attempt to sanitize encryption for use as a form element name
                $encrypted_data = mcrypt_generic($td, $text);
                $encrypted_data = base64_encode($encrypted_data);
                $encrypted_data = 'i' . strtr($encrypted_data, '+/=', '-_.');
                //self::$encrypted[] = $encrypted_data;
                $encryptedFields[] = $encrypted_data;
            } else {
                // reverse form element name sanitization and decrypt
                $text = substr($text, 1);
                $text = strtr($text, '-_.', '+/=');
                $text = base64_decode($text);
                $encrypted_data = mdecrypt_generic($td, $text);
            }
            mcrypt_generic_deinit($td);
            mcrypt_module_close($td);
        }
        return $encrypted_data;
    }

    $encryptedFields = array();

    // encrypt some form fields
    encryption('firstname', true, $encryptedFields);
    encryption('lastname', true, $encryptedFields);
    encryption('email_fields', true, $encryptedFields);

    echo "Encrypted field names:\n";
    print_r($encryptedFields);

    // create a usable string of the encrypted form fields
    $hiddenFieldStr = base64_encode(serialize($encryptedFields));

    echo "\n\nFull string for hidden field: \n";
    echo $hiddenFieldStr . "\n\n";


    $encPostFields = unserialize(base64_decode($hiddenFieldStr));

    echo "\n\nDecrypted field names:\n";
    foreach($encPostFields as $field)
    {
        echo encryption($field, false)."\n";
    }
    ?>
于 2010-01-08T04:50:15.090 に答える