Showing posts with label Security. Show all posts
Showing posts with label Security. Show all posts

Monday, October 16, 2017

SQL Server Always Encrypted - Serving applications using Azure Key Vault and Certificate Store

Here is my second video related to Always Encrypted. This video discusses the way of configuring CMK for serving multiple applications hosted in multiple places, using Local Key Store - Certificate Store and Centralized Key Store - Azure Key Vault.


Here are the codes related to the video. I create a table in my Azure SQL Database, this is the code for it;

CREATE TABLE dbo.Message
(
 MessageId int identity(1,1) primary key
 , MessageCode char(5) COLLATE Latin1_General_BIN2 not null 
 , Message varchar(4000)  COLLATE Latin1_General_BIN2 not null
);
GO

INSERT INTO dbo.Message (MessageCode, Message)
 VALUES ('AA56B', 'This is a test message');
GO

CREATE OR ALTER PROCEDURE dbo.AddMessage @MessageCode char(5)
  , @Message varchar(4000)
AS
BEGIN

 INSERT INTO dbo.Message
  (MessageCode, Message)
 VALUES
  (@MessageCode, @Message);
END
GO


CREATE OR ALTER PROCEDURE dbo.GetMessage @MessageCode char(5)
   , @Message varchar(4000) OUTPUT
AS
BEGIN

 SELECT @Message = Message 
 FROM dbo.Message
 WHERE @MessageCode = MessageCode;
END
GO

And then, I have a .Net Application that accesses Azure Key Vault for taking the CMK and inserting and updating records. Here is the code of it. 

private static ClientCredential _clientCredential;

static void InitializeAzureKeyVaultProvider()
{
    _clientCredential = new ClientCredential("9e67ee1f-50ef-49d1-8ee0-0c48eaf4457b", "HjRqkx7BKLP7Lu+UYgTa5D/zCKAdxx3YITQ6fRrsQTQ=");

    SqlColumnEncryptionAzureKeyVaultProvider azureKeyVaultProvider =
        new SqlColumnEncryptionAzureKeyVaultProvider(GetToken);

    Dictionary providers =
        new Dictionary();

    providers.Add(SqlColumnEncryptionAzureKeyVaultProvider.ProviderName, azureKeyVaultProvider);
    SqlConnection.RegisterColumnEncryptionKeyStoreProviders(providers);
}

public async static Task GetToken(string authority, string resource, string scope)
{
    var authContext = new AuthenticationContext(authority);
    AuthenticationResult result = await authContext.AcquireTokenAsync(resource, _clientCredential);

    if (result == null)
        throw new InvalidOperationException("Failed to obtain the access token");
    return result.AccessToken;
}

public Form1()
{
    InitializeComponent();
    InitializeAzureKeyVaultProvider();

}

private void buttonSubmit_Click(object sender, EventArgs e)
{
    SqlConnection connection = new SqlConnection("Password=Pa$$w0rd;Persist Security Info=True;User ID=Dinesh;Initial Catalog=Marketing;Data Source=dinesqlserver.database.windows.net;Column Encryption Setting = Enabled");
    SqlCommand command = new SqlCommand("AddMessage", connection);
    command.CommandType = CommandType.StoredProcedure;

    SqlParameter parameterMessageCode = new SqlParameter("MessageCode", SqlDbType.Char, 5);
    parameterMessageCode.Value = textBoxMessageCode.Text;

    SqlParameter parameterMessage = new SqlParameter("Message", SqlDbType.VarChar, 4000);
    parameterMessage.Value = textBoxMessage.Text;

    command.Parameters.Add(parameterMessageCode);
    command.Parameters.Add(parameterMessage);

    connection.Open();
    command.ExecuteScalar();
    connection.Close();

}

private void buttonGet_Click(object sender, EventArgs e)
{
    SqlConnection connection = new SqlConnection("Password=Pa$$w0rd;Persist Security Info=True;User ID=Dinesh;Initial Catalog=Marketing;Data Source=dinesqlserver.database.windows.net; Column Encryption Setting = Enabled");
    SqlCommand command = new SqlCommand("GetMessage", connection);
    command.CommandType = CommandType.StoredProcedure;

    SqlParameter parameterMessageCode = new SqlParameter("MessageCode", SqlDbType.Char, 5);
    parameterMessageCode.Value = textBoxMessageCode.Text;

    SqlParameter parameterMessage = new SqlParameter("Message", SqlDbType.VarChar, 4000);
    parameterMessage.Direction = ParameterDirection.Output;

    command.Parameters.Add(parameterMessageCode);
    command.Parameters.Add(parameterMessage);

    connection.Open();
    command.ExecuteScalar();
    connection.Close();

    MessageBox.Show(parameterMessage.Value.ToString());
}

You can find more information and standard codes related to Azure Key Vault usage with Always Encrypted at: https://docs.microsoft.com/en-us/azure/sql-database/sql-database-always-encrypted-azure-key-vault


Thursday, October 12, 2017

Introduction to Always Encrypted

Here is my second video that speaks about Always Encrypted feature. This video shows How Always Encrypted works, how it should be configured and how we can access and update date using a .Net application.


Tuesday, March 14, 2017

Which protocol has been used for my SQL Server connection?

SQL Server uses 3 protocols to make the communication between client and the server. Initially there were 4 protocols but now it supports only 3: Shared Memory, Named Pipes and TCP/IP. We can enable/disable these protocols from server-end and change the priority order from client-end. Now, how do I know which protocol has been used for my connection?

We can easily see this by using sys.dm_exec_connection dynamic management view. It shows all current connection along with the used protocol. The net_transport is the one that shows it.

Here is a sample code. The first connection 54, was made without specifying anything additional when connecting, hence it has used Shared Memory. This protocol is used when it is enabled and connection made using the same machine that hosts the SQL Server. The second connection 56 has been established using Named Pipes because I forced to use Named Pipes for my connection.


How can I force the protocol when connecting via SSMS? It is simple. When connecting, if you use lpc: as the prefix for the server name, it uses Shared Memory. If you use np:, then it uses Named Piped.


Thursday, February 16, 2017

Creating multiple administrative accounts in Azure SQL Database Server

You know that we can create multiple administrator accounts in SQL Server if it is a on-premises instance or an instance configured in a VM (hosted in cloud or on-premises). What we generally do is, create a login and add the login to sysadmin fixed server role. Can we do the same in Azure SQL Database (Server)?

There is only one unrestricted administrative account that can be be created in Azure SQL Database Server. It is created when creating the server. In addition to that, you can add either one Azure Active Directory Account or Security Group Account (that has multiple accounts as members). If you open the Properties of your server, you can see your administrative accounts;


However, if you need to add multiple administrative accounts (not unrestricted administrative accounts), then there is a way of adding them. There are two server-level administrative roles that are available in the master database which user accounts can be added for granting permissions for creating and managing databases and logins.

The first role is dbmanager. This role has permission to create new databases, hence members of this role can create databases. This role exist in the master database. Therefore, only users in the master database can become members of this role.

-- In master database
-- creating a user
CREATE USER Dinesh2 WITH PASSWORD = 'Pa$$w0rd';

-- adding the user to dbmanager role
ALTER ROLE dbmanager ADD MEMBER Dinesh2;

The other role is loginmanager. This role has permissions for creating logins in the master database. Again, this role is master database, hence only users in master database can become members of it.

-- In master database
-- creating a user
CREATE USER Dinesh3 WITH PASSWORD = 'Pa$$w0rd';

-- adding the user to loginmanager role
ALTER ROLE loginmanager ADD MEMBER Dinesh2;

Wednesday, February 15, 2017

Should I create Azure SQL Logins or Azure SQL Users?

Unless it is a contained database, we must create a login for connecting with SQL Server in order to access a database. Databases are accessed using Users and Users are created using Logins. Is it same with Azure SQL Databases? Should I create a login before creating a user?


With Azure SQL Database, it is not a must as Azure SQL database is a contained database (portable). We can create a user account with a password for accessing the database without creating a login. However, it allows us to create a login in the master and then create a user in our database using the login created in the master.

What if I created a user in my database using a login?
The main advantage is maintenance. If the login needs to be dropped or disabled, it can be simply done in the master database. Not only that, since multiple user accounts can be created with multiple databases using the same login, one login can be used for connecting the multiple databases.
The biggest disadvantage with this is, database becomes non-portable. If databases needs to be copied, moved or replicated, login must be created with new servers.

What if I created a user in my database without creating a login?
The main benefit we get is a portable database. Since all users with passwords are maintained inside the database, it can be copied, moved, replicated without any issue.
However, if the environment has multiple databases and users need to access more than one database, then multiple user accounts have to be created.

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, January 13, 2017

SQL Server - Adding an Authenticator when encrypting data

Among multiple methods given for securing data stored in the SQL Server database, even though the latest one which is Always Encrypted is available, we still use Keys. Passphrases and Certificates for encrypting data. When keys such as Symmetric Keys or Asymmetric Keys, or Passphrases are used for encrypting data, an additional parameter can be supplied which is called Authenticator. Since I recently used this for one of my database solutions, thought to make a note on it.

What is the usage of Authenticator? Why we should use it. Let's take an example and understand with it.

The following code creates a database and a table that holds Customers. The Security Code of the customer will be encrypted.

-- Create a database
CREATE DATABASE Sales;
GO

-- Connect with newly cerated database
USE Sales;
GO

-- Create a master key
CREATE MASTER KEY ENCRYPTION BY PASSWORD = 'Pa$$w0rd';
GO 

-- Create a certificate for protecting the our key 
CREATE CERTIFICATE SalesCertificate WITH SUBJECT = 'Sales Certificate';
GO

-- Create the key for encrypting data
-- Note that the created certificate protects it.
CREATE SYMMETRIC KEY SalesKey
WITH ALGORITHM = AES_128  
ENCRYPTION BY CERTIFICATE SalesCertificate;
GO

-- Creating a table that holds customers
-- Note the Securiry Code Column, it is varbinary 
-- because code will be encrypted and stored
CREATE TABLE dbo.Customer
(
 CustomerId int identity(1,1) PRIMARY KEY
 , Name varchar(100) NOT NULL
 , SecurityCode varbinary(256) NOT NULL
);
GO

Let's insert some records.

OPEN SYMMETRIC KEY SalesKey DECRYPTION BY CERTIFICATE SalesCertificate ;
GO

INSERT INTO dbo.Customer
 (Name, SecurityCode)
VALUES
 ('Dinesh', ENCRYPTBYKEY(KEY_GUID('SalesKey'), 'CUS005XZ'))

INSERT INTO dbo.Customer
 (Name, SecurityCode)
VALUES
 ('Yeshan', ENCRYPTBYKEY(KEY_GUID('SalesKey'), 'CUS02ANX3'))


Once inserted, data will be looked like below;


And if I try to retrieve records, I need to decrypt encrypted values;


So far so good. Now let's try understand the usage of Authenticator. Assume that Yeshan needs to access some Securables that can be accessed only by Dinesh through an application. For that, all Yeshan needs is, log in to the application using Dinesh's Security Code. Since he does not know Dinesh's Security Code, one way of accessing the application using Dinesh's account is, replacing the Dinesh's code with his code. Let's see whether it is possible.

The following code updates Dinesh's account with Yeshan's code. And as you see, it gets updated and now Yeshan can use Dinesh account as he knows the code.


This should not be allowed and even if it is possible, what if we make sure that encrypted code cannot be replaced like that. That is what we can do with the Authenticator.

Look at the following code. It passes two additional values for encrypting. The third one which is 1 says that this has an Authenticator. The forth parameter is the data from which to derive an Authenticator.

OPEN SYMMETRIC KEY SalesKey DECRYPTION BY CERTIFICATE SalesCertificate ;
GO

-- Update Security codes with CustomerId as the Authenticator
UPDATE dbo.Customer
 SET SecurityCode = ENCRYPTBYKEY(KEY_GUID('SalesKey'), 'CUS005XZ', 1, Convert(varbinary(256), CustomerId))
WHERE CustomerId = 1;

UPDATE dbo.Customer
 SET SecurityCode = ENCRYPTBYKEY(KEY_GUID('SalesKey'), 'CUS02ANX3', 1, Convert(varbinary(256), CustomerId))
WHERE CustomerId = 2;


Just like the previous code, values are encrypted now. However, if Yeshan tried to do the same, see the result;


As you see, even though Dinesh's code has been replaced with Yeshan's code, when try to decrypt value of Dinesh, it results null because Authenticator is different. This is the usage of the Authenticator.

Note that we used CustomerId as the Authenticator but you can use something else, something uncommon as the Authenticator to make it more secured and avoid malicious activities like this.


Thursday, January 12, 2017

Incorrect syntax near 'TRIPLE_DES'. - SQL Server throws an error when try to use algorithms

Assume that you use SQL Server 2016 and trying to create a Symmetric Key or Asymmetric Key for encrypting data. If you try use an algorithm like TRIPLE_DES, you will get the mentioned error;

Msg 102, Level 15, State 1, Line 20
Incorrect syntax near 'TRIPLE_DES'.

Here is a sample code for seeing this error;

-- Create a database
CREATE DATABASE Sales;
GO

-- Connect with newly cerated database
USE Sales;
GO

-- Create a master key
CREATE MASTER KEY ENCRYPTION BY PASSWORD = 'Pa$$w0rd';
GO 

-- Create a certificate for protecting the our key 
CREATE CERTIFICATE SalesCertificate WITH SUBJECT = 'Sales Certificate';
GO

-- Create the key for encrypting data
-- Note that the created certificate protects it.
-- However, this will throw an error
CREATE SYMMETRIC KEY SalesKey
WITH ALGORITHM = TRIPLE_DES  
ENCRYPTION BY CERTIFICATE SalesCertificate;
GO

Now, what is the reason for this. The reason for this is, this algorithm is deprecated in SQL Server 2016. Not only that, All Algorithms except AES_128, AES_192, and AES_256 are deprecated in SQL Server 2016

What if you still need one of these deprecated algorithms? Yes, it is possible, but you need to downgrade the database by changing the Compatibility Level 120 or below.

This code shows the way of doing it.


USE master;
GO

-- Change the compatibility level to 120
ALTER DATABASE Sales
SET COMPATIBILITY_LEVEL = 120;

-- And check again
USE Sales;
GO

-- This will work now without any error
CREATE SYMMETRIC KEY SalesKey
WITH ALGORITHM = TRIPLE_DES  
ENCRYPTION BY CERTIFICATE SalesCertificate;
GO

Even though you can use the algorithm after changing the Compatibility Level, remember lower Compatibility Level might not let you to use all functionalities available with SQL Server 2016. Therefore, if possible, use allowed algorithms only.

Saturday, December 31, 2016

Azure SQL Databases - Prevent accidental deletes - Azure Locks

Have you ever deleted a database accidentally? If you have done, then you know very well that how it makes you uncomfortable :). If you are managing a very important database and you should make sure that even authorized users cannot easily delete the database without taking an additional action, Azure has a way of configuring it. It is called Azure Locks.

Azure Locks is part of Azure Resource Manager. It allows us to set locks on two ways;
  • Read-only - makes sure that authorized users can read the resource but editing and deleting are not possible.
  • Delete - makes sure that authorized users CANNOT DELETE the resources.
For example, if you set a Delete Lock at one of your Azure SQL Servers, no resources available under the SQL Server such as A Database cannot be deleted until the Lock is released. You can do the same for a database instead setting the lock at the server level as well.

Here is an example. If we need to set a Delete Lock for one of SQL Servers, get the Server Properties Blade opened and click on the Locks property.


Once the Locks Blade is opened, we can add a lock by clicking the Add Button. As shown in the above image, I have set the name of it as DeleteLock, Lock type as Delete and a small note. Once this is saved, this lock gets applied to all resources that come under the selected SQL Server.

If I try to delete a database in that server, Azure Resource Manager makes sure that I cannot delete the database until I remove the lock.



Friday, December 23, 2016

Delete All Azure SQL Server Firewall Rules using TSQL

In order to access Azure SQL Server databases, firewall rules have to be set at either server level or database level by adding client IP addresses. Server level rules can be configured using the Azure Portal but database level rules have to be done using TSQL. If you have many added many rules and you need to delete all or some, and if you try to use the portal for deleting, it will take long time because portal allows you to delete one at a time.

Assume that you have many number of server level rules configured as below;


I was asked about this and here is the script I wrote to delete selected server level firewall rules.

DECLARE @name nvarchar(200)
WHILE EXISTS (SELECT name FROM sys.firewall_rules WHERE name LIKE 'clientIPAddress_%')
BEGIN

 SELECT TOP (1) @name = name FROM sys.firewall_rules WHERE name LIKE 'clientIPAddress_%'
 EXEC sp_delete_firewall_rule @name;
END

It is a simple one but you can use it without using the portal. Make sure you have written the WHERE Condition properly otherwise it might delete rules you may need.

Thursday, December 22, 2016

Azure SQL Database - Enable TDE - Does it encrypt the bacpac file?

We use Transparent Data Encryption (TDE) for protecting our databases, making sure that no one can get our databases added to a different instance even though they manage to get either data files (.mdf) or backup files (.bak). TDE makes sure that data in data files is encrypted and it is called as encrypting data at rest. The standard way of enabling this is;
  1. Create a master key in master database.
  2. Create (or add an existing one from a copy) a certificate protected by the master key.
  3. Create a database encryption key protected by the certificate, in the database needs to be protected.
  4. Enable encryption in the database.

This is different with Azure SQL Database. Azure allows us to enable TDE with Azure SQL Database. It does not require steps like above, it can be simply enabled using the portal.


Although we do not create the certificate and the database encryption key manually, the storage of the database is encrypted using a symmetric key that is protected by a built-in server certificate in the SQL Server
.
Not only that, the main exception comparing with TDE-Enabled On-Premises database is, copying this database from the portal to local environment. If the database is not an Azure SQL Database and if you take a backup of it, you will not be able to restore it in another instance without certificate created for TDE. But if the database is an Azure SQL Database, when you export it to a bacpac file, it can be loaded to any instance without the Azure SQL Server level Certificate used to protect it. See below images;

1. Exporting the bacpac to classic storage.


2. Loading the database to on-premises server using Import Data-tier application... wizard.


3. Getting the database successfully added.



The reason for this is, when exporting a TDE-Enabled Azure SQL Database, the bacpac file is not getting encrypted, hence we need to make sure that it is secured.

Tuesday, November 29, 2016

What if EXECUTE AS statement executes multiple times

While discussing about Impersonation, a question raised; If we mistakenly execute EXECUTE AS statement twice, do we have to call REVERT twice?.

I was not sure about it since I have not done it but realized that it is required.

EXECUTE AS statement allows us to set the execution context by impersonating another login or user. This is useful when a code that requires a different permission set for running and user logged in has no permission for running it. Once this is set, either we have to call REVERT command to go back to the original context or it will be remained in effect until the session is dropped or the module (stored procedure or trigger) where the command was executed exist.

EXECUTE AS statement can be executed multiple times either using same Principal or different Principals (read more with SQL Server Security Concepts: Securables, Pricipals and Permissions). If need to switch back to original context, then REVERT must be called for each context opened.

As per the research I made, there is no way of reverting all context using a single command and bringing the original context back to the session. Therefore, if we have mistakenly execute the statement multiple times, no other option but call REVERT multiple times.

However, we can use sys.user_token for checking whether the original context is set or not. Here is a sample code.


The current context is based on my account. Let's change the context and execute the same.

EXECUTE AS USER = 'Peter'  

SELECT * FROM sys.user_token;
SELECT ORIGINAL_LOGIN();


As you see, now the execution context is set with Peter's account. We can use ORIGINAL_LOGIN function for checking the initial login. If EXECUTE AS USER = 'Peter' statement is executed again, then it creates another context. Here is the the result;


Now if REVERT is called, it does not bring the session back to original context because it reverts only the last one created.

REVERT;

SELECT * FROM sys.user_token;
SELECT ORIGINAL_LOGIN();



Therefore, REVERT has to be called again. Here is another way of checking whether the session uses the original execution context or not.

SELECT login_name, original_login_name, * 
FROM sys.dm_exec_sessions
WHERE program_name like '%Management Studio%'


Saturday, October 22, 2016

How to restirct access to DMVs and DMFs for users

We heavily use Dynamic Management Views and Functions for retrieving insight of inner operations of SQL Server and they are very useful. These DMVs and DMFs are based on Dynamic Management Objects (DMOs).

Generally, if user has permission on VIEW SERVER STATE and VIEW DATABASE STATE, user can execute almost all DMVs and DMFs. If you are a member of sysadmin server role, then you automatically get permission on VIEW SERVER STATE and if your login is a standard login and it has been added to one of the databases as a member of db_owner role, then you have VIEW DATABASE STATE permissions. These permission can be granted explicitly without adding logins or users to the specific roles.

However, if you need to restrict accessing specific DMVs or DMFs to users on one or more databases, there is an easy way of doing it. All we have to do is, restrict access on the specific DMVs and DMFs in the master database to user. It makes sure that user cannot access them regardless of the database context. 

Let's assume that user Jane should not be able to execute sys.dm_sql_referenced_entities DMF in any database. Here are the steps for doing it;

1. Create a user in master database for Jane's login.
2. Open properties of User Jane and click on Securables for listing required objects.


3. Click on Search for finding objects. Select All objects of the types... and click OK.


4. Select Table-valued function and click OK.


5. Select sys.dm_sql_referenced_entities DMF and set Deny permission on SELECT.


6. Click OK to save settings.

Now if you Jane tries to execute this DMF, she will get an error on it as below;


Tuesday, October 11, 2016

How to find NT Service\MSSQLSERVER and NT Service\SQLSERVERAGENT accounts?

You have installed SQL Server and it is up and running without any issue. Later, you need to change some permission given to either SQL Server engine or agent. You look for accounts, searched in local users, searched in local groups but you cannot find them.

Are you experiencing above issues? If yes, first understand the what are these accounts. These are called Virtual Accounts that are created during the installation of SQL Server. These accounts are managed by the Operating System itself, hence they are not visible when you browse Local Users and Groups window. Similarly, there is another type of accounts called Managed Service Accounts that are created at domain level and assigned to SQL Server services.


Now, for some reason, if you changed the service account of your SQL Server service to another account, and later you want to use the same Virtual Account, this is what you have to do.

1. Get the properties of the services.


2. Easiest way is, just type the account and leave the password blank. If the instance is default, type it as NT Service\MSSQLSERVER or if it is a named instance, type NT Service\MSSQL$.


3. Click on to get the service restarted. It will work as you expected.

4. Or, if you want to search the account, click on Browse to open Select User or Group window. Type nt service\ms in Enter the object name to select input box and click on Check Names. If you are setting the Agent Service, look for nt service\sql word.


5. You get Multiple Names Found window opened. Select the account from the list and continue. Do not enter a password, click on OK and get the service restarted.


Just like this, if you need to add these accounts to some other groups for granting more permissions, example, adding Agent Service Account to Administrators Group (not recommended), follow the same steps.


Tuesday, October 4, 2016

What are dbmanager and loginmanager database roles in Azure SQL Database instance

Have you noticed two new database roles appeared in master database? You might have, you might have not, because these two appear only with Azure SQL Database instance. What are they and what is the usage of them?

dbmanager database role
Azure SQL Database instance does not offer any server level roles and no user can be created similar to sa that we have seen with on-premise instances. Since we do not have administrative control over Azure SQL Database instance, the dbmanager role is given to us inside the virtual master database. Generally, when the instance is created using the portal, the account added becomes the admin of the instance and account will be added to the master database. If you need more administrators who can create databases, then you need to create a new user and add the user to this role.

Here are the steps. You need to make sure that you are connected with master database.

CREATE USER Jane WITH PASSWORD = 'Pa$$w0rd'; 
ALTER ROLE dbmanager ADD MEMBER Jane; 

dbmanager database role
Just like the above one, if you need users who can perform operations related to users such as create, alter user account, create a user and add him to this role.

CREATE USER Jack WITH PASSWORD = 'Pa$$w0rd'; 
ALTER ROLE loginmanager ADD MEMBER Jack; 

However, this is not much required and important with Azure SQL Databases as almost all databases are treated as Contained Databases. Therefore required permissions can be simply granted to user as below without creating user accounts in master and adding them to loginmanager role.

GRANT ALTER ANY USER TO Jack;


Monday, October 3, 2016

SQL Server Data Masking - Filtering masked values

SQL Server 2016 introduced Dynamic Data Masking for obfuscating certain values in records, not exactly as a security measure but for hiding sensitive data. While this was being discussed, a question raised: Can we filter data even when data is masked and no permission to unmask?

Generally, unless you are a member of db_owner role, you cannot read masked data. If need, you should be granted with UNMASK permission. Now can you masked filter data? Can you group masked data? Can you do them even if you have no permission for unmasking?

Yes, it is possible. Let's have a look on below code;

-- Create a test database
CREATE DATABASE Sales
GO

-- Connect with it
USE Sales;
GO

-- Create a sample table with masked columns
CREATE TABLE dbo.RetailCustomer
(
 RetailCustomerId int identity(1,1) PRIMARY KEY
 , Name varchar(100) NOT NULL
 , EmailAddress varchar(100) MASKED WITH (FUNCTION = 'email()') NOT NULL
 , CreditLimit decimal(16,2) MASKED WITH (FUNCTION = 'random(1, 10000)') NOT NULL
 , SecurityTokenCode char(10) MASKED WITH (FUNCTION = 'partial(2, "xxxx", 0)') NOT NULL
);
GO

-- Insert set of records
INSERT INTO dbo.RetailCustomer
 (Name, EmailAddress, CreditLimit, SecurityTokenCode)
VALUES
 ('Customer1', 'customer1@gmail.com', 10000, 'EX12345678')
 , ('Customer2', 'customer1@company.lk', 120000, 'EX11223344')
 , ('Customer3', 'customer3@abc.com', 8000, 'TX11223344')

-- Checking records;
SELECT * FROM dbo.RetailCustomer;


As you see, I do not see data as masked data because I am a member of db_owner role. But if you check with different account, he will see masked data. See the code below;

-- Creating a user
CREATE USER Peter WITHOUT LOGIN;

-- Grant read permission to Peter
-- Note that this does not mean that he can unmask
GRANT SELECT ON dbo.RetailCustomer TO Peter;

-- Check with his account
EXECUTE AS USER = 'Peter'
SELECT * FROM dbo.RetailCustomer
REVERT;


We can grant unmask permission to Peter but let's see whether he can do some aggregation and filtering with masked data.

EXECUTE AS USER = 'Peter'
-- Can he aggregate masked values
SELECT SUM(CreditLimit) FROM dbo.RetailCustomer;

-- Can he performed operations against masked values
SELECT LEN(EmailAddress) FROM dbo.RetailCustomer;
SELECT LEFT(EmailAddress, 2) FROM dbo.RetailCustomer;

-- Can he filer records with masked columns
SELECT * FROM dbo.RetailCustomer WHERE CreditLimit = 120000
SELECT * FROM dbo.RetailCustomer WHERE EmailAddress = 'customer1@company.lk';

REVERT;


See the result. He cannot do some operations but he can do filtering without any issue. Looks unsecured? Do not worry, that is why I mentioned that Dynamic Data Masking is not for securing or encrypting data, it is for obfuscating values.

Sunday, October 2, 2016

SQL Server Brain Basher of the Week #055 - Security

You are the Database Administrator and you maintain a database with following characteristics;

  • Database contains sensitive data.
  • Database authentication is set to Mixed Mode.
  • Users can access only tables they are authorized. Authorization is completely handled with SQL Server.
  • Tables related to finance data can be accessed only by users who are in Finance User-Defined Database Role.

Sales team uses their own application to access the database. There is a new requirement from the Sales team as below;
  • Sales team needs to see some financial data through the application.
  • Sales team members should NOT be able to execute impromptu SELECT, INSERT, UPDATE, and DELETE statements against financial tables.
  • The application will prompt for the second password when the screen related to finance data is opened. Sales person needs supervisor to input the second password for seeing data.
Here is the question of the week;

Being a DBA, what is your suggestion to achieve above requirement?

There are couple of things you need to consider. First, although users access the database via applications, users credentials are used for authorization, means users need permissions on finance data in order to access them. But, secondly, if users are granted permissions, they will be able to execute impromptu queries against tables, which should not be avoided. How can you grant permission to these specific tables without giving explicit permissions to users or roles?

If you are a smart DBA, now you should think about Application Roles

An Application Role is a database level role that permissions can be set with an application via the role, without setting permissions to users or other roles. You create it with a password, grant permissions as needed, in this case, let's say two tables related to finance, and then open the Application Role when two tables are required to access.

Since Supervisor enters the password, it can be used as the Application Role password. Once the application accepts the password, it calls a special stored procedure called sp_setapprole with the name of the Application Role and password. This creates New Security Context for the application connection and current user's context becomes inactive. User's security context will only be back once the sp_unsetapprole is called, until that, only Application Role and Public tokens are available for accessing resources.


Note that once the Application Role is active, user can only access other databases via guest account only.

For more info on Application Role, read this: https://msdn.microsoft.com/en-gb/library/ms181491.aspx

Friday, September 30, 2016

How to check my permission on SQL Server object

How do you check and see whether you have permission on a specific object and what permission types you have been granted? This requirement comes whenever you experience a permission issue and it might not be easy to get relevant information from relevant department or person. However, SQL Server offers a function for us: fn_my_permissions. This function can be used for seeing all permissions you have been granted on a particular object;

SELECT * FROM fn_my_permissions (NULL, 'DATABASE');
USE AdventureWorks2014; GO
SELECT * FROM fn_my_permissions('Sales.SalesOrderHeader', 'OBJECT') ;


This function accepts securable and securable class. There are multiple classes such as DATABASE, SCHEMA, OBJECT etc.


Saturday, November 21, 2015

SQL Server Brain Basher of the Week #034 - Analysis Services Security

Security is the most important area that needs to be addressed with many solution and same goes to your Business Intelligence solutions implemented with Microsoft Analysis Services. Typically, all database management systems provide multiple server roles for managing permission, and allow us to extend it either creating custom server roles or database roles. This week question is based Analysis Services server roles;

How many server roles are exist with Analysis Services and what are they?

You do not want to think about this much. Analysis Services offers only one server level role called as Administrators. This cannot be modified and we cannot create any additional roles, but we can add members to this role providing admin rights to anyone required. However system allows us to create additional database level roles which are limited to specific databases.

You can access Administrators role by getting properties of the instance and selecting Security property.


Database roles can be created by accessing Roles node under the database.



Thursday, September 3, 2015

Granting permission on tables - individual tables or schema?

When there is a requirement for granting permission on tables for database users, common or known way of doing it is, granting explicit permission on individual objects for users. But, if database objects are schema-based objects and properly organized, then most appropriate way of managing permission is, granting permission on schema rather than granting permission on tables (or any other objects). The main reason for this is, any granted permission on a schema will by implicitly applied to all objects defined under the schema.

Example, if there are two tables called Product and ProductCategory and they have been created under Production schema, granting SELECT permission on Production schema is totally enough for granting SELECT permission to Product and ProductCategory tables.

Here is a test code;

/*
Creating a login and user called Jack
*/

USE master;
GO

CREATE LOGIN Jack WITH PASSWORD = 'Pa$$w0rd'
 , CHECK_POLICY = OFF;
GO

USE AdventureWorks2014;
GO

CREATE USER Jack FOR LOGIN Jack;
GO

-- Check and see whether Jack has permission on HumanResources schema
-- Login as Jack and see permissions
EXECUTE AS USER = 'Jack';
GO

SELECT * FROM HumanResources.Department;
GO

REVERT;
GO

-- Granting permission to the schema
GRANT SELECT ON SCHEMA::HumanResources TO Jack;
GO

-- Deny permisson on one table for testing
DENY SELECT ON HumanResources.Employee TO Jack;
GO

-- Login as Jack and see permissions
EXECUTE AS USER = 'Jack';
GO

-- Jack can executes this
SELECT * FROM HumanResources.Department;
GO

-- And this too
SELECT * FROM HumanResources.JobCandidate;
GO

-- But not this as we have explicity denied permission
SELECT * FROM HumanResources.Employee;
GO

REVERT;
GO

-- Cleaning up
DROP USER Jack;
GO
DROP LOGIN Jack;
GO