114

In terms of SQL injection, I completely understand the necessity to parameterize a string parameter; that's one of the oldest tricks in the book. But when can it be justified to not parameterize an SqlCommand? Are any data types considered "safe" to not parameterize?

For example: I don't consider myself anywhere near an expert in SQL, but I can't think of any cases where it would be potentially vulnerable to SQL injection to accept a bool or an int and just concatenate it right into the query.

Is my assumption correct, or could that potentially leave a huge security vulnerability in my program?

For clarification, this question is tagged which is a strongly-typed language; when I say "parameter," think something like public int Query(int id).

johnnyRose
  • 7,310
  • 17
  • 40
  • 61
  • 15
    You won't get the benefit of cached query plans if don't use parameters, it would need to make a separate query plan for every new combination of inputs you provide. – Scott Chamberlain Sep 18 '15 at 02:08
  • 2
    Do you assume that a check is made to ensure that the provided number that is input is validated to ensure it is indeed a number? – Tarik Sep 18 '15 at 02:13
  • @ScottChamberlain The question is about security not efficiency. – Tarik Sep 18 '15 at 02:14
  • 1
    @Tarik by parameter I mean I'd be concatenating a parameter to a method I'm in. Think, `public int QueryWhatever(int param)`, strongly typed. – johnnyRose Sep 18 '15 at 02:15
  • 1
    Potential security risks that can be fixed in less time then it can take to ask a question on stackoverflow should be considered bugs... especially when the same fix not only improves security and produces cleaner/more maintainable code... it also improves performance. Normally you have to sacrifices at least one of those 3 areas. – Matthew Whited Sep 18 '15 at 02:53
  • 6
    @MatthewWhited How would you know it takes less time? This situation occurs all over the place in certain projects from a current developer and previous developer. If it actually improves security, please post an answer. For clarification, I do agree that it's better to parameterize, obviously. But that isn't really my question. – johnnyRose Sep 18 '15 at 02:57
  • Because you already know the required change. And it's really easy to search for sqlcommand. – Matthew Whited Sep 18 '15 at 03:00
  • As for an answer my response would be the same as the other below. Just parameterize the queries. Posting duplicate answers is pointless. – Matthew Whited Sep 18 '15 at 03:01
  • 6
    @MatthewWhited I wouldn't want you to post a duplicate answer. If you can contribute something which adds value and addresses my original question, though, please do. Regardless, saying "just parameterize the queries" is not answering my initial question. – johnnyRose Sep 18 '15 at 03:04
  • I can't rightly comprehend what manner of thinking would lead someone to asking such a question - unless you're in an environment where someone's charging you for each use of a parameter - it's not like there's some inherent *cost* to using them. – Damien_The_Unbeliever Sep 18 '15 at 09:17
  • 7
    Parameterized queries are primarily used for performance and optimization. SQL injection prevention is a side effect. – Salman A Sep 18 '15 at 12:18
  • 14
    I think the OP has asked a valid question. He's trying to evaluate cost/ benefit of fixing a potential risk. that equation changes with the potential of that risk. if there is zero risk, i wouldn't do it either. He's asked for a technical question about the potential, not for subjective judgment of whether you think its worth his time. The OP is the only one who can make that call. – Sir Swears-a-lot Sep 19 '15 at 09:32
  • 10
    To explain myself: I'm a dba. I appreciate and respect best practice, and in a perfect world all code would be perfect. Sadly in the world I work in, i have more problems to solve than I have time to solve them in. That means prioritization. IMO Rewriting code that already works, is secure and performs to acceptable levels sounds like a luxury. (That I can't afford) – Sir Swears-a-lot Sep 19 '15 at 09:44
  • @Peter it sounds like job security to me. Honestly, though it seems like the vulnerability isn't really there if the functions are properly gated to begin with. If that is not the case, I would suggest locating each instance that is not properly parameterized or implementing proper gating via some sort of global stopgap (likely propagated with regex). otherwise, a wonderful tool to use for locating specific code by about 50 different optional parameters is [Agent Ransack](https://www.mythicsoft.com/agentransack). This beauty sifts through gigabytes of code in seconds. – CSS Sep 23 '15 at 21:41
  • 4
    I see answers that say it is not safe because someone can change culture formats. This way It is like we say someone may change our code! or someone may change server settings. In most cases If anyone can change server settings or can inject code into your application, it seems the whole server is not secure. The person who can inject code in your application or can change server settings, he doesn't need SQL injection attacks! – Reza Aghaei Sep 26 '15 at 23:15
  • 2
    Who can change server settings or who can run such code to change culture? If a person can do it in your server, he doesn't need SQL Injection to destroy data. – Reza Aghaei Sep 26 '15 at 23:24
  • You can at least replace ' with '', it's a little bit safer, to escape the ' character – Yaman Dec 21 '16 at 19:07

11 Answers11

102

I think it's safe... technically, but it's a terrible habit to get into. Do you really want to be writing queries like this?

var sqlCommand = new SqlCommand("SELECT * FROM People WHERE IsAlive = " + isAlive + 
" AND FirstName = @firstName");

sqlCommand.Parameters.AddWithValue("firstName", "Rob");

It also leaves you vulnerable in the situation where a type changes from an integer to a string (Think employee number which, despite its name - may contain letters).

So, we've changed the type of EmployeeNumber from int to string, but forgot to update our sql queries. Oops.

Rob
  • 26,989
  • 16
  • 82
  • 98
  • 24
    Can we stop using `AddWithValue` already? http://blogs.msmvps.com/jcoehoorn/blog/2014/05/12/can-we-stop-using-addwithvalue-already/ – RemarkLima Sep 18 '15 at 06:17
  • 5
    @RemarkLima What's the solution when you're dynamically generating code which maps values to parameters? The blog post fails to address that scenario. Yes, it's a single line to set the SQL type *when it's known*, but when it's not, then you have a problem (or you have to resort to annotating models with that information). – casperOne Sep 18 '15 at 13:00
  • 1
    Then you're stuck with `AddWithValue` unless you have a mapping of database types as part of the dynamic building of the statement. I'd assume that you have a list of target columns, and as part of the dictionary, you could have the types if you wished. Otherwise, just take the performance hit. Ultimately, it's just good information to know I think. – RemarkLima Sep 18 '15 at 13:11
  • 8
    @RemarkLima The point being "Can we stop using `AddWithValue` already?" should really be "if you know the type, then you should refrain from using `AddWithValue`. – casperOne Sep 18 '15 at 14:15
  • 2
    Hey, don't shoot the messenger, I didn't write it ;-) but the point remains, and if built into your designs from the start, there's no reason you shouldn't know the type. Best practice and all that jazz :-) – RemarkLima Sep 18 '15 at 14:20
  • @casperOne - And coincidentally enough the blog author has also posted an answer on this very question. Seems feedback on the title would be better addressed there. – Martin Smith Sep 19 '15 at 16:48
  • I see your problem - AddWithValue is shorter & more concise, so of course people are going to use it. AddParameter(name, type, value) would be great, and rename the existing one to AddParameterWithInferredType(name, value). – Riking Sep 19 '15 at 23:01
  • 1
    All good points on .AddWithValue(), but considering all of the code I've seen, for 80% of the programmers out there, just using parameters in the first place is a huge leap. – Dave Markle Sep 23 '15 at 13:47
  • @RemarkLima Dictionary mapping of columns and types is something that could eliminate a lot of hassle for dynamically generated sqlcommands, but I would expect 2d enums to have better performance in most cases. I realize I'm still somewhat of a novice with C#, but that has been my experience, in C# as well as with Java. – CSS Sep 23 '15 at 22:17
  • 1
    This is just wrong. See my answer for example on how you can still create SQL injection with `DateTime` or `int`. – Kaspars Ozols Sep 26 '15 at 21:28
  • 1
    @KasparsOzols Which part is 'just wrong'? Also, I'd argue your answer is not an injection.. once you have access to the box (modifiying the culture), there's nothing you can do code-wise to prevent intrusions – Rob Oct 12 '15 at 10:19
  • Part were you say that it is **technically safe** is just wrong. I have provided sample were you can **technically** create injection. Discussion on who and under what circumstances might use this **technical** flaw is beyond this topic. – Kaspars Ozols Oct 12 '15 at 12:44
  • 1
    @KasparsOzols It's technically safe, in that your code is safe as long as the server is not compromised. The only 'unsafe' part is as I described. If we tread into the territory of the *server* being compromised, then no code is safe, whether it be server or desktop (by that point, you have access to the DB credentials, anyway). While your answer shows an example of breaking an application, it is by no means SQL injection, by any stretch of the imagination. – Rob Oct 12 '15 at 14:10
  • @KasparsOzols To expand upon my point, there is *nothing* a user can input into the website/application that will break the query without having access to the server (and at that point, why bother?). If you could show me an in-built culture that did allow an external user, without changing any OS settings, to break the query, then I would agree with you. I still stand by my answer that it is technically safe, but not advised. – Rob Oct 12 '15 at 14:12
66

When using a strongly-typed platform on a computer you control (like a web server), you can prevent code injection for queries with only bool, DateTime, or int (and other numeric) values. What is a concern are performance issues caused by forcing sql server to re-compile every query, and by preventing it from getting good statistics on what queries are run with what frequency (which hurts cache management).

But that "on a computer you control" part is important, because otherwise a user can change the behavior used by the system for generating strings from those values to include arbitrary text.

I also like to think long-term. What happens when today's old-and-busted strongly-typed code base gets ported via automatic translation to the new-hotness dynamic language, and you suddenly lose the type checking, but don't have all the right unit tests yet for the dynamic code?

Really, there's no good reason not to use query parameters for these values. It's the right way to go about this. Go ahead and hard-code values into the sql string when they really are constants, but otherwise, why not just use a parameter? It's not like it's hard.

Ultimately, I wouldn't call this a bug, per se, but I would call it a smell: something that falls just short of a bug by itself, but is a strong indication that bugs are nearby, or will be eventually. Good code avoids leaving smells, and any good static analysis tool will flag this.

I'll add that this is not, unfortunately, the kind of argument you can win straight up. It sounds like a situation where being "right" is no longer enough, and stepping on your co-workers toes to fix this issue on your own isn't likely to promote good team dynamics; it could ultimately hurt more than it helps. A better approach in this case may be to promote the use of a static analysis tool. That would give legitimacy and credibility to efforts aimed and going back and fixing existing code.

Joel Coehoorn
  • 399,467
  • 113
  • 570
  • 794
  • 1
    It definitely isn't a challenge to do it parameterized. My question arose because a coworker wrote a bunch of queries concatenating integer values, and I was wondering whether it was a waste of my time to go through and fix all of them. – johnnyRose Sep 18 '15 at 02:18
  • Don't do it yourself... at least not right away. File bugs against them. You do have bug tracking, right? – Joel Coehoorn Sep 18 '15 at 02:18
  • 2
    I think the question "Is it a bug" is what my question boils down to. – johnnyRose Sep 18 '15 at 02:19
  • 8
    It's a "smell": something that falls short of a bug by itself, but indicates that bugs are likely nearby. Good code tries to eliminate smells. Any good static analysis tool would definitely flag it. – Joel Coehoorn Sep 18 '15 at 02:20
  • Note that you can have maximum 2100 parameters in your query in SQL Server. There might be complex queries which require more than 2100 of parameters (for example running complex queries on EAV data model, or other). – Tom Pažourek Sep 22 '15 at 13:45
  • 1
    I like the term "smell". I would have used something like "larva" instead, where it's not quite a bug yet, but future updates could catch it to a maggot that will eat at your backend until you crush it or fumigate. You certainly don't want the potential for necrotic code to crop up in a production environment, and having something that wasn't developed with a certain amount of finesse could certainly cause such to be present, as in this case. – CSS Sep 23 '15 at 22:22
  • 2
    This is just wrong. See my answer for example on how you can still create SQL injection with `DateTime` or `int` – Kaspars Ozols Sep 26 '15 at 21:42
  • @KasparsOzols I cleaned up the first sentence for that case. – Joel Coehoorn Oct 07 '15 at 16:24
53

In some cases, it IS possible to perform SQL injection attack with non-parametrized (concatenated) variables other than string values - see this article by Jon: http://codeblog.jonskeet.uk/2014/08/08/the-bobbytables-culture/ .

Thing is that when ToString is called, some custom culture provider can transform a non-string parameter into its string representation which injects some SQL into the query.

Maciek
  • 1,696
  • 12
  • 19
53

This is not safe even for non-string types. Always use parameters. Period.

Consider following code example:

var utcNow = DateTime.UtcNow;
var sqlCommand = new SqlCommand("SELECT * FROM People WHERE created_on <= '" + utcNow + "'");

At the first glance code looks safe, but everything changes if you make some changes in Windows Regional Settings and add injection in short date format:

Datetime Injection

Now resulting command text looks like this:

SELECT * FROM People WHERE created_on <= '26.09.2015' OR '1'<>' 21:21:43'

The same can be done for int type as user can define custom negative sign which can be easily changed into SQL injection.

One could argue that invariant culture should be used instead of current culture, but I have seen string concatenations like this so many times and it is quite easy to miss when concatenating strings with objects using +.

Kaspars Ozols
  • 6,967
  • 1
  • 20
  • 33
  • 10
    Who can change server settings? If a person can do it in your server, he doesn't need SQL Injection to destroy data. – Reza Aghaei Sep 26 '15 at 23:18
  • 5
    This is the best answer, it shows one way that validates the OPs concern this is a bug/security flaw. Performance and future proofing aside concatenating datetimes in SQL for example isn't just a *smell* or *tech debt*. @RezaAghaei the question never mentioned Server-Side, it could be a Windows App with SQLExpress - either way that's not criteria for the question. Anyone could say but who has access to the server settings to rebut this excellent answer, just as anyone could say what about shared server hosting or a Y2K bug. I do agree with you the server being locked - its just not a prereq. – Jeremy Thompson Sep 27 '15 at 03:00
  • 2
    Could you provide an example of what you were saying about the `int` type? – johnnyRose Sep 27 '15 at 16:35
  • 1
    I know it's been a few weeks since you answered this, but would it be possible for you to edit your post and add an example of how you can define a custom negative sign? – johnnyRose Oct 15 '15 at 20:46
  • @RezaAghaei - might there be a situation where get culture from user's browser, to show in user's expected format? – ToolmakerSteve Aug 27 '20 at 20:18
  • FWIW: Well-written code preparing query for a DB shouldn't be reliant on server's culture anyway. That's fraught with problems if move to a different server, with a different culture. DB values should use *invariant culture* for consistency. DateTime in particular should probably always be converted to a standard UTC representation (then stored as a DateTime column type). – ToolmakerSteve Aug 27 '20 at 21:09
23
"SELECT * FROM Table1 WHERE Id=" + intVariable.ToString()

Security

It is OK.
Attackers can not inject anything in your typed int variable.

Performance

Not OK.

It's better to use parameters, so the query will be compiled once and cached for next usage. Next time even with different parameter values, query is cached and doesn't need to compile in database server.

Coding Style

Poor practice.

  • Parameters are more readable
  • Maybe it makes you get used to queries without parameters, then maybe you made a mistake once and use a string value this way and then you probably should say goodbye to your data. Bad habit!

"SELECT * FROM Product WHERE Id=" + TextBox1.Text

Although it is not your question, but maybe useful for future readers:

Security

Disaster!

Even when the Id field is an integer, your query may be subject to SQL Injection. Suppose you have a query in your application "SELECT * FROM Table1 WHERE Id=" + TextBox1.Text. An attacker can insert into text box 1; DELETE Table1 and the query will be:

SELECT * FROM Table1 WHERE Id=1; DELETE Table1

If you don't want to use a parametrized query here, you should use typed values:

string.Format("SELECT * FROM Table1 WHERE Id={0}", int.Parse(TextBox1.Text))

Your Question

My question arose because a coworker wrote a bunch of queries concatenating integer values, and I was wondering whether it was a waste of my time to go through and fix all of them.

I think changing those codes is not waste of time. Indeed change is recommended!

If your coworker uses int variables it has no security risk, but I think changing those codes is not waste of time and indeed changing those codes is recommended. It makes code more readable, more maintainable, and makes execution faster.

Joel Coehoorn
  • 399,467
  • 113
  • 570
  • 794
Reza Aghaei
  • 120,393
  • 18
  • 203
  • 398
  • Even the first option isn't completely okay for security. The behavior of `.ToString()` is determined by an operating system configuration item that is easy to change to include arbitrary text. – Joel Coehoorn Sep 20 '18 at 13:42
  • @JoelCoehoorn - if attacker has access to operating system configuration, hasn't he already penetrated your security? [though the best security is redundant security, so I agree there is no reason to code in a way that has this risk] – ToolmakerSteve Aug 27 '20 at 20:19
  • 1
    @ToolmakerSteve For some applications, this might be determined by the end user's client computer. – Joel Coehoorn Aug 27 '20 at 21:41
  • @JoelCoehoorn - excellent point. Even though database values themselves should always be *invariant culture*; only display to user would use a culture. So the safe design is to convert user's text into an `int` variable, then use whatever language feature is available to convert that to an invariant string. **But I see that for "int", this might not be thought of:** I might myself have code that "assumes" `ToString` doesn't need to specify invariant culture, if it is an int variable. – ToolmakerSteve Aug 27 '20 at 21:47
18

There are actually two questions in one. And question from the title has very little to do with concerns expressed by the OP in the comments afterwards.

Although I realize that for the OP it is their particular case that matters, for the readers coming from Google, it is important to answer to the more general question, that can be phrased as "is concatenation as safe as prepared statements if I made sure that every literal I am concatenating is safe?". So, I would like to concentrate on this latter one. And the answer is

Definitely NO.

The explanation is not that direct as most readers would like, but I'll try my best.

I have been pondering on the matter for a while, resulting in the article (though based on the PHP environment) where I tried to sum everything up. It occurred to me that the question of protection from SQL injection is often eludes toward some related but narrower topics, like string escaping, type casting and such. Although some of the measures can be considered safe when taken by themselves, there is no system, nor a simple rule to follow. Which makes it very slippery ground, putting too much on the developer's attention and experience.

The question of SQL injection cannot be simplified to a matter of some particular syntax issue. It is wider than average developer used to think. It's a methodological question as well. It is not only "Which particular formatting we have to apply", but "How it have to be done" as well.

(From this point of view, an article from Jon Skeet cited in the other answer is doing rather bad than good, as it is again nitpicking on some edge case, concentrating on a particular syntax issue and failing to address the problem at whole.)

When you're trying to address the question of protection not as whole but as a set of different syntax issues, you're facing multitude of problems.

  • the list of possible formatting choices is really huge. Means one can easily overlook some. Or confuse them (by using string escaping for identifier for example).
  • Concatenation means that all protection measures have to be done by the programmer, not program. This issue alone leads to several consequences:
    • such a formatting is manual. Manual means extremely error prone. One could simply forget to apply.
    • moreover, there is a temptation to move formatting procedures into some centralized function, messing things even more, and spoiling data that is not going to database.
  • when more than one developers involved, problems multiply by a factor of ten.
  • when concatenation is used, one cannot tell a potentially dangerous query at glance: they all potentially dangerous!

Unlike that mess, prepared statements are indeed The Holy Grail:

  • it can be expressed in the form of one simple rule that is easy to follow.
  • it is essentially undetacheable measure, means the developer cannot interfere, and, willingly or unwillingly, spoil the process.
  • protection from injection is really only a side effect of the prepared statements, which real purpose is to produce syntactically correct statement. And a syntactically correct statement is 100% injection proof. Yet we need our syntax to be correct despite of any injection possibility.
  • if used all the way around, it protects the application regardless of the developer's experience. Say, there is a thing called second order injection. And a very strong delusion that reads "in order to protect, Escape All User Supplied Input". Combined together, they lead to injection, if a developer takes the liberty to decide, what needs to be protected and what not.

(Thinking further, I discovered that current set of placeholders is not enough for the real life needs and have to be extended, both for the complex data structures, like arrays, and even SQL keywords or identifiers, which have to be sometimes added to the query dynamically too, but a developer is left unarmed for such a case, and forced to fall back to string concatenation but that's a matter of another question).

Interestingly, this question's controversy is provoked by the very controversial nature of Stack Overflow. The site's idea is to make use of particular questions from users who ask directly to achieve the goal of having a database of general purpose answers suitable for users who come from search. The idea is not bad per se, but it fails in a situation like this: when a user asks a very narrow question, particularly to get an argument in a dispute with a colleague (or to decide if it worth to refactor the code). While most of experienced participants are trying to write an answer, keeping in mind the mission of Stack Overflow at whole, making their answer good for as many readers as possible, not the OP only.

Your Common Sense
  • 156,878
  • 40
  • 214
  • 345
  • 10
    Not answering the question – edc65 Sep 19 '15 at 10:06
  • Most databases detect already used, parameterized queries by SQL string equality, so the old prepare-and-use-handle method seems outdated for me. These handles can be used only within a certain scope and require coding to keep track of the handle. Parameterized queries should, in my opinion, be used directly, so that query plans can be reused without handle tracking and even across different applications. – Erik Hart Sep 19 '15 at 10:10
15

Let's not just think about security or type-safe considerations.

The reason you use parametrized queries is to improve performance at the database level. From a database perspective, a parametrized query is one query in the SQL buffer (to use Oracle's terminology although I imagine all databases have a similar concept internally). So, the database can hold a certain amount of queries in memory, prepared and ready to execute. These queries do not need to be parsed and will be quicker. Frequently run queries will usually be in the buffer and will not need parsing every time they are used.

UNLESS

Somebody doesn't use parametrized queries. In this case, the buffer gets continually flushed through by a stream of nearly identical queries each of which needs to be parsed and run by the database engine and performance suffers all-round as even frequently run queries end up being re-parsed many times a day. I have tuned databases for a living and this has been one of the biggest sources of low-hanging fruit.

NOW

To answer your question, IF your query has a small number of distinct numeric values, you will probably not be causing issues and may in fact improve performance infinitesimally. IF however there are potentially hundreds of values and the query gets called a lot, you are going to affect the performance of your system so don't do it.

Yes you can increase the SQL buffer but it's always ultimately at the expense of other more critical uses for memory like caching Indexes or Data. Moral, use parametrized queries pretty religiously so you can optimize your database and use more server memory for the stuff that matters...

mcottle
  • 503
  • 1
  • 3
  • 10
8

To add some info to Maciek answer:

It is easy to alter the culture info of a .NET third party app by calling the main-function of the assembly by reflection:

using System;
using System.Globalization;
using System.Reflection;
using System.Threading;

namespace ConsoleApplication2
{
  class Program
  {
    static void Main(string[] args)
    {
      Assembly asm = Assembly.LoadFile(@"C:\BobbysApp.exe");
      MethodInfo mi = asm.GetType("Test").GetMethod("Main");
      mi.Invoke(null, null);
      Console.ReadLine();
    }

    static Program()
    {
      InstallBobbyTablesCulture();
    }

    static void InstallBobbyTablesCulture()
    {
      CultureInfo bobby = (CultureInfo)CultureInfo.InvariantCulture.Clone();
      bobby.DateTimeFormat.ShortDatePattern = @"yyyy-MM-dd'' OR ' '=''";
      bobby.DateTimeFormat.LongTimePattern = "";
      bobby.NumberFormat.NegativeSign = "1 OR 1=1 OR 1=";
      Thread.CurrentThread.CurrentCulture = bobby;
    }
  }
}

This only works if the Main function of BobbysApp is public. If Main is not public, there might be other public functions you might call.

user1027167
  • 4,320
  • 6
  • 33
  • 40
  • 1
    You don't even have to do it by code. You can add injection directly in Windows Regional Settings. See my answer. – Kaspars Ozols Sep 26 '15 at 21:39
  • 3
    Who can change server settings or who can rub such code in server? If a person can do it in your server, he doesn't need SQL Injection to destroy data. – Reza Aghaei Sep 26 '15 at 23:19
7

In my opinion if you can guarantee that the parameter you working with will never contain a string it is safe but I would not do it in any case. Also, you will see a slight performance drop due to the fact that you are performing concatenation. The question I would ask you is why don't you want to use parameters?

Cahit Gungor
  • 1,477
  • 23
  • 30
Max
  • 458
  • 3
  • 7
  • 1
    It's not that I don't want to use parameters, I'm using parameters. A coworker wrote code like this which I modified to be parameterized today, which made me think of the question. – johnnyRose Sep 18 '15 at 02:12
  • Ok. Great. It is a best practices to use parameters. This way you don't have to worry about things like sql injection. Also if you are building a dynamic queries you can also use parameters not matter how complex your queries is. Simply use @1...@n style when building them. And append them to parameters collection with desired value. – Max Sep 18 '15 at 02:18
  • @johnyRose There is one more point to use parameters: programs is evolving and changes. You can use concatenation only for string but that does not guarantee that someone implement refactoring that change some parameter type and that changes can introduce SQL Injection vulnerability. – lerthe61 Dec 26 '16 at 11:16
3

It is ok but never safe.. and the security always depend on the inputs, for example if the input object is TextBox, the attackers can do something tricky since the textbox can accept string, so you have to put some kind of validation/conversion to be able prevent users the wrong input. But the thing is, it is not safe. As simply as that.

japzdivino
  • 1,736
  • 3
  • 17
  • 25
  • That's a string though. I'm talking about other data types, like integers, booleans, or datetimes. – johnnyRose Sep 23 '15 at 12:14
  • @johnnyRose Yup , I've seen a very nice example above that you mark as answered by Kaspards.. and great answer as he uses datetime datatype as an example which is uncommon. :) I hope you already convinced that it is not safe and better to use parameter in any kind of datatypes – japzdivino Oct 05 '15 at 02:42
  • I never really had any doubt it was safer to use parameters. My question referred to strongly-typed implementations. – johnnyRose Oct 05 '15 at 02:45
  • Yup.. i agree. and that is also great question that can help future readers :) – japzdivino Oct 05 '15 at 02:48
-3

No you can get an SQL injection attack that way. I have written an old article in Turkish which shows how here. Article example in PHP and MySQL but concept works same in C# and SQL Server.

Basically you attack following way. Lets consider you have a page which shows information according to integer id value. You do not parametrized this in value, like below.

http://localhost/sqlEnjeksiyon//instructors.aspx?id=24

Okay, I assume you are using MySQL and I attack following way.

http://localhost/sqlEnjeksiyon//instructors.aspx?id=ASCII((SELECT%20DATABASE()))

Note that here injected value is not string. We are changing char value to int using ASCII function. You can accomplish same thing in SQL Server using "CAST(YourVarcharCol AS INT)".

After that I use length and substring functions to find about your database name.

http://localhost/sqlEnjeksiyon//instructors.aspx?id=LEN((SELECT%20DATABASE()))

http://localhost/sqlEnjeksiyon//instructors.aspx?id=ASCII(SUBSTR(SELECT%20DATABASE(),1,1))

Then using database name, you start to get table names in database.

http://localhost/sqlEnjeksiyon//instructors.aspx?id=ASCII(SUBSTR((SELECT table_name FROM INFORMATION_SCHEMA.TABLES LIMIT 1),1,1))

Of course you have to automate this process, since you only get ONE character per query. But you can easily automate it. My article shows one example in watir. Using only one page and not parameterized ID value. I can learn every table name in your database. After that I can look for important tables. It will take time but it is doable.

Atilla Ozgur
  • 14,339
  • 3
  • 49
  • 69
  • 2
    My question refers to a strongly typed language. While your explanation is great for languages with flexible typing, the injected value is still a string. – johnnyRose Sep 26 '15 at 18:11
  • No injected value is integer. You get char and change it to integer using ASCII MySQL function. You do same thing in SQL Server using CAST(YourCharValue AS INT) – Atilla Ozgur Sep 26 '15 at 18:42
  • I meant something like this: `public void QuerySomething(int id) { // this will only accept an integer }` – johnnyRose Sep 26 '15 at 18:44
  • No, this is *not* an example of "injected value is integer". You assume the implementing code executes a query containing `SELECT%20DATABASE()`, and *then* casts that to int. That would be very sloppy coding, and is not what is being discussed, IMHO. Correct example of php code casting input to int would be: `$id_value = 'ASCII((SELECT%20DATABASE())'; $param = (int)$id_value; $query = ... id={$param};` Observe that the arbitrary input string gets cast to an int *before* it reaches the query. Such "casting parameter to int" can be done in any language, AFAIK, before send query to DB. – ToolmakerSteve Aug 27 '20 at 20:43
  • ... granted, URL get parameter strings are especially prone to injection. It is also necessary to "whitelist" the "keys". Code must explicitly look for valid keys. Here, I assume code that looks for key "id" in the get parameter list. Code that just copies the entire string after the "?" into the query is of course completely insecure. – ToolmakerSteve Aug 27 '20 at 20:52