ホームページ  >  記事  >  データベース  >  AES_ENCRYPT() と AES_DECRYPT() を正しく使用して MySQL を暗号化および復号化する方法

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

小云云
小云云オリジナル
2018-05-18 17:40:3717286ブラウズ

この記事では、MySQL の AES_ENCRYPT() と AES_DECRYPT() を使用した正しい暗号化と復号化の方法を主に紹介します。MySQL の AES_ENCRYPT('password','key') 関数は、AES_DECRYPT (テーブルのフィールド名) を暗号化できます。 ) ,'key') 関数の復号化処理については、この記事に詳細なサンプル コードが記載されています。必要な友人はそれを参照できます。すべての人に役立つことを願っています。

前書き

私は最近仕事で要件に遭遇しました。AES_ENCRYPT() 関数を使用して平文を暗号化し、MySQL に保存する必要がありますが、いくつかの問題が発生しました。 . …以下で詳しく紹介していきます。 AES_ENCRYPT()函数将明文加密,存储在MySQL中,但是遇到了一些问题……下面就来详细介绍下。

说将加密后的密文,解密取出来是NULL。

看了一下,她发过来的表结构:

再看了她通过AES_DECRYPT()函数加密了一个字符串,然后insert进去了,执行成功后,显示了一个warning:<br>Query OK, 1 row affected, 1 warning (0.00 sec)

(没有报错而是warning,大概是sql_mode的缘故)

此时她忽略了这个warning,再通过AES_DECRYPT()解密后,发现取出来的明文为NULL。

再回看表结构,发现其字段属性为“varchar” && 字符集是ut8,检查warning为下:

mysql> show warnings;
+---------+------+------------------------------------------------------------------------+
| Level | Code | Message        |
+---------+------+------------------------------------------------------------------------+
| Warning | 1366 | Incorrect string value: &#39;\xE3f767\x12...&#39; for column &#39;passwd&#39; at row 1 |
+---------+------+------------------------------------------------------------------------+
1 row in set (0.00 sec)

查了一下文档,看一下这两个函数的使用:

-- 将&#39;hello world&#39;加密,密钥为&#39;key&#39;,加密后的串存在@pass中
mysql> SET @pass=AES_ENCRYPT(&#39;hello world&#39;, &#39;key&#39;); 
Query OK, 0 rows affected (0.00 sec)

-- 看一下加密后串的长度(都为2的整数次方)
mysql> SELECT CHAR_LENGTH(@pass);
+--------------------+
| CHAR_LENGTH(@pass) |
+--------------------+
| 16   |
+--------------------+
1 row in set (0.00 sec)

-- 使用AES_DECRYPT()解密
mysql> SELECT AES_DECRYPT(@pass, &#39;key&#39;);
+---------------------------+
| AES_DECRYPT(@pass, &#39;key&#39;) |
+---------------------------+
| hello world  |
+---------------------------+
1 row in set (0.00 sec)

那么到底该如何存呢?

方法①:

将字段属性设置为varbinary/binary/四个blob类型,等二进制字段属性。

创建三个字段,属性分别为varbinary、binary、blob。

并将'明文1','text2','明文_text3'加密,密钥为key,存入表中。

最后取出。

mysql> CREATE TABLE t_passwd (pass1 varbinary(16), pass2 binary(16), pass3 blob);
Query OK, 0 rows affected (0.00 sec)

mysql> INSERT INTO t_passwd VALUES (AES_ENCRYPT(&#39;明文1&#39;, &#39;key&#39;), AES_ENCRYPT(&#39;text2&#39;, &#39;key&#39;), AES_ENCRYPT(&#39;明文_text3&#39;, &#39;key&#39;)); 
Query OK, 1 row affected (0.01 sec)

mysql> SELECT AES_DECRYPT(pass1, &#39;key&#39;), AES_DECRYPT(pass2, &#39;key&#39;), AES_DECRYPT(pass3, &#39;key&#39;) FROM t_passwd;
+---------------------------+---------------------------+---------------------------+
| AES_DECRYPT(pass1, &#39;key&#39;) | AES_DECRYPT(pass2, &#39;key&#39;) | AES_DECRYPT(pass3, &#39;key&#39;) |
+---------------------------+---------------------------+---------------------------+
| 明文1   | text2   | 明文_text3   |
+---------------------------+---------------------------+---------------------------+
1 row in set (0.00 sec)

当然,属性括号内的长度要取决于明文的长度,此处明文较短,故只给了16。

方法②:

将密文十六进制化,再存入varchar/char列。

此处需要用到HEX()来存入,用UNHEX()

暗号化された暗号文を復号するとNULLになるという意味です。


彼女が送信したテーブル構造を見てください:


もう一度見てみると、AES_DECRYPT() 関数を使用して文字列を暗号化し、挿入しました。実行が成功すると、 警告が表示されました。

クエリ OK、1 行が影響あり、1 つの警告 (0.00 秒)



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

この時点で、彼女は警告を無視して AES_DECRYPT( ) を渡しました。 復号後、取り出した平文はNULLであることが分かりました。 テーブル構造を振り返ると、そのフィールド属性が "varchar" && であり、文字セットが ut8 であることがわかりました。次のように警告を確認してください。これら 2 つの関数:

mysql> CREATE TABLE t_passwd_2(pass1 char(32));
Query OK, 0 rows affected (0.01 sec)

mysql> INSERT INTO t_passwd_2 VALUES (HEX(AES_ENCRYPT(&#39;hello world&#39;, &#39;key2&#39;)));
Query OK, 1 row affected (0.00 sec)

mysql> SELECT AES_DECRYPT(UNHEX(pass1), &#39;key2&#39;) FROM t_passwd_2; 
+-----------------------------------+
| AES_DECRYPT(UNHEX(pass1), &#39;key2&#39;) |
+-----------------------------------+
| hello world   |
+-----------------------------------+
1 row in set (0.00 sec)

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

方法①:


フィールド属性をvarbinary/binary/four blob type、およびその他のバイナリフィールド属性に設定します。

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

「plaintext1」、「text2」、「plaintext_text3」を鍵keyで暗号化してテーブルに格納します。

最後に取り出してください。

mysql> CREATE TABLE t_passwd_3(pass varchar(32)) CHARSET latin1;
Query OK, 0 rows affected (0.00 sec)

mysql> INSERT INTO t_passwd_3 SELECT AES_ENCRYPT(&#39;text&#39;, &#39;key3&#39;);
Query OK, 1 row affected (0.00 sec)
Records: 1 Duplicates: 0 Warnings: 0

mysql> SELECT AES_DECRYPT(pass, &#39;key3&#39;) FROM t_passwd_3;
+---------------------------+
| AES_DECRYPT(pass, &#39;key3&#39;) |
+---------------------------+
| text   |
+---------------------------+
1 row in set (0.00 sec)

もちろん、属性括弧内の長さは平文の長さに依存します。ここでは平文の方が短いため、16 だけが与えられます。

方法②:

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

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

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

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

🎜🎜最後に、UNHEXで暗号化文字列を取り出し、AESキー「key2」で復号化します: 🎜rrreee🎜同様に、平文の長さに応じて、AES_ENCRYPT暗号化文字列の長さも変わるため、HEX後続の文字列の長さも変わります。 🎜実際の使用においては、業務に応じて妥当な値を評価する必要があります。 🎜🎜🎜🎜🎜方法③: 🎜🎜🎜🎜🎜16進数変換せずにvarcharに直接保存します。 🎜🎜問題の最初に戻ると、暗号化された文字列を utf8 文字セットに保存することはできず、属性は varchar です。 🎜🎜実際には、文字セットを latin1 に変更するだけです: 🎜🎜🎜挿入時に警告は報告されません。 🎜rrreee🎜このメソッドは美しいですが、必要なのはフィールドの文字セットを latin1 に設定するだけですが、隠れた危険をもたらす可能性があります: 🎜🎜🎜ドキュメントには次の文が書かれています: 🎜🎜🎜多くの暗号化および圧縮関数は、結果には任意のバイト値が含まれる可能性があります。これらの結果を格納する場合は、VARBINARY または BLOB バイナリ文字列データ型の列を使用します。これにより、データ値が変更される可能性がある、末尾のスペースの削除や文字セット変換による潜在的な問題が回避されます。非バイナリ文字列データ型 (CHAR、VARCHAR、TEXT) を使用する場合、一般的な考え方は、③の方法を使用する場合、暗号化された文字列を char/varchar/text 型に直接格納してから文字を作成するということです。変換時または空白文字の削除時に潜在的な影響が生じます。 🎜🎜そのため、char/varchar/textに格納する必要がある場合は、方法②を参照して16進数化してください。 🎜🎜🎜または、方法①と同様に、バイナリフィールドに直接格納します。 🎜🎜関連する推奨事項: 🎜🎜🎜🎜PHP で Mcrypt 暗号化と復号化の代わりに OpenSSL を使用するにはどうすればよいですか? 🎜🎜🎜🎜WeChatミニプログラムの暗号化と復号化のNODE-UUID機能の紹介🎜🎜🎜🎜PHPデータの圧縮、暗号化と復号化(パック、アンパック)の詳細な説明🎜🎜

以上がAES_ENCRYPT() と AES_DECRYPT() を正しく使用して MySQL を暗号化および復号化する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。