好的,我们开始今天的讲座,主题是 MySQL 高级函数 CREATE USER ... IDENTIFIED BY ... ASYMMETRIC KEY
及其在身份认证中的应用。
引言:传统密码认证的局限性
在传统的数据库用户身份认证中,我们通常使用用户名和密码。密码以哈希形式存储在数据库中,用户登录时输入的密码经过相同的哈希算法处理后与数据库中存储的哈希值进行比较。这种方式虽然简单易懂,但也存在一些固有的安全风险:
- 密码泄露风险: 如果数据库被攻破,攻击者可以获得密码的哈希值,通过彩虹表、字典攻击等方式破解密码。
- 中间人攻击: 在客户端和服务器之间传输密码(即使是哈希后的密码),也可能被中间人截获。
- 密码重用: 用户可能在多个系统中使用相同的密码,导致一个系统被攻破,其他系统也受到威胁。
- 弱密码问题: 用户可能选择容易猜测的弱密码,增加被破解的风险。
为了解决这些问题,MySQL 引入了基于非对称密钥(公钥/私钥对)的身份认证方式。
CREATE USER ... IDENTIFIED BY ... ASYMMETRIC KEY
语法解析
CREATE USER ... IDENTIFIED BY ... ASYMMETRIC KEY
语句用于创建一个使用非对称密钥进行身份认证的 MySQL 用户。其基本语法如下:
CREATE USER 'username'@'host' IDENTIFIED BY PUBLIC_KEY 'public_key_string';
username@host
: 指定要创建的用户名和允许连接的主机。IDENTIFIED BY PUBLIC_KEY 'public_key_string'
: 指定用户的公钥。用户必须使用与此公钥对应的私钥进行身份认证。
非对称密钥身份认证原理
非对称密钥身份认证的核心思想是:
- 密钥生成: 用户生成一对公钥和私钥。私钥由用户安全保管,公钥提供给 MySQL 服务器。
- 用户创建: 使用
CREATE USER ... IDENTIFIED BY PUBLIC_KEY
语句将用户的公钥注册到 MySQL 服务器。 - 身份认证: 当用户尝试连接 MySQL 服务器时,服务器会生成一个随机字符串(challenge),并使用用户的公钥进行加密。
- 客户端解密: 客户端收到加密后的 challenge 后,使用用户的私钥进行解密。
- 密码验证: 客户端将解密后的 challenge 作为密码发送给 MySQL 服务器。服务器将收到的密码与原始的 challenge 进行比较。如果匹配,则身份验证成功。
这种方式的优势在于:
- 安全性更高: 用户的私钥永远不会离开客户端,即使数据库被攻破,攻击者也无法获得用户的私钥。
- 防止中间人攻击: 即使中间人截获了加密后的 challenge 和解密后的密码,也无法通过验证,因为他们没有用户的私钥。
实战演练:创建和使用非对称密钥认证用户
下面通过一个具体的例子来演示如何创建和使用非对称密钥认证用户。
步骤 1:生成公钥和私钥
首先,我们需要生成一对公钥和私钥。可以使用 OpenSSL 工具来完成:
openssl genrsa -out private_key.pem 2048
openssl rsa -in private_key.pem -pubout -out public_key.pem
这两个命令会生成两个文件:private_key.pem
(私钥) 和 public_key.pem
(公钥)。 请务必妥善保管 private_key.pem
文件。
步骤 2:提取公钥字符串
我们需要从 public_key.pem
文件中提取公钥字符串,并将其用于 CREATE USER
语句。可以使用以下命令提取:
openssl rsa -in public_key.pem -pubout -outform DER | openssl base64 -A
这个命令会将公钥转换为 DER 格式,然后进行 Base64 编码。 输出的结果就是我们需要使用的公钥字符串。
步骤 3:创建 MySQL 用户
使用 mysql
客户端连接到 MySQL 服务器,并执行以下 SQL 语句:
CREATE USER 'testuser'@'%' IDENTIFIED BY PUBLIC_KEY 'MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAw234567890abcdefghijklmnopqrstuvwxyzABCDEFG=='; -- 替换为实际的公钥字符串
请将 'MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAw234567890abcdefghijklmnopqrstuvwxyzABCDEFG=='
替换为实际的公钥字符串。 'testuser'@'%'
表示允许从任何主机连接的用户名为 testuser
的用户。
步骤 4:授予用户权限
GRANT ALL PRIVILEGES ON *.* TO 'testuser'@'%';
FLUSH PRIVILEGES;
这些语句授予 testuser
用户所有数据库的所有权限。 请根据实际需求调整权限。
步骤 5:客户端连接配置
在使用非对称密钥进行身份认证时,需要在客户端进行一些配置。具体的配置方法取决于客户端使用的编程语言和 MySQL 连接库。
例如,在使用 Python 的 mysql.connector
库时,可以这样配置:
import mysql.connector
import base64
import os
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import padding
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import serialization
def get_encrypted_password(private_key_file):
with open(private_key_file, "rb") as key_file:
private_key = serialization.load_pem_private_key(
key_file.read(),
password=None,
backend=default_backend()
)
# Connect to the server to get the challenge.
try:
mydb = mysql.connector.connect(
host="your_host",
user="testuser",
database="mysql",
auth_plugin='mysql_clear_password'
)
challenge = mydb.authentication_plugins['mysql_clear_password'].server_public_key
mydb.close()
except mysql.connector.Error as err:
print(f"Error getting challenge: {err}")
return None
if challenge is None:
print("Server did not provide a challenge.")
return None
# Decrypt the challenge using the private key.
try:
decrypted_password = private_key.decrypt(
challenge,
padding.PKCS1v15()
)
return decrypted_password.decode('latin1')
except Exception as e:
print(f"Decryption error: {e}")
return None
# Example usage
private_key_file = "private_key.pem" # Replace with your private key file
password = get_encrypted_password(private_key_file)
if password:
try:
mydb = mysql.connector.connect(
host="your_host",
user="testuser",
password=password,
database="your_database",
auth_plugin='mysql_clear_password'
)
print("Connection successful!")
mycursor = mydb.cursor()
mycursor.execute("SELECT VERSION()")
myresult = mycursor.fetchone()
print("Database version:", myresult)
mydb.close()
except mysql.connector.Error as err:
print(f"Error: {err}")
else:
print("Failed to retrieve or decrypt password.")
关键点:
auth_plugin='mysql_clear_password'
: 指定使用mysql_clear_password
认证插件。这是 MySQL 用于处理非对称密钥认证的插件。- 需要使用私钥解密challenge。
注意事项
- 安全保管私钥: 私钥的安全性至关重要。如果私钥泄露,攻击者可以使用私钥冒充用户进行身份认证。
- 证书管理: 如果需要频繁更换密钥,建议使用证书管理系统来管理公钥和私钥。
- 性能影响: 非对称密钥加密和解密需要消耗一定的计算资源,可能会对性能产生一定影响。
表格:传统密码认证 vs. 非对称密钥认证
特性 | 传统密码认证 | 非对称密钥认证 |
---|---|---|
密码存储 | 哈希值 | 公钥 |
密码传输 | 哈希值(或加密后的哈希值) | 加密后的 challenge,解密后的 challenge (作为密码) |
安全性 | 较低,易受密码泄露、中间人攻击、弱密码攻击等影响 | 较高,私钥不离开客户端,可以有效防止密码泄露和中间人攻击 |
复杂性 | 简单 | 相对复杂,需要生成和管理密钥,客户端需要进行特殊配置 |
性能 | 较高 | 较低,加密和解密需要消耗计算资源 |
适用场景 | 对安全性要求不高的场景 | 对安全性要求较高的场景,例如需要保护敏感数据的系统 |
ASYMMETRIC KEY
的其他应用场景
除了用户身份认证之外,ASYMMETRIC KEY
还可以用于其他场景,例如:
- 数据加密: 可以使用公钥对数据进行加密,只有拥有私钥的用户才能解密。
- 数字签名: 可以使用私钥对数据进行签名,接收方可以使用公钥验证签名的有效性,从而保证数据的完整性和真实性。
代码示例:使用公钥加密数据
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import padding
from cryptography.hazmat.backends import default_backend
import base64
def encrypt_data(public_key_file, data):
with open(public_key_file, "rb") as key_file:
public_key = serialization.load_pem_public_key(
key_file.read(),
backend=default_backend()
)
encrypted = public_key.encrypt(
data.encode('utf-8'),
padding.PKCS1v15()
)
return base64.b64encode(encrypted).decode('utf-8')
# Example usage
public_key_file = "public_key.pem" # Replace with your public key file
data_to_encrypt = "Sensitive data to be encrypted"
encrypted_data = encrypt_data(public_key_file, data_to_encrypt)
print("Encrypted data:", encrypted_data)
代码示例:使用私钥解密数据
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import padding
from cryptography.hazmat.backends import default_backend
import base64
def decrypt_data(private_key_file, encrypted_data):
with open(private_key_file, "rb") as key_file:
private_key = serialization.load_pem_private_key(
key_file.read(),
password=None,
backend=default_backend()
)
encrypted_data_bytes = base64.b64decode(encrypted_data)
decrypted = private_key.decrypt(
encrypted_data_bytes,
padding.PKCS1v15()
)
return decrypted.decode('utf-8')
# Example usage
private_key_file = "private_key.pem" # Replace with your private key file
encrypted_data = "YOUR_ENCRYPTED_DATA_HERE" # Replace with the encrypted data from the previous example
decrypted_data = decrypt_data(private_key_file, encrypted_data)
print("Decrypted data:", decrypted_data)
最佳实践建议
- 定期更换密钥: 为了提高安全性,建议定期更换用户的公钥和私钥。
- 使用强密钥: 使用足够长的密钥长度(例如 2048 位)来提高安全性。
- 实施访问控制: 限制用户对数据库的访问权限,只授予必要的权限。
- 监控数据库活动: 监控数据库的活动,及时发现异常行为。
总结:非对称密钥认证增强了数据库安全性
CREATE USER ... IDENTIFIED BY ... ASYMMETRIC KEY
提供了一种更安全的身份认证方式,可以有效防止密码泄露和中间人攻击,它在安全性要求较高的应用场景中具有重要意义。同时,理解并灵活运用非对称加密技术,可以为数据安全提供多重保障。