What are security problems of this SP - tsql

I have a query that returns value of a field sent through parameter :
#Field nvarchar(50),
#ID int
...
execute('SELECT ' + #Field + ' from SampleTable where (ID=' + #ID + ');');
I'm doing this to have one SP instead of several SP's with the same structure .
Now I'm not sure is this safe or not ?

You should use sp_executesql and quotename to be safe.
declare #SQL nvarchar(max)
set #SQL = 'select '+quotename(#Field)+' from SampleTable where ID = #ID'
exec sp_executesql #SQL, N'#ID int', #ID

The query is not safe.
The client using the web system can drop your entire database using a SQL injection attack
by passing ' ; DROP DATABASE dbname -- instead of id.
In case you plan to use the above query use a parametrized SQL stored procedure to prevent SQL injection attacks.
More details below :-
How to protect from SQL injection attacks in ASP .NET

Related

Passing table name in sql stored procedure

Is it possible to pass the table name as input parameter to the stored procedure?
For example:
create procedure test
#tablename char(10)
as
begin
select * from #tablename
end
go
I know this does not work. So what is the best way if I want to pass the table name into the stored procedure?
Many thanks
The safest way to do this is via a view.
Create a view which unions all the tables you may wish to access (and which must all have the same column structure), and prefix the rows with the table name.
CREATE VIEW MultiTable
AS
SELECT 'table1' AS TableName, * FROM table1
UNION ALL
SELECT 'table2' AS TableName, * FROM table2
UNION ALL
SELECT 'table3' AS TableName, * FROM table3
Your stored procedure can now filter on the table name:
CREATE PROCEDURE test
#TableName varchar(100)
AS
SELECT * FROM MultiTable WHERE TableName = #TableName
This is safer than using dynamic SQL creation and execution.
You would need to use dynamic SQL, but you need to be aware of potential sql injection risks you open yourself up to as if #tablename contained something dodgy, you could end up in a world of pain.
e.g.
-- basic check to see if a table with this name exists
IF NOT EXISTS(SELECT * FROM sys.tables WHERE name = #tablename)
RETURN
DECLARE #sql NVARCHAR(100)
SET #sql = 'SELECT * FROM ' + QUOTENAME(#tablename)
EXECUTE(#sql)
You need to be very careful with this approach, make sure you don't open up a can of security worms.
My other concern is that you may be trying to make generic data access sprocs which is usually a bad idea. Obviously I don't know your use case.
DECLARE #Name VARCHAR(50)
SET #Name='Company'
EXEC('SELECT * from ' + #Name )
use this way to get record from database.

How to convert SQL Server 2008 R2 database to SQL Server 2012?

I installed SQL Server 2012, and attached a database originally generated by SQL Server 2008 R2.
Everything appeared to work perfectly, with one problem: merges dropped from 1000 per second to 10 per second (a 100x slowdown).
I'm surmising that its because I am accessing a SQL Server 2008 R2 database from SQL Server 2012. Is there some way to convert the database to SQL Server 2012 format? Or is there something else thats going on that might explain the 100x slowdown in performance?
Please make sure that you set the compatibility mode of the database to 110, and update statistics.
ALTER DATABASE MyDatabase SET COMPATIBILITY_LEVEL = 110;
DECLARE #sql NVARCHAR(MAX) = N'';
SELECT #sql += CHAR(13) + CHAR(10) + 'UPDATE STATISTICS '
+ QUOTENAME(SCHEMA_NAME(schema_id))
+ '.' + QUOTENAME(name) + ' WITH FULLSCAN;'
FROM sys.tables;
PRINT #sql;
--EXEC sp_executesql #sql;
When I ran the SQL in the answer the nvarchar overflowed. The problem is when your database has too many tables the SQL is too long for an nvarchar. My database had enough tables to overflow a varchar (twice as long as a nvarchar). So I edited the SQL to loop through each table and execute separate statements. This way you wont miss updating the stats on any of your tables.
ALTER DATABASE MyDatabase SET COMPATIBILITY_LEVEL = 110;
DECLARE #SQL NVARCHAR(MAX) = N'';
Declare #Tables table
([Schema] nvarchar(50)
,[TableName] nvarchar(100))
Insert into #Tables
Select QUOTENAME(SCHEMA_NAME(schema_id)),QUOTENAME(name)
FROM sys.tables;
Declare #Schema nvarchar(50), #TableName nvarchar(100)
While Exists(Select * From #Tables)
Begin
Select Top 1 #Schema = [Schema], #TableName = [TableName] From #Tables
Set #SQL = 'UPDATE STATISTICS ' + #Schema + '.' + #TableName + ' WITH FULLSCAN;'
Begin Try
EXEC SP_ExecuteSql #SQLToExecute = #SQL
Print 'Completed: ' + #SQL
End Try
Begin Catch
DECLARE #ErrMsg nvarchar(4000)
SELECT #ErrMsg = SubString(ERROR_MESSAGE(),0,900)
Select GetDate(), 'Failed updating stats on ' + #Schema + ' ' + #TableName + '. Error: '+#ErrMsg
End Catch
Delete From #Tables Where [Schema] = #Schema and [TableName] = #TableName
End
Updating the Stats is must when you detach and attach database. Otherwise query planner cannot generate efficient execution plan and end-up with long execution time. This is what I noticed.
To upgrade a database file to use LocalDB:
1.In Server Explorer, choose the Connect to Database button.
2.In the Add Connection dialog box, specify the following information:
Data Source: Microsoft SQL Server (SqlClient)
Server Name: (LocalDB)\v11.0
Attach a database file: Path, where Path is the physical path of the primary .mdf file.
Logical Name: Name, where Name is the name that you want to use with the file.
Choose the OK button.
When prompted, choose the Yes button to upgrade the file.
Is this on the right track:
http://msdn.microsoft.com/en-us/library/ms189625.aspx
USE master;
GO
CREATE DATABASE MyDatabase
ON (FILENAME = 'C:\MySQLServer\MyDatabase.mdf'),
(FILENAME = 'C:\MySQLServer\Database.ldf')
FOR ATTACH;
GO

Does EXECUTE AS protect against SQL Injection?

I have a situation where I need to do this
CREATE PROCEDURE search_sp #condition varchar(8000) AS
SELECT * FROM tbl WHERE #condition
If I add a user to the database that only has the 'db_datareader' role and then use execute as to switch context to that user for the purposes of running the select statement, would this then protect me from SQL injection?
e.g.
DECLARE #cookie varbinary(100);
EXECUTE AS USER = 'restricted__user' WITH COOKIE INTO #cookie;
DECLARE #SQL AS NVARCHAR(MAX)
SET #SQL= 'SELECT * FROM tbl WHERE ' + #condition
EXEC sp_executesql #SQL
REVERT WITH COOKIE = #cookie;
No, it won't. This will limit the queries that could be run if injected if the "EXECUTE AS USER" is even evaluated. It won't stop something like foo' or 1 = 1; /*... which can be a case where "EXECUTE AS USER" is never reached. Properly handling the input is required.
What happens when I pass "1=1" as condition?
Now you send back all rows in 'tbl'. If table is, say, users, I now have all user names and all passwords (hopefully they're hashed and salted...).

How can I call sp_executesql stored procedure in entity framework?

How can I call sp_executesql stored procedure in entity framework?
I need to dynamically execute formulas stored in SQL Server table column using Select Statement. I tried ENTITY SQL but it does not work.
Use ObjectContext.ExecuteStoreCommand (requires EF 4).
if i understood correctly try this
CREATE PROCEDURE sp_calculatesalary(#EmployeeId as int)
begin
declare #dynsql varchar(500)=' Salary,Username from employee where EmployeeId=#empID'
exec sp_executesql #dynsql,'#empID int',#empID=#EmployeeID
SELECT 1 as salary,2 as username
end
it solves stored procedures mapping problem

T-SQL A problem while passing CSV string into a stored procedure

I have that procedure which returns rows associated by ID with passed argument, i.e 1,5,7,9
ALTER PROCEDURE [dbo].[get_data]
#MyCodes as varchar(max) = ''
AS
BEGIN
DECLARE #query as nvarchar(max)
set #query = 'SELECT name FROM user WHERE id IN (#p_MyCodes)'
exec SP_EXECUTESQL #query,
N'#p_MyCodes varchar(max)',
#p_MyCodes = #MyCodes
END
That procedure generates an error : Error converting data type varchar to numeric. when I pass as an argument e.g. 3,7,5
What's wrong ?
I don't think this is going to accomplish what you are expecting it to. The error you are getting is because it can't convert the string '3,7,5' to a number (note that it is NOT trying to parse out your individual values).
Two ways to get what you want:
1) Create a table value function that takes a CSV string and returns the results (I'm sure there are many on the web; Here's a related question: Split function equivalent in T-SQL?). This is nice because you can get rid of the SP_EXECUTESQL sproc call entirely; Your query becomes:
SELECT name FROM user where id IN (SELECT value FROM dbo.f_Split(#p_MyCodes))
2) Change your set to something like:
set #query = 'SELECT name FROM user WHERE id in (' + #p_MyCodes + ')'
I don't recommend #2, it offers a SQL injection hole.
You cannot pass the ID list as parameter. You could create the SQL statement by concatenating:
set #query = 'SELECT name FROM user WHERE id IN (' + #MyCodes + ')'
exec SP_EXECUTESQL #query
Though, this disables any kind of execution plan re-usage and enables SQL injection
A better solution would be to split the list into a temp table (or table variable) and using a JOIN. Last year, I wrote a blog post about different ways to split strings in T-SQL:
http://florianreischl.blogspot.com/2009/09/high-performance-string-split-functions.html
You can't use a comma separated string with the in operator, you have to use the actual values. So, you either have to split the string up and put the values in a temporary table, or concatenate the string into the query:
set #query = 'SELECT name FROM user WHERE id IN (' + #p_MyCodes + ')'
Note that this opens up a potential security hole for SQL injection. You should not do this if you don't have full control over where the string comes from.