好的,我们开始今天的讲座,主题是 MySQL 安全与审计之:MySQL
的Password Expiration
(密码过期)及其在密码生命周期管理中的应用。
引言:密码安全的重要性
在当今的信息安全环境中,数据库安全至关重要。而数据库密码的安全性是整个安全体系中的关键一环。弱口令、长期不更改的密码,都可能成为攻击者入侵的突破口。因此,制定完善的密码策略,并强制执行,是保障数据库安全的重要手段。MySQL 提供的 Password Expiration 功能,正是密码生命周期管理的重要组成部分。
一、MySQL Password Expiration 功能概述
Password Expiration
,即密码过期功能,是指强制用户定期更改其数据库密码。这种机制可以显著降低因密码泄露或猜测而导致的风险。MySQL 从 5.7.4 版本开始引入了密码过期策略,并不断增强。
1.1 default_password_lifetime
系统变量
default_password_lifetime
是一个全局系统变量,用于设置密码的默认过期时间。它的值表示密码在多少天后过期。默认值为 0,表示密码永不过期。
要查看当前的 default_password_lifetime
值,可以使用以下 SQL 语句:
SHOW VARIABLES LIKE 'default_password_lifetime';
要修改全局的 default_password_lifetime
值,可以使用以下 SQL 语句:
SET GLOBAL default_password_lifetime = 90; -- 设置密码 90 天后过期
设置完成后,新创建的用户将继承这个过期策略。已经存在的用户,如果未单独设置过期策略,也会受到影响。
1.2 PASSWORD EXPIRE
子句
PASSWORD EXPIRE
子句用于控制单个用户的密码过期状态。它可以用于 CREATE USER
和 ALTER USER
语句中。
PASSWORD EXPIRE DEFAULT
: 用户密码的过期时间由全局变量default_password_lifetime
决定。PASSWORD EXPIRE INTERVAL N DAY
: 用户密码将在 N 天后过期。PASSWORD EXPIRE NEVER
: 用户密码永不过期。PASSWORD EXPIRE
: 用户密码立即过期,下次登录时必须更改密码。
例如,创建一个用户,密码 60 天后过期:
CREATE USER 'testuser'@'localhost' IDENTIFIED BY 'password' PASSWORD EXPIRE INTERVAL 60 DAY;
修改一个已存在用户的密码过期策略,使其密码立即过期:
ALTER USER 'testuser'@'localhost' PASSWORD EXPIRE;
修改一个已存在用户的密码过期策略,使其密码永不过期:
ALTER USER 'testuser'@'localhost' PASSWORD EXPIRE NEVER;
1.3 password_history
插件和变量
password_history
插件用于记录用户历史密码,防止用户在密码过期后,简单地将密码改回之前的密码。
password_history
: 设置记住多少个历史密码。password_reuse_interval
: 设置在多少天内不能重用历史密码。
首先,安装 password_history
插件:
INSTALL PLUGIN password_history SONAME 'password_history.so';
然后,设置 password_history
和 password_reuse_interval
的值:
SET GLOBAL password_history = 5; -- 记住 5 个历史密码
SET GLOBAL password_reuse_interval = 90; -- 90 天内不能重用历史密码
注意:password_history
插件在 MySQL 8.0 中已被移除,在 MySQL 8.0 中,密码历史记录功能被内置到服务器中,不需要单独安装插件。相关变量的名字也略有不同。
二、密码生命周期管理流程
一个完整的密码生命周期管理流程应该包括以下几个阶段:
- 密码策略制定: 明确密码复杂度要求、过期时间、历史密码重用限制等。
- 密码创建/修改: 创建用户时,设置合适的密码过期策略。修改用户密码时,也要遵循密码策略。
- 密码过期提醒: 在密码即将过期时,提醒用户及时更改密码。
- 密码过期处理: 密码过期后,强制用户更改密码才能继续使用。
- 密码历史记录: 记录用户的历史密码,防止用户重用旧密码。
- 审计和监控: 定期审计密码策略的执行情况,监控异常的密码修改行为。
2.1 密码策略制定
密码策略应该根据实际的安全需求制定。以下是一些常见的密码策略要求:
- 密码复杂度: 密码长度至少为 8 位,包含大小写字母、数字和特殊字符。
- 密码过期时间: 密码每 90 天或 180 天过期一次。
- 历史密码重用限制: 禁止重用最近 5 个密码。
- 密码修改频率: 限制用户在短时间内频繁修改密码。
可以使用 MySQL 的密码验证插件(如 validate_password
)来强制执行密码复杂度要求。
2.2 密码创建/修改
在创建用户时,应该根据密码策略设置合适的密码过期策略。例如:
CREATE USER 'newuser'@'localhost' IDENTIFIED BY 'StrongPassword123!' PASSWORD EXPIRE INTERVAL 90 DAY;
修改用户密码时,也应该遵循密码策略。可以使用 ALTER USER
语句修改密码和过期策略:
ALTER USER 'newuser'@'localhost' IDENTIFIED BY 'NewStrongPassword456!' PASSWORD EXPIRE INTERVAL 90 DAY;
2.3 密码过期提醒
MySQL 本身没有提供密码过期提醒功能。需要通过其他方式实现。常见的做法包括:
- 编写脚本: 编写一个脚本,定期查询数据库中密码即将过期的用户,并通过邮件或短信通知用户。
- 集成到应用程序中: 在应用程序中,判断用户密码是否即将过期,并在用户登录时提醒用户更改密码。
以下是一个简单的 Python 脚本,用于查询密码即将过期的用户:
import mysql.connector
import datetime
def get_expiring_passwords(days_before_expiry=7):
"""
获取密码在 days_before_expiry 天内即将过期的用户。
"""
mydb = mysql.connector.connect(
host="localhost",
user="root",
password="your_password",
database="mysql"
)
mycursor = mydb.cursor()
# 查询密码过期时间
mycursor.execute("SELECT User, Host, password_last_changed, password_lifetime FROM mysql.user")
expiring_users = []
for user, host, last_changed, lifetime in mycursor:
if lifetime is not None and lifetime > 0:
expiry_date = last_changed + datetime.timedelta(days=lifetime)
days_to_expiry = (expiry_date - datetime.date.today()).days
if days_to_expiry <= days_before_expiry and days_to_expiry >= 0:
expiring_users.append((user, host, days_to_expiry))
mydb.close()
return expiring_users
if __name__ == "__main__":
expiring_users = get_expiring_passwords()
if expiring_users:
print("以下用户的密码即将过期:")
for user, host, days_to_expiry in expiring_users:
print(f"User: {user}@{host}, Days to expiry: {days_to_expiry}")
else:
print("没有密码即将过期的用户。")
2.4 密码过期处理
当用户密码过期后,MySQL 会阻止用户登录,并返回一个错误信息。用户必须更改密码才能继续使用。
可以使用 ALTER USER
语句更改密码:
ALTER USER 'expireduser'@'localhost' IDENTIFIED BY 'NewPassword123!';
在应用程序中,需要捕获密码过期错误,并提示用户更改密码。
2.5 密码历史记录
如前所述,可以使用 password_history
插件(MySQL 8.0 及其以上版本内置)来记录用户的历史密码,防止用户重用旧密码。
2.6 审计和监控
定期审计密码策略的执行情况,监控异常的密码修改行为。可以使用 MySQL 的审计日志功能来记录所有密码修改操作。
三、代码示例:完整的密码生命周期管理
以下是一个完整的密码生命周期管理的代码示例,包括密码策略制定、密码创建/修改、密码过期提醒和密码过期处理。
3.1 密码策略制定
假设密码策略如下:
- 密码长度至少为 8 位,包含大小写字母、数字和特殊字符。
- 密码每 90 天过期一次。
- 禁止重用最近 5 个密码。
3.2 密码创建/修改
-- 安装密码验证插件
INSTALL PLUGIN validate_password SONAME 'validate_password.so';
-- 设置密码验证插件的参数
SET GLOBAL validate_password.policy = MEDIUM;
SET GLOBAL validate_password.length = 8;
-- 设置密码过期时间
SET GLOBAL default_password_lifetime = 90;
-- 安装密码历史记录插件 (MySQL 5.7)
-- INSTALL PLUGIN password_history SONAME 'password_history.so';
-- SET GLOBAL password_history = 5;
-- SET GLOBAL password_reuse_interval = 90;
-- 创建用户
CREATE USER 'user1'@'localhost' IDENTIFIED BY 'InitialPassword123!' PASSWORD EXPIRE INTERVAL 90 DAY;
-- 修改用户密码
ALTER USER 'user1'@'localhost' IDENTIFIED BY 'NewPassword456!' PASSWORD EXPIRE INTERVAL 90 DAY;
3.3 密码过期提醒 (Python 脚本)
import mysql.connector
import datetime
import smtplib
from email.mime.text import MIMEText
def get_expiring_passwords(days_before_expiry=7):
"""
获取密码在 days_before_expiry 天内即将过期的用户。
"""
mydb = mysql.connector.connect(
host="localhost",
user="root",
password="your_password",
database="mysql"
)
mycursor = mydb.cursor()
# 查询密码过期时间
mycursor.execute("SELECT User, Host, password_last_changed, password_lifetime FROM mysql.user")
expiring_users = []
for user, host, last_changed, lifetime in mycursor:
if lifetime is not None and lifetime > 0:
expiry_date = last_changed + datetime.timedelta(days=lifetime)
days_to_expiry = (expiry_date - datetime.date.today()).days
if days_to_expiry <= days_before_expiry and days_to_expiry >= 0:
expiring_users.append((user, host, days_to_expiry))
mydb.close()
return expiring_users
def send_email_alert(user, host, days_to_expiry, recipient_email="[email protected]"):
"""
发送密码过期提醒邮件。
"""
sender_email = "[email protected]"
sender_password = "your_email_password" # Be careful storing this!
subject = "密码即将过期提醒"
body = f"尊敬的用户 {user}@{host},nn您的 MySQL 密码将在 {days_to_expiry} 天后过期。请及时更改密码。nn谢谢!"
msg = MIMEText(body)
msg['Subject'] = subject
msg['From'] = sender_email
msg['To'] = recipient_email
try:
with smtplib.SMTP_SSL('smtp.example.com', 465) as server: # Replace with your SMTP server details
server.login(sender_email, sender_password)
server.sendmail(sender_email, recipient_email, msg.as_string())
print(f"成功发送邮件到 {recipient_email}")
except Exception as e:
print(f"发送邮件失败:{e}")
if __name__ == "__main__":
expiring_users = get_expiring_passwords()
if expiring_users:
print("以下用户的密码即将过期:")
for user, host, days_to_expiry in expiring_users:
print(f"User: {user}@{host}, Days to expiry: {days_to_expiry}")
send_email_alert(user, host, days_to_expiry)
else:
print("没有密码即将过期的用户。")
3.4 密码过期处理 (应用程序代码)
在应用程序中,需要捕获密码过期错误,并提示用户更改密码。 以下是一个简单的示例代码 (伪代码):
try:
# 连接数据库
connection = connect_to_database()
# 执行查询
result = execute_query(connection, "SELECT * FROM users WHERE username = 'user1'")
# 处理查询结果
process_result(result)
except mysql.connector.Error as err:
if err.errno == 1862: # CR_PASSWORD_EXPIRED
print("密码已过期,请更改密码。")
# 跳转到密码修改页面
redirect_to_password_change_page()
else:
print(f"数据库错误:{err}")
finally:
# 关闭连接
if connection:
connection.close()
四、实际应用中的注意事项
- 测试: 在生产环境中使用 Password Expiration 功能之前,务必在测试环境中进行充分的测试。
- 通知: 提前通知用户密码过期策略,并提供详细的密码修改指南。
- 兼容性: 确保应用程序能够正确处理密码过期错误。
- 监控: 定期监控密码策略的执行情况,及时发现和解决问题。
- 备份: 定期备份数据库,以防止数据丢失。
- 自动化: 尽量使用自动化工具来管理密码生命周期,减少人工干预。
- 用户教育: 对用户进行安全培训,提高用户的安全意识。
五、MySQL 8.0 的变化
MySQL 8.0 对密码管理进行了一些改进:
- 内置密码历史记录: 密码历史记录功能被内置到服务器中,不需要单独安装插件。
- 变量名称变更:
password_history
和password_reuse_interval
变量被password_previous_history
和password_reuse_time
取代。 - 更灵活的密码策略: 提供了更多的密码策略选项,例如可以设置密码的最大长度。
六、表格总结
功能 | 描述 | 系统变量/子句 |
---|---|---|
密码过期时间设置 | 设置密码的默认过期时间或单个用户的密码过期时间。 | default_password_lifetime , PASSWORD EXPIRE |
密码历史记录 | 记录用户的历史密码,防止用户重用旧密码。 | password_history (MySQL 5.7), password_previous_history (MySQL 8.0), password_reuse_time (MySQL 8.0) |
密码复杂度验证 | 强制执行密码复杂度要求。 | validate_password 插件 |
密码过期提醒 | 定期查询数据库中密码即将过期的用户,并通过邮件或短信通知用户。 | 需要编写脚本或集成到应用程序中 |
密码过期处理 | 密码过期后,强制用户更改密码才能继续使用。 | ALTER USER |
审计和监控 | 定期审计密码策略的执行情况,监控异常的密码修改行为。 | MySQL 审计日志 |
密码过期功能是数据库安全的重要一环,通过合理的配置和使用,可以有效降低安全风险。希望今天的讲座能帮助大家更好地理解和应用 MySQL 的 Password Expiration 功能,提升数据库的安全性。
密码过期功能是提高MySQL安全性的关键,合理配置和使用可显著降低安全风险。