How do I prevent my SQL statements from SQL injection when using CLR/C++ with multiple variables? - sql

I am having a major problem where I do not know how to prevent SQL injection when writing SQL statements in CLR/C++
Below is the code
String^ sqlstr = "SELECT * FROM ";
sqlstr += tableName + " WHERE " + field + " = " + fieldEntity;
I need to be able to input correct SQL Injection preventions to this statement.
Background code
class database
{
protected:
string fieldEntity;
string tableName;
string field;
...
____
OleDbDataReader^ openData(String^ fieldEntity, String^ field, String^ tableName)
{
String^ sqlstr = "SELECT * FROM ";
sqlstr += tableName + " WHERE " + field + " = " + fieldEntity;
...
___
OleDbDataReader^ reader2 = testData.openData(effectID, "effectID", "effectOnUser");
while (reader2->Read())
{
Object^ dHealthptr = reader2["effectOnHealth"];
Object^ dTirednessptr = reader2["effectOnTiredness"];
Object^ dHappinessptr = reader2["effectOnHappiness"];
...

There are two ways to prevent SQL Injection and the environment of SQLCLR does not change this:
The preferred mechanism is by using parameterized queries. Different languages and libraries go about this in different ways, but at the very least you should be able to use prepared statements. Please note that this does not apply to scenarios that could not accept a variable, such as with tableName and field in your code.
Please see:
Issuing a Parameterized Query
Using Stored Procedures
Sanitize the inputs:
Bare minimum, and by far the most common, requirement is to escape single quotes by doubling them (i.e. ' becomes '')
Additionally (below is a quote from a related answer of mine on DBA.StackExchange):
There is a lesser known type of attack in which the attacker tries to fill up the input field with apostrophes such that a string inside of the Stored Procedure that would be used to construct the Dynamic SQL but which is declared too small can't fit everything and pushes out the ending apostrophe and somehow ends up with the correct number of apostrophes so as to no longer be "escaped" within the string. This is called SQL Truncation and was talked about in an MSDN magazine article titled "New SQL Truncation Attacks And How To Avoid Them", by Bala Neerumalla, but the article is no longer online. The issue containing this article — the November, 2006 edition of MSDN Magazine — is only available as a Windows Help file (in .chm format). If you download it, it might not open due to default security settings. If this happens, then right-click on the MSDNMagazineNovember2006en-us.chm file and select "Properties". In one of those tabs there will be an option for "Trust this type of file" (or something like that) which needs to be checked / enabled. Click the "OK" button and then try opening the .chm file again.
So, be sure to properly size the string input parameters. You don't need VARCHAR(500) for a column that is declared as VARCHAR(25). Please see my answer on DBA.StackExchange for more details and examples:
Why does SQL Injection not happen on this query inside a stored procedure?

For tableName and field variables, those are being used as SQL identifiers in your query. You can't use either common method of query parameters or escaping. You just have to make sure to whitelist the values for those variables. In other words, check them against known identifiers of tables and columns in your database.
For the other variable fieldEntity, I suppose this should be used like a constant value in your SQL query. You can protect this from SQL injection by using a query parameter.
I don't know CLR, but there are lots of examples of using SQL query parameters in C++ or C#.
https://owasp.org/www-project-cheat-sheets/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html

Related

How do I add parameters to my queries when using clr/c++ for multiple variables

I want to be able to add parameters to my queries to make my statements less vunerable to sql injections
My code (Key parts are surrounded by ** as I cannot make code bold)
OleDbConnection^ existingSqlConnection = nullptr;
existingSqlConnection = gcnew OleDbConnection("Provider = Microsoft.ACE.OLEDB.12.0;" +
"Data Source =" + "myDatabaseV3.accdb");
**String^ sqlText = "SELECT * FROM #tableName WHERE #fieldName = #fieldEntityName";
OleDbCommand^ dbCommand = gcnew OleDbCommand(sqlText, existingSqlConnection);
OleDbParameterCollection^ paramCollection = dbCommand->Parameters;
dbCommand->Parameters->Add(gcnew OleDbParameter("#tableName", tableName->ToString()));
dbCommand->Parameters->AddWithValue("#fieldName", field);**
dbCommand->Parameters->AddWithValue("#fieldEntityName", fieldEntity);
**Console::WriteLine(dbCommand->CommandText);
Console::WriteLine(paramCollection->Count);**
existingSqlConnection->Open();
OleDbDataReader^ reader = dbCommand->ExecuteReader(System::Data::CommandBehavior::CloseConnection);
return reader;
The output for this is
SELECT * FROM #tableName WHERE #fieldName = #fieldEntityName
3
Which clearly shows that there are 3 parameters but they are not being added to my query which is the problem I want to be solved
This is not how parameters work. They are not replacement values for text templates. Parameters are a mechanism to pass in a value to the variable in the query, just like passing a parameter to a stored procedure will pass that value in to be used as a variable in the query.
Along these lines, parameters can only be used where variables can be used in queries. And, variables cannot be used for object names, which is why people resort to using SQL Injection when the table and/or column name(s) need to change. In your example code:
#tableName could never be a variable in a query, hence it cannot be a parameter
#fieldName could never be a variable in a query, hence it cannot be a parameter
#fieldEntityName if it is supposed to be a value and not a column name, can be a parameter, in which case it will remain as #fieldEntityName in the query, and it will have a value of fieldEntity.
Please see the second option of my answer on your related question for how to prevent SQL Injection (short answer: sanitize inputs).
Also, using AddWithValue() is a bad practice. Create the parameter with the intended max size, then give that a value, and finally add it to the parameters collection. You do not want it to auto-detect the max size for the parameter as it will use the first value it gets, and any subsequent value that is longer will be silently truncated.

Fortify Sql Injection for Oracle

When I scan my project with fortify static code analyzer it finds Sql Injection results.
At Recommendations window fortify says : "The root cause of a SQL injection vulnerability is the ability of an attacker to change context in the SQL query, causing a value that the programmer intended to be interpreted as data to be interpreted as a command instead. When a SQL query is constructed, the programmer knows what should be interpreted as part of the command and what should be interpreted as data. Parameterized SQL statements can enforce this behavior by disallowing data-directed context changes and preventing nearly all SQL injection attacks. Parameterized SQL statements are constructed using strings of regular SQL, but when user-supplied data needs to be included, they create bind parameters, which are placeholders for data that is subsequently inserted. Bind parameters allow the program to explicitly specify to the database what should be treated as a command and what should be treated as data. When the program is ready to execute a statement, it specifies to the database the runtime values to use for the value of each of the bind parameters, without the risk of the data being interpreted as commands."
Look my code please. I am already using Parameterized SQL statements. So what is the problem? What am I missing?
Summary of my code;
Dim stateid As String = HttpContext.Current.Request.QueryString.Item("stateid"))
Dim colArgs As COLLECTIONS.ParamterCollection
colArgs = New COLLECTIONS.ParamterCollection
colArgs.Add(DATA.DataPreps.PrepStringForDB(stateid ))
Dim sSQL As String = "SELECT * FROM STATE WHERE N_STATE_ID = :P"
PrepareSQL(sSQL, colArgs, objDBConfigObject)
Dim objCommand As OracleCommand = new OracleCommand(sSQL, connection)
objCommand.CommandTimeout = m_nConnectionTimeout
For Each objArgument In colArgs
objParam = New Oracle.DataAccess.Client.OracleParameter(":P" & CStr(nInArgIndex), objArgument.enOracleType)
objParam.Value = objArgument.varValue
objCommand.Parameters.Add(objParam)
nInArgIndex += 1
objArgument = Nothing
objParam = Nothing
Next
objCommand.CommandType = CommandType.Text
objDataAdapter = New Oracle.DataAccess.Client.OracleDataAdapter(objCommand)
nRecordsAffected = objDataAdapter.Fill(objDataSet)
You can use DBMS_ASSERT to validate all user inputs.Read this
http://docs.oracle.com/cd/B28359_01/appdev.111/b28419/d_assert.htm#BABIEIFE
Parameterized queries are not a magic bullet. I would add a few things:
objParam.OracleDbType = Oracle.DataAccess.Client.OracleDbType.VarChar (this is the db column data type)
Ensure you are doing input validation to defang any dangerous SQLi characters.
Perform some sanity checking on arguments being passed. For example, how many max characters should the string stateid be?

VisualBasic OleDb accessing Excel spreadsheet, can't set column in query using parameter?

I'm working in Visual Basic and using OleDb to access an Excel spreadsheet. I'm importing the data from the sheet into my DataGridView, and that works fine, but now I'm working on filtering. For the most part it works great, but I'm trying to use parameters ("#p1" and so on), and I'm getting a very strange issue.
I can have the following (excluding a bunch of irrelevant stuff before, in between, and after)
query = query & "Project" & " LIKE #Gah1"
...
MyCommand.SelectCommand.Parameters.AddWithValue("#Gah1", "%House%")
and it gives me the results I'm looking for. But I can't seem to get a parameter for the name of the column itself, for example
query = query & "#Gah1" & " LIKE #Gah2"
...
MyCommand.SelectCommand.Parameters.AddWithValue("#Gah1", "Project")
MyCommand.SelectCommand.Parameters.AddWithValue("#Gah2", "%House%")
does not work (and I've tried enclosing Project in different brackets and stuff in different ways, can't get it to work). I've found plenty of examples on using parameters, but none that use them to give the column name.
I'm guessing the parameter changes how the string is represented, seeing as you don't need to have the ' ' around string literals.
Is it not possible to give column names in parameter? If you can, what do I need to do?
Well it won't let me post comment, so here
a) Oops, no, I guess not
b) The string query that I end up sending in my test query here is
"select * from [Bid Summary$] where #Gah1 LIKE #Gah2"
I can post the procedure if absolutely need be, but it isn't the problem because the whole thing works perfectly fine if I replace #Gah1 with Project or [Project], so I just showed the lines that I change.
I'm very new to parameterized queries, can you explain how to avoid query strings using it? If there's a better way to do what I'm doing I'm happy to use it =)
And thanks for response and edit
I use combination of string methods and parameters, like this:
//replace field name in a query template
query = String.Format("select * from [Bid Summary$] where {0} LIKE ?", "#Gah1");
//set value (name is in OleDb parameter ignored, so it could be null)
MyCommand.SelectCommand.Parameters.AddWithValue(null, "%House%");
Note: There is possibility of a sql injection, so be sure about origin of field name (not from user input).

How can this SQL query code be broken/exploited by user input? [duplicate]

This question already has answers here:
Closed 12 years ago.
Possible Duplicate:
Can I protect against SQL Injection by escaping single-quote and surrounding user input with single-quotes?
We have a legacy app that doesn't do queries using positional parameters, and there's SQL everywhere. It was decided (before I started here) that since user input can contain apostrophes, every string input should be manually escaped for those apostrophes.
Here is the essential original code (not written by me), translated into C# for easier consumption:
private string _Escape(string input)
{
return input.Replace("'", "''");
}
private bool _IsValidLogin(string userName, string password)
{
string sql =
string.Format
(
#"SELECT COUNT(*) FROM UserAccounts
WHERE UserName = '{0}' AND Password = '{1}'",
_Escape(userName),
_Escape(password)
);
// ...
}
This really seems like it can be broken in some way, but I'm at a loss as to how it could be exploited by user input. Assume user input is unfiltered until it hits _IsValidLogin, and forget that passwords appear to be stored in plain text.
The solution to shore it up for good is obvious -- use positional parameters -- but I need some ammunition to demonstrate to management why/how this code is insecure so time/$ can be allocated for it to get fixed.
Note: I'm assuming this can be broken, but that may not actually be the case. I'm not a SQL superstar.
Note 2: I've expressed this question as database-agnostic, but if you can exploit this code for a certain engine, I welcome your contribution.
It could be exlpoited by backslashes.
password = foo\' OR 1=1 --
becomes:
password = foo\'' OR 1=1 --
the query:
"SELECT COUNT(*) FROM UserAccounts
WHERE UserName = '{0}' AND Password = 'foo\'' OR 1=1 --'"
-- Is the comment mark in this example.
The solution assumes the program only filters (duplicates) apostrophes.
Well, I can't see a way it's vulnerable. So, let's argue a different reason why it should be changed --- it's rather ineffiecent. In MSSQL (and, I think, most other high end SQL servers), queries are parsed, and execution plan is devised, and then the query and plan are stored. If an exact copy of the query is requested again, the saved execution plan is used. Parameter don't affect this, so if you use parameters, it will reuse the plans; if you embed the text, it never will.

AS400 library/file (member) JDBC query

Using JDBC (with jt400 driver / connection, naming=system) I'm running these SQL statements:
"CREATE ALIAS QTEMP/SOURCETEMP FOR " + library + "/" + file + " (" + member + ")"
"SELECT SRCDTA FROM QTEMP/SOURCETEMP"
"DROP ALIAS QTEMP/SOURCETEMP"
This works. However, when the member String has a . in it this confuses everthing.
Is there any way of dealing with this?
Thanks.
You can escape any .'s by changing eg:
member = "foo.bar"
to
member = "\"FOO.BAR\""
ie capital letters enclosed within double quotes.
Somewhere in here there are details on how library(members) are handled.
Your problem seeems to be the basic member name is leant to be up eight chars and anything after a '.' is interpreted as a type (somewaht like .html, .jpg .exe etc)
however you can only store one type of data in a library object. So if your first member was premier.stuff than all the other member must have ".stuff" as a suffix if supplied.
The official 400-eze for a member is:
member
Different sets of data, each with the same format, within one database file.
You could probably get away with deleting everything after the first period from your member name.
Sorry if this isn't too clear but when the iSeries was designed they ignored every OS designed up till that point and started again from scratch. The results take some getting used too.