0

I have a process that supplies untrusted data to the database, so I've been trying to parameterize my queries.

When I use INSERT I can use something like the following, by way of example:

INSERT INTO [dbo].[Names]
           ([First_Name]
           ,[Last_Name])
VALUES ("Geoff", "Bridges")

I am, however, attempting to replicate that type of procedure using UPDATE.

UPDATE [dbo].[Names] SET 
    Last_Name,
    Last_Name
WHERE ID = 5
VALUES("Geoff", "Bridge");

I'm not quite sure how to approach this problem. Thanks for any assistance.

10
  • 2
    So having read the documentation what parts of it didn't you understand? And secondly, from where are you calling this T-SQL? And if you are just substituting the {} with your own values, thats not parameterisation - thats string concatenation - you use actual parameters (@ParamName) for parameterisation Commented May 4, 2021 at 2:14
  • 3
    your UPDATE query syntax is wrong. Please refer to documentation Commented May 4, 2021 at 2:15
  • 2
    The docs show plenty of examples of using constant values e.g. UPDATE DimEmployee SET FirstName = 'Gail' WHERE EmployeeKey = 500; . Or use an update with a join in the same way as your previous question about using values with delete. Commented May 4, 2021 at 2:43
  • 1
    There is an Examples section in the documentation Commented May 4, 2021 at 2:49
  • 1
    But if you show how you plan to call this from code you may well find the correct solution is different again. Commented May 4, 2021 at 2:51

1 Answer 1

1

SQL Parameterization can be achieved through different techniques depending on the programmatic context, from a pure SQL point of view, we simply need to declare the values as variables, then we can use those variables within your normal SQL commands.

DECLARE @firstName VARCHAR(50) = 'Geoff';
DECLARE @lastName VARCHAR(50) = 'Bridges';
DECLARE @recordId INT = 5;

INSERT INTO [dbo].[Names]
           ([First_Name]
           ,[Last_Name])
VALUES (@firstName, @lastName)

Updating the same record, when the ID is known to be 5:

UPDATE [dbo].[Names] SET 
    Last_Name = @lastName,
    First_Name = @firstName
WHERE ID = @recordId 

In most cases the declaration section is managed from your application logic, and not usually expressed explicitly in SQL.


UPDATE

After reading through the extended comments, its clear we need more information here. If you are constructing dynamic SQL scripts from your application logic, using declared parameters not going to provide much safety on its own, you will still need to sanitize the input if you wish to guard against SQL Injection attacks.

Most higher languages like C# will have a built in mechanism to sanitize and validate SQL parameter input, yes, ultimately this results at some level with the parameters being serialised into strings and injected into a SQL script, these mechanisms will prevent your script from executing if the type and or length validation fails.

The following is an example of an injection attack that will break even if you use parameterised syntax where you are only substituting the values:

User sets their first name as: hello'; DROP TABLE Names;SELECT '

Now, inject that into your script:

DECLARE @firstName VARCHAR(50) = 'hello'; DROP TABLE Names; SELECT '';
...

Whilst that may not result in the table being dropped, it is obvious that all sorts of commands could be executed in this way. I don't want to give you any specific malicious ideas, but it's common for attackers to grant permissions to external users or to otherwise exploit access to the underlying system, perhaps even to execute custom scripts directly from the command line.

  • this is one reason why you should NEVER use SA logins!

However, if the application were to sanitize the input data first, either through a framework, 3rd party library or manually, it should have escaped the name value and executed something like this instead:

DECLARE @firstName VARCHAR(50) = 'hello''; DROP TABLE Names; SELECT''';
...

Which would be a silly name for a user, but at least the table wasn't dropped.


Alternatively, if your request is to specifically use the VALUES Table Constructor syntax for the update, then that is possible too, though not advised...

UPDATE [dbo].[Names] SET 
    Last_Name = lName,
    First_Name = fName
FROM [dbo].[Names]
INNER JOIN 
(VALUES (@firstName, @lastName, @recordId)) as V(fName, lName, recId) ON V.recId = Names.ID
Sign up to request clarification or add additional context in comments.

5 Comments

Now that is a great reply. Thank you. What do you mean by SA logins? I'll have to do a bit of hunting on the sanitising - but the options are not too good on the platform I'm on, a combination of old production database versions and trying to sanitise SQL via javascript.
As a general rule, you should NOT compose SQL from the browser, regardless of what you do to sanitize input, if your solution allows the browser to submit a SQL expression directly to the database, then your whole database is exposed. SA = 'Server Administrator' login, which has the highest privelidges. If you do not have a backend API, then please make sure that the user account that your runtime uses from the browser is locked down so that it cannot execute DDL statements
Chris, composing SQL from the browser is not the inference here. Think of Node-Red like having something available in Node, .Net Core, etc. Request comes in, http server middleware handles it, passes of request to SQL server. In this case Node-Red has the query in it that I need to run, and I'm attempting to load parameters from the http post request into it. For that part of the conversation I abstracted away that detail because I could be using a number of frameworks and have largely the same issue with creating the query. Thanks for clarifying what you meant by SA.
This is an open question to ponder, please do not respond here... But if what you say is true @anakaine then I wonder why are aren't you using some sort of ORM framework, why are you manually composing these SQL statements, why would you try to support posting untrusted data directly into the database anyway... I wish you well, but this does not sound like good enterprise application design.
Every case has it's reasons. This is no exception. ORM is certainly a consideration, but it's not an option in this case, and thanks to me usually working at higher levels of abstraction I thus struggle with some of the lower bits being discussed here. I appreciate the note on it not being enterprise best practice, and I agree. Sometimes we have to work with what we have until we can affect change, however.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.