AES_ENCRYPT() と AES_DECRYPT() を使用して MySQL を暗号化および復号化する正しい方法の例

AES_ENCRYPT() と AES_DECRYPT() を使用して MySQL を暗号化および復号化する正しい方法の例

序文

最近、仕事でAES_ENCRYPT()関数を使用してプレーンテキストを暗号化し、MySQL に保存する必要があるという要件に遭遇しましたが、いくつか問題が発生しました... 以下に詳細を紹介します。

暗号化された暗号文を復号すると、結果が NULL になると言われています。

彼女が送ってきたテーブル構造を見てみました。

次に、彼女が AES_DECRYPT() 関数を使用して文字列を暗号化し、それを挿入しているのを確認しました。実行が成功すると、 warning:
Query OK, 1 row affected, 1 warning (0.00 sec)

(エラーはありませんが、警告は出ます。おそらく sql_mode が原因です)

このとき、彼女は警告を無視し、 AES_DECRYPT()で復号化したところ、得られた平文が NULL であることがわかりました。

テーブル構造をもう一度見てみると、フィールド属性は「varchar」であり、文字セットは ut8 であり、警告は次のようになります。

mysql> 警告を表示します。
+---------+------+------------------------------------------------------------------------------------+
| レベル | コード | メッセージ |
+---------+------+------------------------------------------------------------------------------------+
| 警告 | 1366 | 行 1 の列 'passwd' の文字列値が正しくありません: '\xE3f767\x12...' |
+---------+------+------------------------------------------------------------------------------------+
セット内の 1 行 (0.00 秒)

ドキュメントをチェックして、これら 2 つの関数がどのように使用されるかを確認してください。

-- キー 'key' を使用して 'hello world' を暗号化し、暗号化された文字列を @passmysql> SET @pass=AES_ENCRYPT('hello world', 'key'); に保存します。 
クエリは正常、影響を受けた行は 0 行 (0.00 秒)

-- 暗号化された文字列の長さを確認します(すべて 2 の累乗です)
mysql> CHAR_LENGTH(@pass)を選択します。
+--------------------+
| CHAR_LENGTH(@pass) |
+--------------------+
| 16 |
+--------------------+
セット内の 1 行 (0.00 秒)

-- AES_DECRYPT() を使用して復号化します。mysql> SELECT AES_DECRYPT(@pass, 'key');
+---------------------------+
| AES_DECRYPT(@pass, 'キー') |
+---------------------------+
| こんにちは世界 |
+---------------------------+
セット内の 1 行 (0.00 秒)

それでどうやって保存するのでしょうか?

方法1:

フィールド プロパティを varbinary/binary/four blob 型に設定し、その他のバイナリ フィールド プロパティを設定します。

varbinary、binary、blob の属性を持つ 3 つのフィールドを作成します。

そして、キー key を使用して 'plaintext1'、 'text2'、 'plaintext_text3' を暗号化し、テーブルに保存します。

最後に取り出します。

mysql> テーブル t_passwd を作成します (pass1 varbinary(16), pass2 binary(16), pass3 blob);
クエリは正常、影響を受けた行は 0 行 (0.00 秒)

mysql> t_passwd に値 (AES_ENCRYPT('plaintext1', 'key'), AES_ENCRYPT('text2', 'key'), AES_ENCRYPT('plaintext_text3', 'key')) を挿入します。 
クエリは正常、1 行が影響を受けました (0.01 秒)

mysql> t_passwd から AES_DECRYPT(pass1, 'キー')、AES_DECRYPT(pass2, 'キー')、AES_DECRYPT(pass3, 'キー') を選択します。
+---------------------------+----------------------------+---------------------------+
| AES_DECRYPT(pass1, 'キー') | AES_DECRYPT(pass2, 'キー') | AES_DECRYPT(pass3, 'キー') |
+---------------------------+----------------------------+---------------------------+
| プレーンテキスト1 | テキスト2 | プレーンテキスト3 |
+---------------------------+---------------------------+---------------------------+
セット内の 1 行 (0.00 秒)

もちろん、属性括弧の長さはプレーンテキストの長さによって異なります。ここではプレーンテキストの方が短いため、16 のみが与えられています。

方法2:

暗号文を 16 進数に変換し、varchar/char 列に保存します。

ここでは、入金には HEX() を使用し、出金にはUNHEX()使用する必要があります。

文字列属性を持つフィールドを作成します。

まず、AES を使用してキー「key2」で「hello world」を暗号化し、次に HEX 関数を使用して暗号化された文字列を 16 進数に変換します。

最後に、暗号化された文字列は UNHEX を通じて取り出され、キー「key2」に従って AES を通じて復号化されます。

mysql> テーブル t_passwd_2(pass1 char(32)) を作成します。
クエリは正常、影響を受けた行は 0 行 (0.01 秒)

mysql> t_passwd_2 に値 (HEX(AES_ENCRYPT('hello world', 'key2')) を挿入します);
クエリは正常、1 行が影響を受けました (0.00 秒)

mysql> t_passwd_2 から AES_DECRYPT(UNHEX(pass1), 'key2') を選択します。 
+-----------------------------------+
| AES_DECRYPT(UNHEX(pass1), 'key2') |
+-----------------------------------+
| こんにちは世界 |
+-----------------------------------+
セット内の 1 行 (0.00 秒)

同様に、平文の長さに応じて、AES_ENCRYPT で暗号化された文字列の長さも変化するため、HEX 以降の文字列の長さも変化します。
実際の使用においては、ビジネスに基づいて妥当な価値を評価するだけで十分です。

方法3:

16 進数化せずに varchar に直接保存します。

問題の始まりに戻ると、暗号化された文字列を utf8 文字セットで保存することはできず、属性は varchar です。

実際には、文字セットを latin1 に変更するだけです。

挿入中に警告は報告されません。

mysql> CREATE TABLE t_passwd_3(pass varchar(32)) CHARSET latin1;
クエリは正常、影響を受けた行は 0 行 (0.00 秒)

mysql> t_passwd_3 に INSERT INTO し、AES_ENCRYPT('text', 'key3') を選択します。
クエリは正常、1 行が影響を受けました (0.00 秒)
記録: 1 重複: 0 警告: 0

mysql> t_passwd_3 から AES_DECRYPT(pass, 'key3') を選択します。
+---------------------------+
| AES_DECRYPT(pass, 'key3') |
+---------------------------+
| テキスト |
+---------------------------+
セット内の 1 行 (0.00 秒)

この方法は美しいですが、フィールドの文字セットを latin1 に設定すると、隠れた危険が生じる可能性があります。

文書にはこう記されている。

多くの暗号化および圧縮関数は、結果に任意のバイト値が含まれる可能性がある文字列を返します。これらの結果を保存する場合は、VARBINARY または BLOB バイナリ文字列データ型の列を使用します。これにより、非バイナリ文字列データ型 (CHAR、VARCHAR、TEXT) を使用する場合に発生する可能性がある、末尾のスペースの削除やデータ値を変更する文字セット変換に関する潜在的な問題を回避できます。

一般的な考え方としては、方法 3 を使用して暗号化された文字列を char/varchar/text 型に直接保存すると、文字変換を実行するときやスペースを削除するときに潜在的な影響が出る可能性があります。

したがって、char/varchar/text で保存する必要がある場合は、方法 ② を参照して 16 進数に変換します。

または、方法①のようにバイナリフィールドに直接格納します。

要約する

上記はこの記事の全内容です。この記事の内容が皆さんの勉強や仕事に少しでもお役に立てれば幸いです。ご質問があれば、メッセージを残してコミュニケーションしてください。123WORDPRESS.COM をご愛顧いただき、ありがとうございます。

参考資料:

第 12 章 関数と演算子 - 12.13 暗号化と圧縮関数

以下もご興味があるかもしれません:
  • MySQLサーバーは--read-onlyオプションで実行されているため、このステートメントを実行できません
  • mysql データベースmysql: [エラー] 不明なオプション ''--skip-grant-tables''
  • MySQL ビューの一貫性を確保する方法の詳細な説明 (チェック オプション付き)
  • MySQL に絵文字を保存するときに表示されるエラー メッセージ「java.sql.SQLException: 文字列値が正しくありません:'\xF0\x9F\x92\xA9\x0D\x0A...'」の解決方法
  • MySQL の NULL と空の文字列
  • ODBC経由でMySQLとPHPを任意のデータベースに接続する例
  • Ubuntu で apt-get を使用して mysql をインストールおよび完全にアンインストールする方法の詳細な説明
  • mysqlサーバーは--skip-grant-tablesオプションで実行されています
  • pt-heartbeat を使用して MySQL レプリケーションの遅延を監視する方法の詳細な説明
  • MySQL pt-slave-restart ツールの使い方の紹介

<<:  複数のネットワークカードを備えた Linux システムでのルーティング構成の詳細な説明

>>:  JavaScriptのプロトタイプオブジェクトを徹底的に理解しましょう

推薦する

React はモバイル端末を構築するために antd-mobile+postcss を導入しました

antd-mobileをインストールするグローバル輸入 npm をインストール antd-mobil...

Centos 用の rpm パッケージのカスタマイズと yum リポジトリの構築に関するチュートリアル

1 yumでソフトウェアをインストールしたときにダウンロードしたrpmパッケージを保存しますyum ...

MySQLのインストールと設定方法のグラフィックチュートリアル(CentOS7)

1. システム環境[root@localhost ホーム]# cat /etc/redhat-re...

CentOS 7.6 Telnetサービス構築プロセス(Opensshアップグレードバトル第一弾のバックアップトランスポートライン構築)

不明な点があるときはいつでも、Blog Park にアクセスして、いつでも答えやインスピレーションを...

Docker の NFS-Ganesha イメージを使用して NFS サーバーを構築する詳細なプロセス

目次1. NFS-Ganeshaの紹介2. NFS-Ganeshaの設定3. NFS-Ganesha...

CSS の子要素を親要素と高い一貫性を持たせる方法

絶対位置決め方式: (1)親要素を相対配置に設定します。親要素の高さを指定しない場合は、左の子要素の...

WindowsにOpenSSLをインストールし、OpenSSLを使用して公開鍵と秘密鍵を生成します。

1. OpenSSL公式サイト公式ダウンロードアドレス: https://www.openssl....

Vueがsweetalert2プロンプトコンポーネントを統合する際の問題についてお話ししましょう

目次1. プロジェクト統合1. CDNインポート方法: 2. 箱の梱包を確認する3. 迅速な箱詰め4...

Vue命令の動作原理と実装方法

Vue の紹介現在のビッグフロントエンドの時代は、混乱と衝突の時代です。世界は多くの派閥に分かれてお...

最も単純な ErrorBoundary コンポーネントをカプセル化して、React 例外を処理する

序文React 16から、子コンポーネントで発生したエラーを捕捉し、エラーログを記録し、ダウングレー...

Linuxのtimeコマンドの使い方の詳しい説明

1. コマンドの紹介時間は、コマンドの実行に費やされた時間や関連するシステム リソース、その他の情報...

Linux のロード vmlinux デバッグ

gdb を使用してカーネル シンボルをロードする arm-eabi-gdb 出力/ターゲット/製品/...

JSパッケージオブジェクトに関する簡単な説明

目次概要意味インスタンスメソッドプリミティブ型とインスタンスオブジェクト間の自動変換カスタムメソッド...

Node.js の非同期イテレータの詳細な説明

目次序文非同期イテレータとは何ですか?非同期イテレータストリームとしてページング機能を備えたAPIの...

Vueのトグルボタンをクリックしてボタンを有効にし、無効にします。

実装方法は3つのステップに分かれています。テンプレートに 2 つのボタンを設定し、v-if と v-...