Showing posts with label Auditing. Show all posts
Showing posts with label Auditing. Show all posts

Wednesday, February 1, 2017

Azure SQL Database - Auditing & Threat Detection

Has your database been attacked by someone?

Most of our applications are data-driven applications and attackers can use various techniques for getting into the database. One of the famous and most common techniques is SQL Injection which is a Code-Injection that modifies the statement written in the application and get it executed as attacker wants.

Here is a link for reading more on SQL-Injection: http://www.w3schools.com/sql/sql_injection.asp

Whether the database is a On-Premises database or Cloud database, if the code has been written poorly, then it is exposed for attackers. And the biggest issue is, in most cases, we do not know whether the database is attacked or not. What if someone can detects possible attacks and notifies you immediately? Yes Microsoft Azure SQL Server can do it.

If you have worked with Azure SQL Servers, you have already noticed a Setting called Auditing & Threat Detection in the SQL Server Blade. It allows you to set Auditing and in addition to that, we can enable a feature called Threat Detection which is still in Preview mode (means it will not always work as you expected until the final version is released.).

Read the post written on Auditing for more info on it: How to check success and failure logins attempts in Azure SQL Database

Threat Detection detects anomalous database activities that are considered as security threats and notifies us with details. This means, it can detects possible SQL-Injections as well. However, as per my experienced, it does not detect immediately at the initial tries but later, notification is sent immediately. As per some experts, it needs some times to learn the patterns for notifying but it is too early to make a such statement as this is still in Preview mode.

Let's see how we can use Threat Detection with an example. I created a Azure SQL database with following schema and inserted a set of records. Assume that this Sales database contains Sales made by Sales Representatives.

-- Create User table
CREATE TABLE dbo.Users
(
 UserId int identity(1,1) PRIMARY KEY
 , UserName varchar(10) NOT NULL
 , Password varbinary(1000) NOT NULL
);
GO

INSERT INTO dbo.Users
 (UserName, Password)
VALUES
 ('Dinesh', ENCRYPTBYPASSPHRASE('DK?DF%23:D', 'Dinesh123'))
 , ('Jane', ENCRYPTBYPASSPHRASE('DK?DF%23:D', 'Jane123'))
 , ('Jack', ENCRYPTBYPASSPHRASE('DK?DF%23:D', 'Jack123'));

-- Create Sales table
CREATE TABLE dbo.Sales
(
 SalesId int identity(1,1) PRIMARY KEY
 , UserId int NOT NULL
 , Constraint FK_Sales_Users FOREIGN KEY (UserId) REFERENCES dbo.Users (UserId)
 , SalesDate date NOT NULL
 , SalesAmount decimal(16,2)
);
GO

INSERT INTO dbo.Sales
 (UserId, SalesDate, SalesAmount)
VALUES
 (1, '2016-01-01', 10000.00)
 , (1, '2016-01-02', 12000.00)
 , (1, '2016-01-03', 14000.00)
 , (2, '2016-01-01', 9000.00)
 , (2, '2016-01-02', 110000.00)
 , (3, '2016-01-01', 17000.00)
 , (3, '2016-01-02', 126000.00)
 , (3, '2016-01-03', 19000.00)

Next step is creating a simple web application. I created an ASP.Net Web Application that contents with the Azure SQL Database created. I added a Web Form that contains two input boxes for accepting User Id and Password, a button for Loading User's Sales and a GridView for showing retrieved data.


This is Button-Click method written.

string sql = "SELECT u.UserName, s.SalesDate, s.SalesAmount FROM dbo.Sales s INNER JOIN dbo.Users u ON s.UserId = u.UserId WHERE ";
sql += " u.UserName = '" + TextBoxUserId.Text + "' AND DECRYPTBYPASSPHRASE('DK?DF%23:D', u.Password) =  '" + TextBoxPassword.Text + "'";

string connectionString = ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString;

SqlConnection connection = new SqlConnection(connectionString);
SqlCommand command = new SqlCommand(sql, connection);

connection.Open();
SqlDataReader reader = command.ExecuteReader();

DataTable table = new DataTable();
table.Columns.Add("UserName", System.Type.GetType("System.String"));
table.Columns.Add("SalesDate", System.Type.GetType("System.DateTime"));
table.Columns.Add("SalesAmount", System.Type.GetType("System.Decimal"));

DataRow row;
while (reader.Read())
{
    row = table.NewRow();
    row["UserName"] = reader["UserName"].ToString();
    row["SalesDate"] = Convert.ToDateTime( reader["SalesDate"]);
    row["SalesAmount"] = Convert.ToDecimal( reader["SalesAmount"]);
    table.Rows.Add(row);
}
GridView1.DataSource = table;
GridView1.DataBind();

connection.Close();

As you see, SqlCommand is not a parameterized command, hence attacker can use a simple SQL-Injection to modify the statement and get different set of data.

All done. If I check for User:Dinesh, I will be seeing Sales related to him.


However, if you use a SQL-Injection like below, I can get all Sales Records regardless of the user. 


We are not going to talk about the SQL-Injection and the poor code written in the Web Application. Let's see how we can get a notification from Azure when something like this is tried out by someone.

As you know, all we have to do is, enable Threat Detection. This how it has to be set up in Azure SQL Server Blade via Auditing & Threat Detection Setting.


Everything required is done. As you see, Threat Detection is ON and all Threat Detection types have been selected. I have added my email address for receiving alerts. Note that, you need to enable Auditing for enabling Threat Detection and it should be configured to all Audited Events.

Now if you try again with a SQL-Injection, you will immediately get a mail with details;


I can click on the View Related SQL Statements and see more details. If I click, it opens the Audit Records Blade that shows all records activities.



As you see, it is very easy to set up and you can be alerted on all suspicious activities. Try and see.

Friday, October 7, 2016

How to check success and failure logins attepmts in Azure SQL Database

Who tried to access my Azure SQL Database? Were they succeeded? Can I get more details on attempts?

If you are maintaining a Azure SQL Database, you should be asking these questions yourself. Or, practically, you need to have these questions in order to protect your database. Generally, with on-premise instance, we get these information using either Audit or Logon Triggers. Can we get the same from Azure SQL Database?

Azure SQL Database has Auditing that can be easily enabled via the portal. It does not support Logon Triggers and notifications cannot be sent via emails as it does not support Database Mail. However Audit captures everything you need and there are few ways of seeing them.

In order to see required information for my databases, I enabled Audit and then use Azure Storage Explorer to see all details because it is the easiest way. If you need the same, here is the way of doing it;

1. Open the Azure Web Portal and open SQL Server blade.
2. Click on the server you need to audit and select Auditing and Threat detection.
3. Enable Auditing. Select Table as Auditing type because it is easy to read.
4. Create a new storage for storing audit records.
5. Set the Retention (Days) as you need and set the Table name as you like.


6. Select Audited Events and check both Success and Failure check-boxes.
7. Select all Threat Detection Types.


8. Click on Save to save all settings.

As I mentioned above, there are multiple ways of getting audit records to our environment. Let's use Azure Storage Explorer and see how we can see them. Let's see how we can use other channels like Power BI with another post later.

1. Open Azure Storage Explorer and configure the connection for the storage you use. Read more on this at: http://dinesql.blogspot.com/2016/09/microsoft-azure-storage-explorer-latest-version.html
2. You should be able to see all required details related to login attempts.




Saturday, October 1, 2016

SQL Server Audit shows wrong data and time?

It was bit funny, could not figure out immediately what has happened, the records related to Audit are saved with wrong data and time.

SQL Server Audit is a the primary auditing tool in SQL Server and it is based on event-driven monitoring engine called Extended Events. It is used for tracking actions performed against the database and server instance, mainly for auditing.

I have written three posts on it, have a look on if you are new to SQL Server Audit;




While discussing the topic, we witnessed that SQL Server has saved audit records with wrong date and time. It took few minutes to realize that it is NOT wrong at all, records are save with UTC time standard. If you need to get the write data and time, you need to covert it to the time based on your time zone.

In my case, in order to see the right date and time for my audit records, I have to convert the UTC to +05:30 time zone like below.

SELECT 
 convert(datetime, SWITCHOFFSET(event_time, '+05:30')) event_time
 , object_name, user_defined_event_id, statement, user_defined_information
FROM sys.fn_get_audit_file ('c:\temp\*',default,default);

Now the question is, how to see the same if Audit is recorded with Windows Application Log or Security Log. Not sure about the way but will check and see. If you have already found a solution, please share.

Friday, September 11, 2015

How to enable SQL Server Audit for Windows Security Log

I have written few posts on SQL Server Auditing and they are written based on either Windows Event Log or File as the target of the Audit;


There is another option that can be set for the target which is Windows Security Event Log which is the most secured place for placing audit info. But, it cannot be set as simple as other targets, it needs some extra steps.

If I have created an Audit like below;


and try to enable;


I get this error. Reason for this is, for setting the target as Windows Security Log, SQL Server Service Account has to be a member of Generate Security Audit Policy. For that, open Local Security Policy and add SQL Server Service Account to Generate Security Audit Policy.


You may need to restart the SQL Server before trying with enabling the Audit created. Once done, you will be successfully enable the Audit.


Thursday, September 10, 2015

SQL Server Audit for application event - User-Defined Audit Actions

SQL Server Audit is the main tool for capturing events related to server and databases, and it can record event information to files, Windows Application Event Log, and Windows Security Event Log. All editions of SQL Server support server-level auditing but only Enterprise, Developer and Evaluation editions support database-level auditing. 

When defining an Audit, it needs to specify an Audit (1), then either Server-Specification or Database-Specification (2) specifying what Action/Action Group need to be included. Action/Action Groups are pre-defined comprehensive events that cover almost all events related to server and databases. Once configured, events are recorded with the given target. What if we want to raise our own events and get the captured with the same Audit?

Good example is, tracking changes in Product table, specifically on the Price column. If an Audit is already defined for other events, and need to use same target for recording price changes too, all we have to do is, include USER_DEFINED_AUDIT_GROUP Action Group to either Server or Database specification and use sp_audit_write stored procedure for recording our custom event. Here are steps for doing it.

Let's create an Audit first. If you have already created an Audit, you do not need to create it. Go to security node in the Object Explorer , then Audit node, and then create a new Audit.



Next, let's create a Server-Specification. Note that I have included two events; FAILED_LOGIN_GROUP and USER_DEFINED_AUDIT_GROUP. The second one added is for custom events.



Capturing ListPrice changes can be easily implemented with a Trigger and sp_audit_write procedure can be called within it. Here is the sample code for implementing it.

USE AdventureWorks2014;
GO

CREATE TRIGGER Production.CheckPriceChanged ON Production.Product
AFTER UPDATE
AS
BEGIN

 DECLARE @Message nvarchar(4000)
  , @OldPrice money
  , @NewPrice money
  , @ProductNumber nvarchar(25)

 IF UPDATE(ListPrice)
 BEGIN
 
  SELECT @OldPrice = ListPrice FROM deleted;
  SELECT @NewPrice = ListPrice, @ProductNumber = ProductNumber FROM inserted;

  SET @Message = N'Price changed: Product Number: ' +  @ProductNumber + N' Old price: ' + CONVERT(nvarchar(20), @OldPrice) + N' New price: ' 
      + CONVERT(nvarchar(20), @NewPrice) + N' User: ' +  CONVERT(nvarchar(20), SYSTEM_USER)

  -- Calling auditing stored procedure
  EXEC sp_audit_write 1, 1, @Message;
 END 
END;
GO

Let's make some changes and see how it is going to be recorded.

-- Updating records
UPDATE Production.Product
 SET ListPrice = 100
WHERE ProductID = 1;

UPDATE Production.Product
 SET ListPrice = 0
WHERE ProductID = 1;

-- Checking the audit output with fn_get_audit_file
SELECT event_time, object_name, user_defined_event_id, statement, user_defined_information
FROM sys.fn_get_audit_file ('c:\Audit\*',default,default);


Tuesday, August 25, 2015

Who modified my tables: tracking SQL Server table changes

What is the easiest way of capturing changes on tables? I was asked this question and what immediately came to my mind was DDL Triggers. Though this is not a new feature of SQL Server, it is still unknown to many and various ways are implemented for capturing changes.

DDL Trigger can be implemented for capturing almost all DDL changes. Here is the code for capturing changes made to tables;

USE AdventureWorks2014;
GO

-- Creating a table for holding changes
CREATE TABLE TableChanges 
(
 ChangedDate datetime,
 EventType nvarchar(100), 
 TableName nvarchar(100), 
 LoginName nvarchar(100), 
 SQLCommand nvarchar(2000));
GO

-- Creating the DDL trigger for tables
CREATE TRIGGER CaptureTableChanges 
ON DATABASE 
WITH EXECUTE AS 'dbo'
FOR ALTER_TABLE, DROP_TABLE 
AS

 DECLARE @data XML

 SET @data = EVENTDATA();

 INSERT TableChanges 
  (ChangedDate, EventType, TableName, LoginName, SQLCommand) 
   VALUES 
  (getdate(), 
  @data.value('(/EVENT_INSTANCE/EventType)[1]', 'nvarchar(100)'), 
  @data.value('(/EVENT_INSTANCE/ObjectName)[1]', 'varchar(100)'),
  @data.value('(/EVENT_INSTANCE/LoginName)[1]', 'varchar(100)'),
  @data.value('(/EVENT_INSTANCE/TSQLCommand)[1]', 'nvarchar(2000)')
  ) ;
GO

-- Creating a login and user for testing
CREATE LOGIN Jack WITH PASSWORD = 'Pa$$w0rd', CHECK_EXPIRATION = OFF, CHECK_POLICY=OFF;
GO
CREATE USER Jack FOR LOGIN Jack;
GO
ALTER ROLE db_ddladmin ADD MEMBER Jack;


-- Use a different window for this
-- Connect using Jacks credentials and execute
ALTER TABLE Production.Product
 ALTER COLUMN Color nvarchar(20);
GO

-- Check captured changes
SELECT * FROM TableChanges ;
GO