Eliminate possibility of belated data manipulations on MySQL table - mysql

I want to guarantee that the rows in my MySQL table cannot be manipulated after their creation.
I know that only granting insert and select privileges is one step in this direction, but I also want to make sure the root user cannot alter data after insertion.
Incremental hashing:
To this end, I think about an additional column 'hash', that stores the hash value of the last row's hash concatted with the new column data.
If I then export the hashes eg. every day, any manipulation could be detected.
Am I right? Can you point me to some resources where this has been done already? Would one do this with a trigger? Maybe even in an auxiliary table that is only accessible by root?

Something like that :
DELIMITER $$
CREATE TRIGGER trigger_hash
AFTER INSERT
ON table_name FOR EACH ROW
BEGIN
UPDATE table_name
SET hash = MD5(concat(NEW.field1, NEW.field2, NEW.field3, ...))
WHERE id= NEW.id
END;
$$
DELIMITER ;

Related

Alter a where clause on a update through a trigger or similar

I'm currently building a replication database (for reporting from) for an already existing database and we are wanting to obfuscate/hash certain columns. Both are on AWS RDS platform with the replication set up as a 'read replica' of the source.
One of the issues with using RDS Replication I've found is you cannot specify which columns to ignore (given that RDS read replicas are supposed to be 1:1 this isn't surprising and I fully understand I'm doing something very niche)
The solution to this problem was to set up triggers on updates/inserts to alter these values, like so:
DELIMITER $$
CREATE TRIGGER clients_insert_obfuscate
BEFORE INSERT ON clients
FOR EACH ROW
BEGIN
SET NEW.access_token = NULL, NEW.user_token_ttl = 0;
END$$
DELIMITER ;
However one of the values we want to alter is a primary key (the PKs on this table are used as coupon code redemption numbers).
Which leads me to my question - is there anyway of altering the where clause in a update before its executed from within mysql? So on the replica databse, instead of matching against the unhashed code its matching against the hashed code?
So far I have this:
DELIMITER $$
CREATE TRIGGER insert_obfuscate
BEFORE INSERT ON codes
FOR EACH ROW
BEGIN
SET NEW.code = SHA2(NEW.code, 256);
END$$
DELIMITER ;
DELIMITER $$
CREATE TRIGGER update_obfuscate
BEFORE UPDATE ON codes
FOR EACH ROW
BEGIN
SET NEW.code = SHA2(NEW.code, 256);
END$$
DELIMITER ;
So the insert is fine - but the update trigger is only looking at the params to update - not the where clause.
I understand a trigger might not be the right route to take on this but I'm struggling to find anything else.
Is there anyway of doing this or do I need to look at changing the schema? I would prefer not to change the schema on a production DB though.
Thanks

ReSet all password status to zero using trigger

I am optimizing my login system in which I am maintain previous passwords of a user, schema of pwd table for maintaining passwords is as follows:
here userId refers to primary key of user table.
If status attribute is 1 that means row has marking current password if it is 0 previous password.
How can I write a trigger so that if a new entry for any user is made in pwd
table, all previous status of that user gets set to 0 and new value will remain 1 as the default value of status attribute. Currently I am doing so at application level.
It won't be possible because it would require to have a mutating (changing the same table it's being fired upon) trigger which is prohibited in MySQL.
You can create a stored procedure though, but you would still need to call it from the client code explicitly.
Now a better schema design would be to keep all current passwords in one table (presumably in the users table) and all previous in the other (i.e. pwd_history). Not only it makes queries for current passwords faster it also allows you to use a trigger if you choose to.
DELIMITER //
CREATE TRIGGER tg_pwd_history
AFTER UPDATE ON users
FOR EACH ROW
BEGIN
IF NOT NEW.pwd <=> OLD.pwd THEN
INSERT INTO pwd_history (`userId`, `pwd`, `ts`)
VALUES (NEW.id, OLD.pwd, NOW());
END IF;
END//
DELIMITER ;
Here is a SQLFiddle demo
Now I very much hope you're not storing them in plain text.

whenever i update my table i want to store my old data(old-row) in a new table

CREATE TRIGGER items_
ON test
after update
AS
begin
INSERT INTO test2(id,namecan)
SELECT id,namecan from test
end
I Have tried with trigger but i didnt get any results so please help me how to deal with it
methods involving two stored procedures are also welcome
You could do it with a stored procedure, but I would use a trigger.
With a stored procedure, I'd perceive you using a cursor on the otherDatabase table to read through the records and compare each with the values in Table1 to determine whether Table1's data needed to be written to Table2, and if so, to do it.
With a trigger, I would simply update the data in Table1 by whatever means, without concerning myself with what the overwriting data is, and in the trigger,
use the old and new values using the ##Inserted & ##Deleted (system) tables to determine if the old values (##Deleted) needed to be written to Table2.
If you don want to use triggers, you can go for this concept..
Let there is a form from which you are inserting the values on a table say register table. And the action of the form in going to servlet MyServlet. In Myservlet
you can first fetch the data from the Register table and store it into the Rsultset object let rs. And after that insert the rs into a new table.
Please let me know if m not clear to u..
Your trigger syntax is wrong
delimiter //
CREATE TRIGGER items_ after update
ON test
for each row
begin
INSERT INTO test2(id,namecan) values (old.id,old.namecan);
end; //
delimiter ;
So this trigger will make an entry to the test2 table every time you update row in the test table with the old row values from test table.
You should call old.id and old.namecan (i assume that table 'test' have 'id' and 'namecan' field)to get the older data. your trigger body should look like this
begin
INSERT INTO test2(id,namecan) value(old.id, old.namecan)
end
'old' will reference to record which you update.

How to sync values in a table column in mysql trigger

I need to sync values in a table column in mysql trigger while having the same value in another column. Here is an example of my table:
id___MP____sweek
1____2_____1
2____2_____1
3____1_____2
4____1_____2
5____3_____3
6____3_____3
If a user changes, for example, MP in the first row (id=1) from 2 to 4, then the value of MP with the same sweek has to be changed (e.g., id=2, MP becomes also 4).
I wrote a BEFORE UPDATE tigger that does not work:
USE moodle;
DELIMITER $$
CREATE TRIGGER trigger_course_minpostUPD BEFORE UPDATE ON moodle.mdl_course_sections FOR EACH ROW
BEGIN
IF NEW.MP <> OLD.MP THEN
BEGIN
SET #A=NEW.MP;
SET NEW.MP = #A
WHERE OLD.sweek=NEW.sweek;
END;
END IF;
END$$
DELIMITER ;
From within a MySQL trigger you are not able to affect other rows on the same table.
You would want to say something like:
UPDATE my_table SET MP=NEW.MP WHERE sweek = NEW.sweek
But - sorry - no go.
There are hack around this -- and ugly ones, too.
If your table is MyISAM, you can wrap it up with a MERGE table, and act on the MERGE table instead (MySQL doesn't realize at that point you're actually hacking around it).
However, using MyISAM as a storage engine may not be a good thing -- today's focus is on InnoDB, a much more sophisticated engine.
Another trick is to try and use the FEDERATED engine. See relevant post by Roland Bouman. Again, this is a dirty hack.
I would probably let the application do the thing within the same transaction.

To check values in other databases using trigger

Is it possible to check whether a particular value in a column exists in other databases using trigger? These two databases are located inside the same MYSQL instance. Specifically, what I want to do is this:
Before a row is added to a table ( Document_Index_table) inside Database A ( Document_DB).
A trigger is fired. This trigger carries the one of the column value (usr_id) inside the row and pass it to Database B ( User_Control_DB).
Based on the values, User_Control_DB will check whether the usr_id exists in column usr_id of the table (Usr_Information).
If exists, then return a true to Document_DB and the row in 1. is allowed to add to the Document_DB.
If not, then an error is issued. No row is added to Document_DB.
How can this be done, if it can be done at all?
Edit: Both databases are MySQL databases
So, I'm a complete novice at database development, but you could do something like this:
Create a 'Before' insert trigger on your document_index_table.
The trigger does something like this:
declare numRows integer;
select count(*) from user_control_db.usr_information where usr_id = NEW.usr_id into num_rows;
if (numRows > 0) then
call NonExistentProc();
end if;
I believe that this would accomplish what you wanted. It'll produce an error like "PROCEDURE documentdb.NonExistenProc does not exist" and skip the insert if there isn't at least one row that has the matching usr id in the user control db.
Again, I'm a novice at this DB stuff so there might be a more elegant way, but this worked for my single test case.
Hope that helps.