I am wondering how safe the fromSqlRaw method is. I am doing the following in my code, where the person id is a parameter from the method itself:
string sql = String.Format("SELECT * FROM [users].[user] WHERE Id LIKE {0}", id)
var list = this.context.Person.FromSqlRaw<Person>(sql).ToList();
Is this code safe to SQL injection? And is there other security vulnerabilities that I should know of when using this?
Use proper parametrization for your input.
After clarifications in comments, it seems that your parameter is user-input string, this is a wide door opened for injection attacks.
Usually, you can create a SqlCommand, and provide some SqlParameter in it.
In EFCore, FromSqlRaw and FromSqlInterpolated (in 3.0, replacement for FromSql in EFCore < 3.0) allow you to shorten this syntax, see the documentation.
string sql = "SELECT * FROM [users].[user] WHERE Id LIKE {0}"
var list = this.context.Person.FromSqlRaw<Person>(sql, "42")
Note that this looks very similar to what you did in the question... But the difference is clearly emphasized in the documentation:
Warning
Always use parameterization for raw SQL queries
When introducing any user-provided values into a raw SQL query, care
must be taken to avoid SQL injection attacks. In addition to
validating that such values don't contain invalid characters, always
use parameterization which sends the values separate from the SQL
text.
In particular, never pass a concatenated or interpolated string ($"")
with non-validated user-provided values into FromSqlRaw or
ExecuteSqlRaw. The FromSqlInterpolated and ExecuteSqlInterpolated
methods allow using string interpolation syntax in a way that protects
against SQL injection attacks.
Indeed, in your case, the string was first interpolated as a string (without any sanity-check), then executed as-is.
FromSqlRaw had no idea that the "Id" part was coming from a parameter.
Related
Someone looking at my code said that the SQL query below (SELECT * FROM...) was obviously open to attack. I have researched this and it seems I'm doing this correctly by using a parameterized query, but clearly I'm missing something.
app.get("/api/v1/:userId", async (req, res) => {
try {
const teammate = await db.query("SELECT * FROM teammates WHERE uid = $1", [
req.params.userId,
]);
This query is not open to SQL injection, because it uses a parameterized query. The data is not substituted for the parameter ($1), but sent separately in a “bind” message, so no matter what the data contain, it is not interpreted as part of the SQL statement.
Moreover, it looks like the argument is an integer, and SQL injection can only happen with string arguments.
Someone at that company may have assumed that the $1 was going to be used for string interpolation, instead of a SQL query parameter.
They might not be aware that PostgreSQL uses the dollar-sign sigil for a query parameter placeholder. Other databases like MySQL use ? for a placeholder, and Oracle uses a : sigil in front of a named parameter.
You wrote the code correctly. See a similar example for node.js and PostgreSQL here: https://node-postgres.com/features/queries The section on "Parameterized query" specifically shows that style of code as the defense against SQL injection.
You might be better off not getting that job, in retrospect.
I am making a query with ASP.NET with SqlConnection and SqlCommand. I am adding parameters to the query with the AddWithValue method, to avoid SQL injection.
I want to check the resultant query after the parameters have been included, for debug purposes. If I have "WHERE name = #myName", I want to see the query after #myName has been replaced. Is this possible?
Thank you.
Not really, because .NET never sends the complete query. The query is assembled by the database when it receives the SQL string and the parameter values.
The most you can do is log the SQL string, and log the values of the parameters you passed to it. From that you should still be able to easily infer what query was actually executed.
I'm so confused or rather I'm like, soooooooooo confused with pdo prepared statements. I know that prepared statements are the best way to keep data safe from hackers.
From : How can prepared statements protect from SQL injection attacks?
We are sending program to the server first
$db->prepare("SELECT * FROM users where id=?"); where the data is
substituted by some variable called "placeholder".
Note that the very same query being sent to the server, without any
data in it! And then we're sending the data with the second request,
totally separated from the query itself:
$db->execute($data);
query-
$query=$db->prepare("SELECT * FROM USERS WHERE username=?");
$query->execute(array($tex));
$tex=blah; DROP TABLE users;--
then it will be like - SELECT * FROM USERS WHERE username=blah; DROP TABLE users;--
how prepare statements will help me with this example above?
I'm really sorry if this question is vague to understand. Any help would be appreciated. Thanks in advance.
The prepared statement handler will make sure the bound value is always used as valid SQL value/literal (ie. an SQL string or a number) and never as 'raw SQL text'1.
This is why placeholders values cannot be used as identifiers such as column or table names or act as other SQL keywords; and cannot generate the vulnerable query hypothesized. Instead it is treated as the following:
WHERE username='blah; DROP TABLE users;--'
--^ placeholder ensures valid SQL string value is used
-- (note automatic/implicit addition of SQL quotes)
And even when binding with 'more tricky' data:
$tex = "blah'; DROP TABLE users;--"; // embedded SQL quote character
It would still be safe:
WHERE username='blah''; DROP TABLE users;--'
--^ placeholder STILL ensures valid SQL string value is used
Thus, when using placeholders, it is impossible to generate the SQL that is vulnerable (in this way).
For SQL Injection the 'shape' of the query (which includes keywords and identifiers, but excludes values) must itself be altered by the input.
1 Technically placeholders values can also be sent through a separate data channel (depending on adapter/driver) and thus might not even appear in the raw SQL query itself.
However a simple way to think about why placeholders are safe, or how they 'work' is:
When using placeholders the adapter ensures that the equivalent of 'sql really safe escape' and applicable quoting is always used for every bound text value - and is thus impossible for accidentally forget.
Since App Engine doesn't actually use SQL, does that mean that App Engine apps are immune from SQL injection attacks?
Yes, they are both equally susceptible to injection attacks, provided you do something along the lines of concatenating user-inputs with the GQL string.
However, if you follow Google's best-practice suggestion of using parameters when inputting values in a GQL string, you should be fine with GQL. So instead of:
query = GqlQuery("SELECT * FROM Song WHERE composer = 'Lennon, John'")
you can use:
query = GqlQuery("SELECT * FROM Song WHERE composer = :1", "Lennon, John")
or:
query = GqlQuery("SELECT * FROM Song WHERE composer = :composer", composer="Lennon, John")
Additionally, you will avoid this problem entirely by using the Query class to generate the query.
Well no SQL==no SQL injection, by definition. :-)
But you could certainly do GQL injection, if the app is using GQL and naïvely sticking string literal values into queries without escaping. The damage you can do with that is less than some variants of SQL that let you ;-terminate the current query and begin a new one in the same string, but it's still potentially dangerous.
GQLQuery provides a simple built-in parameter binding mechanism, though (unlike some languages' default libraries...). So there's really no excuse to still be stuffing string literals into a query string.
public function receiveDomainNames($keyword)
{
try
{
$stmt = $this->_dbh->prepare("SELECT d.someField FROM domain d WHERE d.someField LIKE :keyword");
$someField = '%'.$keyword.'%';
Do we need to escape $keyword on this case?
On php manual we can read:
If an application exclusively uses prepared statements, the developer can
be sure that no SQL injection will
occur (however, if other portions of
the query are being built up with
unescaped input, SQL injection is
still possible).
Is this the case on your opinion, are, on this case, build up unescaped input (no prior treatment has been made to our $keyword parameter) ?
Thanks in advance,
MEM
Given the above SQL statement, I see no rational possibility of a SQL injection.
What the warning about "other parts" would be a SQL query like:
$binds = array(":id"=>$_GET['id']);
$myPDO->prepare("SELECT {$_GET['columns']} FROM {$_GET{['table']} WHERE id = :id");
$statement = $myPDO->execute($binds);
The example is a worst case/explicit example of what they mean, that naively someone might think since they're escaping the where argument, that everything is safe.
With your example above, there is no un-escaped input so you're safe.
If an application exclusively uses prepared statements, the developer
can be sure that no SQL injection will occur (however, if other
portions of the query are being built up with unescaped input, SQL
injection is still possible).
I'd figure variables you create shouldn't have to be escaped because you know what they're doing.
Only escape content gotten from the user, such as $_COOKIE, $_POST, $_GET and other parameters such as the URL.