Skip to content

MySQL - 锁定用户账户

MySQL 提供了一项关键的安全功能,可以通过锁定用户账户来暂时或永久禁用它。这是管理数据库安全和访问控制的重要管理工具。

锁定用户账户的常见原因包括:

  • 安全事件响应: 如果账户被怀疑遭到泄露,立即锁定可以防止进一步的未经授权访问。
  • 临时停用: 当员工离职或服务账户暂时不需要时,锁定是注销用户的可逆替代方案。
  • 合规性: 在重新启用账户之前强制进行手动审查。
  • 自动化安全: 在多次登录尝试失败后自动锁定账户。

您可以在创建用户账户时或通过修改现有账户来锁定它。MySQL 为此目的使用 ACCOUNT LOCK 子句。

要创建一个默认锁定状态的新用户,请在 CREATE USER 语句后附加 ACCOUNT LOCK。

CREATE USER 'temp_user'@'localhost'
IDENTIFIED BY 'a-secure-password'
ACCOUNT LOCK;

要锁定现有用户,请使用 ALTER USER 语句。

ALTER USER 'app_user'@'%' ACCOUNT LOCK;

此命令执行后,'app_user'@'%' 尝试连接服务器的任何尝试都将失败,并显示“账户已锁定”错误。

-- 锁定用户尝试连接
-- mysql -u app_user -p
-- 输入密码: *****
ERROR 3118 (HY000): Access denied for user 'app_user'@'%'. Account is locked.

要重新启用锁定的账户,请在 ALTER USER 语句中使用 ACCOUNT UNLOCK 子句。这与锁定操作直接对应。

ALTER USER 'app_user'@'%' ACCOUNT UNLOCK;

解锁后,用户可以使用其有效凭据再次连接。

所有用户的锁定状态都存储在 mysql.user 系统表的 account_locked 列中。您可以查询此表以查看一个或所有用户的状态。值为 ‘Y’ 表示锁定,‘N’ 表示未锁定。

SELECT User, Host, account_locked
FROM mysql.user
WHERE User = 'app_user';
用户主机账户是否锁定
app_user%Y

使用客户端程序自动化账户锁定

Section titled “使用客户端程序自动化账户锁定”

在实际应用程序中,您可能希望通过编程方式锁定用户账户,例如,作为管理面板或自动化安全脚本的一部分。

尽管 ALTER USER 本身不太容易受到传统注入攻击,但最佳实践是,每当使用用户提供的数据来标识要锁定的账户时,都应使用参数化查询或正确转义的输入,以防止任何潜在的安全问题。

此脚本锁定作为参数提供的特定用户。

import mysql.connector
def lock_user(db_config, username, hostname='localhost'):
# ALTER USER 这样的 DDL 语句不能使用标准占位符。
# 我们必须构建查询字符串,但首先要验证输入。
# 基本验证,以防止对标识符进行简单的注入。
if not username.isalnum() or not (hostname.isalnum() or hostname in ['%', 'localhost']):
print("Error: Invalid username or hostname format.")
return
# 注意:为此脚本使用具有高权限且凭据强大的账户。
try:
with mysql.connector.connect(**db_config) as cnx:
with cnx.cursor() as cursor:
# 验证后安全地构建查询。
query = f"ALTER USER '{username}'@'{hostname}' ACCOUNT LOCK"
cursor.execute(query)
cnx.commit()
print(f"Successfully locked user '{username}'@'{hostname}'.")
except mysql.connector.Error as err:
print(f"Failed to lock user: {err}")
# 示例用法
db_admin_config = {'user': 'admin_user', 'password': 'admin_password', 'host': '127.0.0.1'}
lock_user(db_admin_config, 'compromised_user')

此异步函数锁定指定的用户。

const mysql = require('mysql2/promise');
async function lockUser(dbConfig, username, hostname = 'localhost') {
// 与 Python 类似,在将标识符包含在查询字符串中之前进行验证。
if (!/^[a-zA-Z0-9_]+$/.test(username) || !/^[a-zA-Z0-9._%]+$/.test(hostname)) {
console.error('Error: Invalid username or hostname format.');
return;
}
let connection;
try {
connection = await mysql.createConnection(dbConfig);
const query = `ALTER USER ?@? ACCOUNT LOCK`;
// mysql2/promise 通常可以使用 `?` 处理标识符替换
await connection.execute(query, [username, hostname]);
console.log(`Successfully locked user '${username}'@'${hostname}'.`);
} catch (err) {
console.error(`Failed to lock user: ${err.message}`);
} finally {
if (connection) await connection.end();
}
}
// 示例用法
const dbAdminConfig = { host: 'localhost', user: 'admin_user', password: 'admin_password' };
lockUser(dbAdminConfig, 'compromised_user');