Copyright © 2014 http://netkiller.github.io
版權聲明
轉載請與作者聯繫,轉載時請務必標明文章原始出處和作者信息及本聲明。
|
|
|
微信掃瞄二維碼進入 Netkiller 微信訂閲號 QQ群:128659835 請註明“讀者” |
2014-08-19
This is a security solutions for records of database that anti delete, change and traces.
2014-08-28 last
Once the data was inserted, the data does not allow to be deleted anyone
And do not allow for data modification operations.
sometimes, Our data is only inserted, does not delete it. and some of fields does not allow changed.
For example deposit datas, a fields money in table account.
Another reason is that we prevent misuse.
I think it can be divided into two kinds of role, one is DBA, another one is the developer. the following is part of the database.
CREATE DEFINER=`dba`@`192.168.%` TRIGGER `account_before_delete` BEFORE DELETE ON `account` FOR EACH ROW BEGIN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Permission denied', MYSQL_ERRNO = 1001; END
if you want to delete any recodes,the database will be throw an exception "Permission denied"
To deny update all of fields.
DELIMITER $$ CREATE DEFINER=`dba`@`192.168.%` TRIGGER `logging_before_update` BEFORE UPDATE ON `logging` FOR EACH ROW BEGIN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Permission denied', MYSQL_ERRNO = 1001; END
deny some of fields, but you can exclude others.
CREATE DEFINER=`dba`@`192.168.%` TRIGGER `members_before_update` BEFORE UPDATE ON `members` FOR EACH ROW BEGIN SET NEW.`id` = OLD.id; SET NEW.`name` = OLD.name; SET NEW.`chinese_name` = OLD.chinese_name; SET NEW.`english_name` = OLD.english_name; SET NEW.`sex` = OLD.sex; SET NEW.`address` = OLD.address; SET NEW.`zipcode` = OLD.zipcode; SET NEW.`country_code` = OLD.country_code; SET NEW.`mobile` = OLD.mobile; SET NEW.`email` = OLD.email; SET NEW.`qq` = OLD.qq; SET NEW.`question` = OLD.question; SET NEW.`answer` = OLD.answer; SET NEW.`ctime` = OLD.ctime; END
Some fields is changed, the others do not, because NEW.xxx = OLD.xxx.
Usually, We were use a database for development. The database contains all of features such as frontend and backend. I propose to divide the frontend and backend,Then create user and assign permissions to schema/database.
We created three databases cms, frontend and backend, and then correspond to create three user cms, frontend and backend. next assign permissions to schema/database and only able to access their databases.
CREATE DATABASE `cms` /*!40100 COLLATE 'utf8_general_ci' */; CREATE DATABASE `frontend` /*!40100 COLLATE 'utf8_general_ci' */; CREATE DATABASE `backend` /*!40100 COLLATE 'utf8_general_ci' */;
backend user is highest permissions
mysql> SHOW GRANTS FOR 'backend'@'localhost'; +--------------------------------------------------------------------------------------+ | Grants for backend@localhost | +--------------------------------------------------------------------------------------+ | GRANT USAGE ON *.* TO 'backend'@'localhost' | | GRANT SELECT, INSERT, UPDATE, DELETE ON `cms`.* TO 'backend'@'localhost' | | GRANT SELECT, INSERT, UPDATE, DELETE ON `frontend`.* TO 'backend'@'localhost' | | GRANT SELECT, INSERT, UPDATE, DELETE, CREATE ON `backend`.* TO 'backend'@'localhost' | +--------------------------------------------------------------------------------------+ 4 rows in set (0.04 sec)
frontend user is cover login, logout, edit profile, view news and so on.
mysql> SHOW GRANTS FOR 'frontend'@'localhost'; +------------------------------------------------------------------------+ | Grants for frontend@localhost | +------------------------------------------------------------------------+ | GRANT USAGE ON *.* TO 'frontend'@'localhost' | | GRANT SELECT, INSERT, UPDATE ON `frontend`.* TO 'frontend'@'localhost' | | GRANT SELECT ON `cms`.`news` TO 'frontend'@'localhost' | +------------------------------------------------------------------------+ 3 rows in set (0.00 sec)
cms is user of Content Management System, it cover create news, edit content, login to cms as admin. the admin user in the table `backend`.`Employees` but only read it, do not change anything.
mysql> SHOW GRANTS FOR 'cms'@'localhost'; +----------------------------------------------------------------------+ | Grants for cms@localhost | +----------------------------------------------------------------------+ | GRANT USAGE ON *.* TO 'cms'@'localhost' | | GRANT SELECT, INSERT, UPDATE, DELETE ON `cms`.* TO 'cms'@'localhost' | | GRANT SELECT ON `backend`.`Employees` TO 'cms'@'localhost' | +----------------------------------------------------------------------+ 3 rows in set (0.00 sec)
Usually, cms and backend users we will allow source IP address and deny others
we need to archive all of data before change, we can called up it for audit and so on anytime.
table
CREATE TABLE `article` ( `article_id` MEDIUMINT(8) UNSIGNED NOT NULL AUTO_INCREMENT, `cat_id` SMALLINT(5) NOT NULL DEFAULT '0', `title` VARCHAR(150) NOT NULL DEFAULT '', `content` LONGTEXT NOT NULL, `author` VARCHAR(30) NOT NULL DEFAULT '', `keywords` VARCHAR(255) NOT NULL DEFAULT '', PRIMARY KEY (`article_id`), INDEX `cat_id` (`cat_id`) ) ENGINE=MyISAM ROW_FORMAT=DEFAULT AUTO_INCREMENT=1
version control table, Used to record every change.
CREATE TABLE `article_history` ( `id` MEDIUMINT(8) UNSIGNED NOT NULL AUTO_INCREMENT, `article_id` MEDIUMINT(8) UNSIGNED NOT NULL, `cat_id` SMALLINT(5) NOT NULL DEFAULT '0', `title` VARCHAR(150) NOT NULL DEFAULT '', `content` LONGTEXT NOT NULL, `author` VARCHAR(30) NOT NULL DEFAULT '', `keywords` VARCHAR(255) NOT NULL DEFAULT '', PRIMARY KEY (`id`), INDEX `article_id` (`article_id`) ) ENGINE=MyISAM ROW_FORMAT=DEFAULT AUTO_INCREMENT=1
version control trigger
DROP TRIGGER article_history; DELIMITER // CREATE TRIGGER article_history BEFORE update ON article FOR EACH ROW BEGIN INSERT INTO article_history SELECT * FROM article WHERE article_id = OLD.article_id; END; // DELIMITER;
Any change will copy the data to the history table, we can always compare two versions of the data changes, I also do this to develop a similar diff tool that can compare progressive changes in the reality of data through different colors.
CREATE TABLE `config_fee` ( `id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, `level` INT(11) NULL DEFAULT NULL COMMENT '層級', `type` ENUM('Deposit','Withdrawing') NOT NULL DEFAULT 'Withdrawing' COMMENT '類型,存款,取款', `min_fee` FLOAT(10,2) NOT NULL COMMENT '最低手續費', `max_fee` FLOAT(10,2) NOT NULL COMMENT '最高手續費', `ratio` FLOAT(10,2) NOT NULL COMMENT '手續費比例', `operator` VARCHAR(10) NOT NULL COMMENT '操作者', `status` ENUM('Current','Trash') NOT NULL DEFAULT 'Current', `ctime` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, `mtime` TIMESTAMP NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`id`) ) COMMENT='手續費管理' COLLATE='utf8_general_ci' ENGINE=InnoDB;
show me the screenshot
mysql> select type,operator,status,ctime,mtime from config_mtf_fee; +---------+----------+---------+---------------------+---------------------+ | type | operator | status | ctime | mtime | +---------+----------+---------+---------------------+---------------------+ | Deposit | jam | Trash | 2014-07-20 11:10:17 | 2014-07-20 11:10:57 | | Deposit | lucy | Trash | 2014-08-24 11:10:17 | 2014-08-24 11:10:57 | | Deposit | lily | Trash | 2014-08-25 11:10:17 | 2014-08-25 11:10:57 | | Deposit | kitty | Trash | 2014-08-27 11:10:17 | 2014-08-27 11:10:57 | | Deposit | neo | Current | 2014-08-28 11:10:54 | 2014-08-28 11:10:59 | +---------+----------+---------+---------------------+---------------------+ 2 rows in set (0.00 sec)
Above screenshot, you need last record and status is 'Current', 'Trash' is history datas.
When you update data, first to update status from 'Current' to 'Trash', and then insert data into table and status is 'Current'. we need last record and status is 'Current'.
Update trigger will be update all of the datas except status and mtime.
CREATE DEFINER=`root`@`%` TRIGGER `config_fee_before_update` BEFORE UPDATE ON `config_fee` FOR EACH ROW BEGIN SET NEW.`id` = OLD.id; SET NEW.`level` = OLD.level; SET NEW.`type` = OLD.type; SET NEW.`min_amount` = OLD.min_amount; SET NEW.`min_fee` = OLD.min_fee; SET NEW.`max_fee` = OLD.max_fee; SET NEW.`ratio` = OLD.ratio; SET NEW.`operator` = OLD.operator; SET NEW.`ctime` = OLD.ctime; END;
The trigger can be refuse to remove
CREATE DEFINER=`dba`@`192.168.%` TRIGGER `config_fee_before_delete` BEFORE DELETE ON `config_fee` FOR EACH ROW BEGIN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Permission denied', MYSQL_ERRNO = 1001; END