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のプロトタイプオブジェクトを徹底的に理解しましょう

ブログ    

推薦する

VueはAmapを使用して都市の位置特定を実現

この記事では、Amapを使用して都市の位置特定を実現するVueの具体的なコードを参考までに共有します...

クリックイメージ反転効果を実現するJavaScript

最近、顔コレクションに関するプロジェクトに取り組んでいましたが、フロントエンドモジュールを書いている...

LinuxのCentos7でmysql5.7.29を構築する詳細なプロセス

1. MySQLをダウンロードする1.1 ダウンロードアドレスhttps://downloads.m...

JavaScript ベースのシンプルなカルーセルの実装

この記事では、シンプルなカルーセルを実装するためのJavaScriptの具体的なコードを参考までに紹...

TS 数値区切り文字とより厳密なクラス属性チェックの詳細な説明

目次概要演算子の改良と正確なinstanceofよりスマートなオブジェクトリテラル推論固有のシンボル...

Linux での vi (vim) の新しい使い方のまとめ

私は数年間 vi エディタを使ってきましたが、実用的な用途で使ったことはありませんでした。今日 Py...

JavaScript ループトラバーサルの 24 種類のメソッドをすべてご存知ですか?

目次序文1. 配列走査法1. 各() 2. マップ() 3. 〜のために4. フィルター() 5. ...

Vue.js $refs 使用例の説明

プロパティやイベントがあるにもかかわらず、JavaScript で子コンポーネントに直接アクセスする...

MySQL を解凍してインストールおよび完全に削除する方法の詳細なグラフィック説明

1. MySQLをインストールする(1)ダウンロードしたMySQLの圧縮ファイルをMySQLをインス...

CSSを使用して円形の波効果を実現する

モバイル デバイスでは、金額を表示するために円形の波グラフィックがよく使用されます。最初は、この効果...

jQueryはクッキーを操作する

コードをコピーコードは次のとおりです。 jQuery.cookie = 関数(名前、値、オプション)...

jsを使用してシンプルなカルーセル効果を実現する

この記事では、シンプルなカルーセル効果を実現するためのjsの具体的なコードを参考までに紹介します。具...

Vueフロントエンドパッケージングの詳細なプロセス

目次1. パッケージ化コマンドを追加する2. パッケージ化されたコードを実行する3. パッケージ化し...

Ubuntu インストール時にブラックスクリーンが表示される場合の解決策 (3 種類)

私のコンピューターのグラフィック カードは Nvidia グラフィック カードです。再起動後、画面に...

http:// の代わりに // を使用する利点は何ですか (アダプティブ https)

//デフォルトプロトコル/ デフォルト プロトコルの使用は、リソース アクセス プロトコルが現在の...