Is this all to stop SQL injection in Drupal?
db_query('INSERT INTO {tablename} (field1, field2) VALUES ("%s", "%s")', $field1, $field2);
You can use parameters, as described in the documentation.
However, you should call the drupal_write_record function instead.
Is your question "Is this all I need to do to stop SQL injection in Drupal?"
The answer is "Almost, but not quite."
db_query("INSERT INTO {tablename} (field1, field2) VALUES ('%s', '%s')",
$field1, $field2);
Single quotes are more standard for quoting values in SQL.
Alternately, if you've defined tablename table via hook_schema, you can use drupal_write_record instead, as the other answer states. The advantage of drupal_write_record is that you don't have to deal with any sql, you just do this:
$tablename = array('field1' => $field1, 'field2' => $field2);
drupal_write_record('tablename', $tablename);
I strongly recommend using drupal_write_record() function instead of SQL instructions, as SLaks pointed before.
Related
I'm looking for the equivalent of Scope_identity() or ##identity in sql server, except for sqllite?
I'd hate to resort to a max select on the id column, but that is plausible.
Since I have never used SQL Server, I am not exactly sure what ##IDENTITY does, but if I understand this document correctly, then sqlite3_last_insert_rowid() may be what you are looking for.
last_insert_rowid()
This function returns the ROWID of the last row insert from the database connection which invoked the function. The last_insert_rowid() SQL function is a wrapper around the sqlite3_last_insert_rowid() C/C++ interface function.
Reference
I am using Full Text Search with LINQ in my application and as this is not supported by LINQ I use a table-valued function workaround. The function is created on SQL Server 2008.
Surprisingly, I get error “The full-text query parameter for Fulltext Query String is not valid” when I search for a simply text e.g. “manager”
I used SQL Server Profiler and found out that LINQ generated the parameter as nvarchar(4000) instead of nvarchar(250) which is in my function.
The biggest surprise came when I changed my SQL Server function so it accepts parameter as nvarchar(4000) instead of nvarchar(250) and the problem is solved.
I was also playing to change the parameter to nvarchar(2000) and less but this also didn’t work.
Does anybody know why this behaves this way?
Updated on 18th November 2013 - Good news and bad news
Good news - I am now using Entity Framework 6 for this particular example and it is not anymore needed to use nvarchar(4000)
Bad news - You have to use instead nvarchar(max) :-(
For an expanation see the following link http://social.msdn.microsoft.com/Forums/en-US/linqtosql/thread/1a46d676-32f0-44a4-b39f-61a17bccb8e3/.
In my case I had to force JAVA to call my Table-Value-Function with matching datatype as below
query.setParameter(0, variable, new **StringNVarcharType**() )
You need to ensure the size of the varchar (or nvarchar) variables are the same in your sql function and where they are declared.
In my case I had a function that declared the variable as nvarchar(100) but the stored procedure that called the function declared the variable passed in as nvarchar(200). Changing the function to be the same as the stored procedure variable fixed this.
Code below shows the non-working case with the inconsistently sized nvarchars.
CREATE FUNCTION [dbo].[udf_FullTextSearch](#searchExpression nvarchar(100))
RETURNS TABLE
AS
RETURN
SELECT *
FROM Company c
WHERE contains(c.Name, #searchExpression)
GO
DECLARE #searchExpression nvarchar(200) = '"ltd"'
SELECT * FROM [dbo].[udf_FullTextSearch](#searchExpression)
in typical PHP applications I used to use mysql_real_escape_string before I did SQL inserts. However I am unable to do that in Drupal so would need some assistance. And without any sort of function like that, user input with apostrophes is breaking my code.
Please suggest.
Thank You
My SQL is as follows:
$sql = "INSERT INTO some_table (field1, field2) VALUES ('$field1', '$field2')";
db_query($sql);
Wrap your table with {}.
Also, use the proper placeholder syntax for insertion, like %d for numbers, %s for strings.
Here is the function API page:
http://api.drupal.org/api/function/db_query/6
Note that it has arguments.
Example:
db_query('INSERT INTO {tablename} (field1, field2) VALUES ("%s", "%s")', $field1, $field2);
I'm building a website using ASP.NET and SQL Server, and I use
SELECT PK FROM Table WHERE PK = ##identity
My question is which is better and more reliable to retrieve the last inserted PK for multiuser website, using ##identity or using this:
SELECT MAX(PK) FROM Table WHERE PK = Session ("UserID")
I'm not sure exactly what you want to achieve, but the recommended way to retrieve the primary key value of the last statement on a connection is to use SCOPE_IDENTITY()
##Identity is particularly risky where you are using triggers, since it returns the last generated identity value, including those generated by triggers flowing on from a statement.
MSDN has the following to say:
SCOPE_IDENTITY and ##IDENTITY return
the last identity values that are
generated in any table in the current
session. However, SCOPE_IDENTITY
returns values inserted only within
the current scope; ##IDENTITY is not
limited to a specific scope.
You should certainly use SCOPE_IDENTITY() in favour of the MAX(PK) approach - any number of possible future changes could invalidate this method.
For SQL Server 2005 and above...
You can do the INSERT and SELECT in one call using the OUTPUT clause...
INSERT MyTable (col1, col2, ..., coln)
OUTPUT INSERTED.keycol, INSERTED.col1, INSERTED.col2, ..., INSERTED.coln
VALUES (val1, val2, ..., valn)
Otherwise, you only use SCOPE_IDENTITY()
As mentioned by #David Hall the ##IDENTITY keyword returns the most recently created identity for your current connection, not always the identity for the recently added record in your query and may return an incorrect value. Using MAX(PK) there is a higher chance for an incorrect value and I'd strongly recommend against using it. To avoid the any race conditions I'd suggest that you use SCOPE_IDENTITY() to return the identity of the recently added record in your INSERT SQL Statement or Stored Procedure.
Depends on what you're trying to accomplish. If you want to return the just-generated ID to the ASP.NET code (a typical scenario), then ##identity is your friend. In a high-concurrency situation, mak(PK) is not even guaranteed to be the PK you're after.
I've been preaching both to my colleagues and here on SO about the goodness of using parameters in SQL queries, especially in .NET applications. I've even gone so far as to promise them as giving immunity against SQL injection attacks.
But I'm starting to wonder if this really is true. Are there any known SQL injection attacks that will be successfull against a parameterized query? Can you for example send a string that causes a buffer overflow on the server?
There are of course other considerations to make to ensure that a web application is safe (like sanitizing user input and all that stuff) but now I am thinking of SQL injections. I'm especially interested in attacks against MsSQL 2005 and 2008 since they are my primary databases, but all databases are interesting.
Edit: To clarify what I mean by parameters and parameterized queries. By using parameters I mean using "variables" instead of building the sql query in a string.
So instead of doing this:
SELECT * FROM Table WHERE Name = 'a name'
We do this:
SELECT * FROM Table WHERE Name = #Name
and then set the value of the #Name parameter on the query / command object.
Placeholders are enough to prevent injections. You might still be open to buffer overflows, but that is a completely different flavor of attack from an SQL injection (the attack vector would not be SQL syntax but binary). Since the parameters passed will all be escaped properly, there isn't any way for an attacker to pass data that will be treated like "live" SQL.
You can't use functions inside placeholders, and you can't use placeholders as column or table names, because they are escaped and quoted as string literals.
However, if you use parameters as part of a string concatenation inside your dynamic query, you are still vulnerable to injection, because your strings will not be escaped but will be literal. Using other types for parameters (such as integer) is safe.
That said, if you're using use input to set the value of something like security_level, then someone could just make themselves administrators in your system and have a free-for-all. But that's just basic input validation, and has nothing to do with SQL injection.
No, there is still risk of SQL injection any time you interpolate unvalidated data into an SQL query.
Query parameters help to avoid this risk by separating literal values from the SQL syntax.
'SELECT * FROM mytable WHERE colname = ?'
That's fine, but there are other purposes of interpolating data into a dynamic SQL query that cannot use query parameters, because it's not an SQL value but instead a table name, column name, expression, or some other syntax.
'SELECT * FROM ' + #tablename + ' WHERE colname IN (' + #comma_list + ')'
' ORDER BY ' + #colname'
It doesn't matter whether you're using stored procedures or executing dynamic SQL queries directly from application code. The risk is still there.
The remedy in these cases is to employ FIEO as needed:
Filter Input: validate that the data look like legitimate integers, table names, column names, etc. before you interpolate them.
Escape Output: in this case "output" means putting data into a SQL query. We use functions to transform variables used as string literals in an SQL expression, so that quote marks and other special characters inside the string are escaped. We should also use functions to transform variables that would be used as table names, column names, etc. As for other syntax, like writing whole SQL expressions dynamically, that's a more complex problem.
There seems to be some confusion in this thread about the definition of a "parameterised query".
SQL such as a stored proc that accepts parameters.
SQL that is called using the DBMS Parameters collection.
Given the former definition, many of the links show working attacks.
But the "normal" definition is the latter one. Given that definition, I don't know of any SQL injection attack that will work. That doesn't mean that there isn't one, but I have yet to see it.
From the comments, I'm not expressing myself clearly enough, so here's an example that will hopefully be clearer:
This approach is open to SQL injection
exec dbo.MyStoredProc 'DodgyText'
This approach isn't open to SQL injection
using (SqlCommand cmd = new SqlCommand("dbo.MyStoredProc", testConnection))
{
cmd.CommandType = CommandType.StoredProcedure;
SqlParameter newParam = new SqlParameter(paramName, SqlDbType.Varchar);
newParam.Value = "DodgyText";
.....
cmd.Parameters.Add(newParam);
.....
cmd.ExecuteNonQuery();
}
any sql parameter of string type (varchar, nvarchar, etc) that is used to construct a dynamic query is still vulnerable
otherwise the parameter type conversion (e.g. to int, decimal, date, etc.) should eliminate any attempt to inject sql via the parameter
EDIT: an example, where parameter #p1 is intended to be a table name
create procedure dbo.uspBeAfraidBeVeryAfraid ( #p1 varchar(64) )
AS
SET NOCOUNT ON
declare #sql varchar(512)
set #sql = 'select * from ' + #p1
exec(#sql)
GO
If #p1 is selected from a drop-down list it is a potential sql-injection attack vector;
If #p1 is formulated programmatically w/out the ability of the user to intervene then it is not a potential sql-injection attack vector
A buffer overflow is not SQL injection.
Parametrized queries guarantee you are safe against SQL injection. They don't guarantee there aren't possible exploits in the form of bugs in your SQL server, but nothing will guarantee that.
Your data is not safe if you use dynamic sql in any way shape or form because the permissions must be at the table level. Yes you have limited the type and amount of injection attack from that particular query, but not limited the access a user can get if he or she finds a way into the system and you are completely vunerable to internal users accessing what they shouldn't in order to commit fraud or steal personal information to sell. Dynamic SQL of any type is a dangerous practice. If you use non-dynamic stored procs, you can set permissions at the procesdure level and no user can do anything except what is defined by the procs (except system admins of course).
It is possible for a stored proc to be vulnerable to special types of SQL injection via overflow/truncation, see: Injection Enabled by Data Truncation here:
http://msdn.microsoft.com/en-us/library/ms161953.aspx
Just remember that with parameters you can easily store the string, or say username if you don't have any policies, "); drop table users; --"
This in itself won't cause any harm, but you better know where and how that date is used further on in your application (e.g. stored in a cookie, retrieved later on to do other stuff.
You can run dynamic sql as example
DECLARE #SQL NVARCHAR(4000);
DECLARE #ParameterDefinition NVARCHAR(4000);
SELECT #ParameterDefinition = '#date varchar(10)'
SET #SQL='Select CAST(#date AS DATETIME) Date'
EXEC sp_executeSQL #SQL,#ParameterDefinition,#date='04/15/2011'