SQL Server inject trigger ignored? - sql

One of my customer's website had been getting injection attack (inserting ads in emails) and at that time I didn't know how to handle the attack so I set trigger on update and delete to send me an email so I would know ads were added to table. However, I did not receive any email when values got changed.
ALTER TRIGGER [dbo].[TRIG_DEL]
ON [dbo].[A]
INSTEAD OF DELETE
AS
BEGIN
DECLARE #str VARCHAR(100)
SET #str = CONCAT('Someone is trying to delete A table at ', CURRENT_TIMESTAMP)
EXEC [msdb].[dbo].sp_send_dbmail
#profile_name = 'A_Email',
#recipients = 'abc#def.com;',
#subject = 'UPDATE ALERT',
#body = #str
END
This is my trigger and it works fine when I test it. Is there any way to avoid trigger? I just want to know how the attacker avoided the trigger, out of curiosity.

Related

How to create a trigger to send email when a new record is added in to the table

When I run an interface with name 'personimport' it will generate a new record in the table (run history).
There are 5 columns in the table:
interface-id, interface name, date, personid, error msg
Inserting "1, qwerty, 2019-09-11, a1" is successful, but inserting "2, person import, 2019-09-12, a2" throws an error .
Whenever a new record is added into this table with the name 'person import' I want to send an email to set of employees.
How to write a trigger for this in SQL Server?
You need to have database mail configured:
https://learn.microsoft.com/en-us/sql/relational-databases/database-mail/configure-database-mail?view=sql-server-2017
You need to create a trigger:
From SSMS goto the table and expand
Right click triggers, and "New Trigger"
Name your trigger, on table name, and after insert
CREATE TRIGGER SendTheEmails
ON runhistory
AFTER insert
AS
BEGIN
-- Insert statements for trigger here
END
GO
https://learn.microsoft.com/en-us/sql/t-sql/statements/create-trigger-transact-sql?view=sql-server-2017
Then for the SQL to email:
Declare #message varchar(max)
Declare #subjectline varchar(60)
set #subjectline = 'Your Subject'
set #message = 'Your Message body'
EXEC msdb.dbo.sp_send_dbmail #profile_name = 'dbmailProfileName'
, #recipients = 'youremails#yourdomain'
, #subject = #subjectline
, #body_format = 'html'
, #body = #message
Obviously you can declare other variables, and use the insert table for further information.
Yeah, and as Fillburt said, this seems like a duplicate of Send e-mail from a trigger

T SQL After Update Trigger on column get the value changed

I've only started exploring with triggers recently. I've set up my database mail function and all is working well. My trigger works perfectly if the column value is changed, but how do I get the value/row that changed?
USE [database]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER TRIGGER [dbo].[triggerName] ON [dbo].[tableName]
FOR UPDATE
AS
declare #cust varchar(100);
if update(Column)
BEGIN
SET NOCOUNT ON
set #cust = THE VALUE MUST GO HERE I ASSUME
END
EXEC msdb.dbo.sp_send_dbmail
#recipients = 'someone#example.com',
#profile_name = 'ProfileName',
#subject = 'Customer Information Changed',
#body = #cust;
Compare the values in inserted and deleted. If they are not the same, then the value changed.

Insert only trigger in SQL Server

I'm trying to create a trigger that sends an email ONLY when there's an insert. I currently get an email whether there's an insert or not and I WANT to get an email ONLY when there's an insert in the table. Here's how the trigger currently looks like
ALTER TRIGGER [dbo].[myTriggerName]
ON [dbo].[myTableName]
AFTER INSERT
AS
BEGIN
EXEC msdb.dbo.sp_send_dbmail
#recipients = 'MyRecipients',
#profile_name = 'DBAdmins',
#subject = 'MySubject',
#body = 'Body';
END
I would be extremely careful to put extensive processing or things like sending e-mails directly into a trigger.
The trigger executes in the context of the calling transaction, and thus delays the completion of that transaction until it is done.
If you have external dependencies (like a SMTP server), you can quickly get into situations where you have timeouts etc.
A trigger should be extremely nimble, small and fast.
My recommendation would be:
make a note into a separate table EmailToSend with all the necessary information you need (recipient, subject, body, date stored)
CREATE TRIGGER trgYourTableInsert
ON dbo.YourTable
AFTER INSERT
AS
INSERT INTO dbo.EmailToSend(Recipient, Subject, Body)
VALUES('john.doe#acme.org', 'Hello there', '.......')
have a separate process (e.g. a scheduled stored procedure that runs once every hour) checking that table and doing the actual sending of the e-mails (without blocking any other processes / transactions) - something along the lines of:
SELECT (list of columns)
FROM dbo.EmailToSend
WHERE DateSent IS NULL
or something like that - it really heavily depends on what exactly you're putting into that table and how you want to handle this ....
CREATE TRIGGER dbo.trg_I_tbl
ON dbo.tbl
AFTER INSERT
AS
BEGIN
SET NOCOUNT ON;
DECLARE #text NVARCHAR(MAX)
SELECT #text = STUFF((
SELECT ', ' + col
FROM INSERTED
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 2, '')
EXEC msdb.dbo.sp_send_dbmail
#recipients = 'your_account#gmail.com',
#subject = 'caption',
#body = #text
END
GO

How to use nested If statements in SQL trigger

I'm trying to learn SQL triggers to automatically handle events in my database but I'm having some problems with execution.
If I run the following code:
declare #userid numeric(18,0);
declare #username nvarchar(max);
set #userid = 400
execute GetUserNameFromID #userid,#username output
select #username
which calls the following stored procedure:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE GetUserNameFromID
-- Add the parameters for the stored procedure here
#UserID numeric(18,0),
#UserName nvarchar(MAX) OUT
AS
BEGIN
SET NOCOUNT ON;
SELECT #UserName = u.name from Users u where ID=#UserID
END
GO
I get a nice result 'sometestuser'
But when calling it from my trigger it fails to return a value from the stored procedure:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER Trigger [dbo].[CheckIfUserHasNoItemsLeft] on [dbo].[Items] for update
As
Begin
set nocount on
declare #inactive_user nvarchar(50);
declare #userid numeric(18,0);
declare #username nvarchar(MAX);
if ( select Count(*) from inserted ) > 1 RaIsError( 'CheckIfIserHasNoItemsLeft: No more than one row may be processed.', 25, 42 ) with log
if update(InactiveUser)
set #inactive_user = (select InactiveUser from inserted)
if #inactive_user is not null
set #userid = (select CID from inserted)
execute GetuserNameFromID #userid,#username output
if #username is not null
insert into tasks (Task) values ('The last item for ' + #username + ' has been marked inactive, check if this user should now be also marked inactive.')
End
InactiveUser is the name of the app user who has marked this item inactive, it is what I am using as a check to see if the item has been set inactive rather than create an additional boolean column just for this purpose.
I'm sure it's something simple but information on If...Then statements for SQL seems to be limited and a lot of answers suggest using Case but the query editor gives me errors about incorrect syntax no matter which way I try to do it that way.
As I'm learning I'm more than happy for someone to show me a completely new way of handling this if what I've done is wrong or bad design. I'm hoping to create a set of triggers that will add items to the tasks table for administrators to check when user accounts appear to be stale and other maintenance checks etc.
I am using SQL server 2005.
Thank you.
Edit: Changed 'value <> null' to 'value is not null'
Edit2: Added HABO's suggestion to throw an error if more than one row is detected.
How about we take a whole new approach to this. Processes like this are exactly why the inline table valued functions were created.
Let's start by converting your stored procedure to an inline table valued function.
CREATE FUNCTION GetUserNameFromID
(
#UserID numeric(18,0)
) RETURNS TABLE
AS RETURN
SELECT u.name
from Users u
where ID = #UserID
GO
That is a LOT simpler and cleaner than that stored procedure with an output variable.
Here is where it really starts to make a difference. Here is what you could do with that trigger using the newly created iTVF.
ALTER Trigger [dbo].[CheckIfUserHasNoItemsLeft] on [dbo].[Items] for update
As Begin
set nocount on
if update(InactiveUser)
insert into tasks (Task)
select 'The last item for ' + u.name + ' has been marked inactive, check if this user should now be also marked inactive.'
from inserted i
cross apply dbo.GetUserNameFromID(i.CID) u
end
This is super simple AND it is fully set based so if you update 1 or 1,000 rows it will work correctly.

Can't drop trigger

I created a trigger on a table, and now I can't alter or delete it.
I cant even access the table.
what can I do?
trigger script:
create trigger [Products].[InsertLessThen5InStock]
on [Products].[Products]
after update
as
BEGIN
DECLARE #ck int
select UnitsInStock from Products.Products where UnitsInStock<5
set #ck=##ROWCOUNT
print #ck
if #ck >0
BEGIN
DECLARE #mails varchar (200)
exec dbo.Manager_email #mails output
EXEC msdb.dbo.sp_send_dbmail
#profile_name = 'DefaultMailSender',
#recipients = #mails ,
#body = 'Products that will expire in less then 5 days',
#subject = 'Products that will expire in less then 5 days',
#body_format = 'HTML',
#query = 'EXECUTE MadCat.dbo.SaveTableAsHTML
#DBFetch =''select UnitsInStock from Products.Products where UnitsInStock<5'''
END
END
GO
Since it is complaining about not being able to get a lock, it means some process has reserved the table exclusively. You should try restarting the server, and then issuing the drop trigger command.
drop trigger [Products].[InsertLessThen5InStock]