跳转到主内容
趣航编程网 - 趣学编程,启航技术之路!

如何防止SQL误删整个表_通过触发器进行操作权限二次确认

MySQL触发器无法拦截DROP TABLE,因其仅支持DML操作;防御需权限隔离(REVOKE DROP)与审计兜底(通用日志+告警)。 MySQL 里用 BEFORE DELETE 触发器拦不住 DROP TABLE 触发器根本监听不到
DROP TABLE
,它只响应
INSERT
、
UPDATE
、
DELETE
这类 DML 操作。而删表是 DDL,MySQL 的触发器机制不支持拦截。很多同学配完
BEFORE DELETE
就以为万事大吉,结果一执行
DROP TABLE users;
,触发器连影子都没见着。 真正能起作用的路径只有两条:权限隔离 + 审计兜底。 用 REVOKE 剥夺普通账号的 DROP 权限 这是最直接有效的防线。只要账号没被显式授予
DROP
权限,哪怕有
DELETE
权限,也执行不了删表命令。
REVOKE DROP ON mydb.* FROM 'app_user'@'%';
确认生效:查
SHOW GRANTS FOR 'app_user'@'%';
,输出里不能出现
DROP
开发/运维账号另建专用高权账号(比如
dba_admin
),严格管控登录终端和会话时长 注意:
GRANT ALL PRIVILEGES
会隐式包含
DROP
,千万别给业务账号开这个 DELETE 全表时靠 WHERE 1=0 拦截误操作 即便不能防删表,至少得防
DELETE FROM users;
这种漏写
WHERE
的事故。触发器可以在这里卡一下。 示例触发器逻辑:
CREATE TRIGGER prevent_full_delete BEFORE DELETE ON users FOR EACH ROW BEGIN IF (SELECT COUNT(*) FROM information_schema.PROCESSLIST WHERE ID = CONNECTION_ID() AND INFO LIKE 'DELETE FROM users%') > 0 THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Full table delete blocked: missing WHERE clause'; END IF; END;
但要注意几个硬伤: 依赖
information_schema.PROCESSLIST
,在 MySQL 8.0+ 默认关闭 performance_schema 时可能查不到
INFO
字段 无法区分
DELETE FROM users WHERE id = 123;
和
DELETE FROM users;
—— 都是全表扫描,触发器没法看 SQL 文本细节 更靠谱的做法是:强制所有 DELETE 必须带非空
WHERE
条件,并在应用层做语法校验(比如 ORM 层禁止无条件 delete) 真正的兜底:开启通用查询日志 + 自动告警 权限和触发器都只是前置限制,出事后的快速定位和止损,靠的是可追溯的日志。 开启
general_log = ON
,日志输出到表(
general_log_table = ON
),避免文件写满磁盘 用定时任务或监控脚本扫描
mysql.general_log
表,匹配关键词:
DROP TABLE
、
DELETE FROM [a-z_]+;$
(结尾无 WHERE)、
TRUNCATE TABLE
匹配到即发企业微信/钉钉告警,并自动 kill 对应
CONNECTION_ID()
注意:通用日志有性能开销,生产环境建议仅在核心库开启,且日志保留不超过 24 小时 权限控制是底线,日志审计是后视镜。没人能保证永远不手滑,但得让手滑之后三秒内有人知道、五秒内能拦住。

相关文章