Can I see the actual query generated when using OracleParameters with OracleCommand? - c#

I want to use ODP.NET to run various queries on an oracle database and I'd like to use parameters in the query. Here's a trivial example snippet (omitting all the obvious setup bits of the OracleConnection):
string query = "SELECT FIRSTNAME FROM EMPLOYEES WHERE LASTNAME=:pNAME";
OracleCommand command = new OracleCommand(query);
command.Parameters.Add(":pNAME", OracleDBType.Varchar2).Value = "O'Brien";
My question is, is there anyway to see the query that gets generated from this? I know this is a simple example and the output is probably very obvious, but I'm trying to see how it actually handles things like escaping characters such as the ' in O'Brien. And of course in the future if my queries get more complicated and I'm getting sql errors, I thought I might be able to use the generated query to debug.
Any help or pointers is greatly appreciated!

SQL parameters are passed as parameters directly to SQL server, so there is no way to see it from your application. You can try checking it from Oracle side.

Related

How can I visualize MySQL Query string in C#

I am struggling with proper parameter passing to a MySQL query. In MySQL workbench, my query works fine, but not in the C# code. I assume it is due to wrong parameter passing.
That's why I'd like to see what precisely do I pass to the cmd.ExecuteScalar() method. But I can't figure out how to determine the cmd string.
In debugger I only get query with formal parameters, not passed ones. And even by using cmd.ToString() I get this nonsense:
MySql.Data.MySqlClient.MySqlCommand.
Here is my code:
string timeStampStr = timeStamp.ToString("yyyy-MM-dd hh:mm:ss");
...
MySqlCommand cmd = new MySqlCommand("SELECT COUNT(*) FROM plc WHERE plc.last_communication < #timeThreshold AND plc.id = #plcId", _conn);
cmd.Parameters.AddWithValue("#timeThreshold", timeStampStr); // Is this correct ? timeStampStr is a string
cmd.Parameters.AddWithValue("#plcId", plcId);
object result = cmd.ExecuteScalar();
Thank you !
Your best bet is probably to enable the query log on MySQL and use that to profile what was sent to the database engine.
This is because the application code doesn't actually replace the placeholders with the parameter values, the database engine does. The application code invokes the parameterized query and supplies the parameters simultaneously. (As a bit of a side-effect, this allows database engines to cache execution plans for parameterized queries much more effectively, since the query itself doesn't change. This provides a slight performance improvement when using parameterized queries over concatenated values.)
And even by using cmd.ToString() I get this nonsence: MySql.Data.MySqlClient.MySqlCommand.
That's not nonsense, that's the name of the class on which you're calling .ToString(). The default behavior of .ToString() for reference types is to return the name of the type, unless you override it.

C# Parse SQL statement to use parameters

Dilemma: I have a need to build an API into another application. In this API, we must allow the developers to run SQL statements on the SQL server... Unfortunately, we are very restricted (yes, the world is upside down here) as to what we can do to minimize SQL injections... We can't create SPs on the SQL server and we can't restrict what the user can enter for his/her query either. Now while I was told that because we are building an API for "other developers", we shouldn't have to worry about SQL injection, I don't tend to agree and I'd really like to prevent that if I can...
So I was thinking that what I could do, and this is where my question comes in, is parse the query to either:
Check for SQL Injection patterns and return an error if found; or
Remove any "assignment" sections, and replace then with parameters dynamically
Are these, given my situation, the only 2 options I have? And if so, how would you implement number 2 above so that this example statement:
SELECT * FROM Table WHERE Field1='test' AND Field2=1
Becomes:
SELECT * FROM Table WHERE Field1=#Field1 AND Field2=#Field2
Where the parameters have been extracted dynamically in C#? And if so, how would I be able to extract the data type for the params? Is that possible?
You can't solve it at the application side. You can restrict as much as you can, and parse all you want, but the SQL injection attacks are contiguously evolving and new vectors are being created that will bypass your parsing.
For running ad-hoc queries I strongly recommend relying on permissions, not on SQL parsing. Users should be able to inject themselves all they want, but the permissions should prevent any damage. You won't be able to prevent (intentional or accidental) DOS from running a bad query that brings the server to its knees, but for that there is resource governance and audit.
But I can't stress this enough: you won't parse yourself out of the problem. Multi-byte character exploits are +10 years old now, and I'm pretty sure I don't know the majority of filter/parse by-pass techniques out there.
If your assignment is just writing a wrapper around a database so that other developers can send in their own SQL and get results then SQL injections are the "normal use case". There is just no way of knowing if a request is malicious or not. If you are allowed to run "good" code, you'll always be able to run "evil" code.
you can extract parameters from sql syntax
SqlConnection sqlCon = new SqlConnection("...");
String sqlScript = "Somethings ...";
Regex r = new Regex(#"(?<Parameter>#\w*)", RegexOptions.Compiled);
string[] parameters = r.Matches(sqlScript).Cast<Match>().Select<Match, string>(x => x.Value.ToLower()).Distinct<string>().ToArray<string>();
SqlCommand sqlCom = new SqlCommand(sqlScript, sqlCon);
foreach (string sqlParam in parameters)
{
sqlCom.Parameters.AddWithValue(sqlParam, "PARAMETER VALUE");
}

Check for SQL Keywords in C#

if i allow users to type in a textbox and then perform a search against my db, there is the potential for sql injection. i could use regex, thats my first thought. but i had a better idea. why not see if what they typed has any SQL keywords in it. Im using an SQL Server database, in an ASP.NET program with c#, i thought microsoft would have offered an easy solution to what i am talking about. the best i can find is in this article:
Is it a programmatic way to get SQL keywords (reserved words)
which is probably what ill end up doing, but my problem is i still have to type out the entire list of keywords, there is around a hundred. sure i could be done by now instead of searching and asking this question. but isnt there an easier way? right now im going to:
1 Create a Hashset
2 add all the keywords to the hashset (cmon)
3 validate user input against the hashset
would love to see step 2 be made much easier, any other suggestions about sql injections are also appreciated
If you are passing the search text into a stored procedure and doing something like
WHERE search LIKE #inputParam
SQL will not allow injection to incur in the above fragment.
However, if you are building a string variable and then using EXEC #sql or sp_execute #SQL, you are vulnerable to SQL injection.
In my opinion, you would be better off avoiding the problem of checking for SQL keywords altogether by using parameterized SQL. Here's an example in C# (assuming you're using MS SQL Server):
using (SqlCommand sqlcmd = new SqlCommand("SELECT * FROM [MyDB].[dbo].[MyTable] WHERE [SomeColumn] = #SomeValue", sqlconnection))
{
sqlcmd.Parameters.AddWithValue("#SomeValue", strUsersSearchString);
// use sqlcmd.ExecuteReader() here
// or whatever you normally would
}
Here's another example on MSDN. This one is using parameterized SQL to call a stored procedure: http://msdn.microsoft.com/en-us/library/ff648339.aspx#paght000002_step3
Use named parameters. Dapper-dot-net makes it really easy to do this:
IEnumerable<Row> results = connection.Query<Row>("SELECT column FROM table WHERE title LIKE #query", new { query = "SEARCHTERM" });

Best practices for inline SQL queries

I'm working with an asp.net website that uses a lot of inline SQL queries... and I'm wondering if it is best to create the inline queries on the fly:
int i = 500;
using (SqlConnection conn = new SqlConnection(connStr))
{
SqlCommand com = new SqlCommand(conn);
...
com.CommandText = "select from table where column < #parameter";
...
}
Or to have a class to hold all queries needed for the application. Something like this:
class SqlQueries
{
private string query1 =
"select * from tblEmployees where EmployeeName = #EmployeeName";
private string query2 =
"select * from tblVacation where EmployeeName = #EmployeeName";
public string Query(string s)
{
string str = string.Empty;
switch (s)
{
case "query1":
str = query1;
break;
case "query2":
str = query2;
break;
}
return str;
}
}
Thank you!
I've used a lot of ADO.NET queries in my day and I have always used the first method. The second method is an interesting idea, but it might be cumbersome to edit those queries if you are at another place in the code that uses it. It also makes it harder to see what a query is doing at a particular place in code. Example:
string sql = "Update User set age = #age where UserId = #UserId";
tells a developer what is happening, while:
string sql = SqlQueries.Query("updateAge");
Leaves questions about what table/columns are being updated. Also, with the first one, you know exactly what params need to be added.
If you are writing this query in several places that might change things
It's not terrible to put the literal directly in the method, as long as you always call that same method every time you want to run that query. However, if you are going to copy that string literal into multiple places in your code, then a constant is definitely preferred. However, rather than taking a string as the argument for the Query method in your second example, it should take an enumeration value.
However, if you are using the second method you described, I would ask you why you don't just start using stored procedures instead?
I would recommend using stored procedures as a much better solution to your problem than hard coded in-line queries. If you have to change the query at a later date, you don't have to rebuild your application, so bugs in your query can be fixed without needing to deploy the whole application. The 2nd option you have there is a maintenance nightmare waiting to happen. It all looks so nice when you have one or two queries in it, but that begins to look a bit more ugly when you have tens or hundreds in there. Your code looks like it's c#, so I would recommend checking out the Microsoft Enterprise Library,
http://msdn.microsoft.com/en-us/library/ff632023.aspx
You might need to download a different version depending on what version of the .NET framework you are developing with.
If you absolutely have to have "inline" sql as opposed to stored procedures (and I have done this for utility type applications that merely interact with a database, rather than own it), I would suggest putting your SQL into an embedded resource file. This will make your queries easier to maintain (although you will still need to re-compile your app to make changes).
I think it's OK to have the queries "inline" as long as they aren't repeated in several places. If that starts to happen, then you might want to start creating Query classes.
In both the cases you are ultimately building/fetching String which you will pass to CommandText. So there would be no such difference. Only thing you need to consider in your case is how you would maintain the code or how will other people understand your code.
If you're going to use inline SQL at least don't put it in the web page code because it will be painful when you make database changes to know what it affects. Putting all the queries in one classes might be a bit disorganized, but if you grouped them by functional classes (like manager classes for your business objects) it might be easier to deal with.
If your queries are longer than a line or two, you should consider putting them in their own .sql file. Set the build action on the file to embedded resource, and access it with a call to GetManifestResourceStream(). That way, you're elevating your sql to the status of a proper language, with syntax highlighting, validation and intellisense (when you connect VS to your DB). Needless to say, this hugely facilitates maintenance.
If all this seems like a hassle, grab my VS extension, QueryFirst. Create your .sql files with the provided template and they will automatically be wired up for compilation. But you won't care because you'll just access the queries via the generated classes.
Sql is the only computer language I can think of that we accept to see chopped up in string literals. It ought to be a scandal.

Escaping various characters in C# SQL from a variable

I'm working a C# form application that ties into an access database. Part of this database is outside of my control, specifically a part that contains strings with ", ), and other such characters. Needless to say, this is mucking up some queries as I need to use that column to select other pieces of data. This is just a desktop form application and the issue lies in an exporter function, so there's no concern over SQL injection or other such things. How do I tell this thing to ignore quotes and such in a query when I'm using a variable that may contain them and match that to what is stored in the Access database?
Well, an example would be that I've extracted several columns from a single row. One of them might be something like:
large (3-1/16" dia)
You get the idea. The quotes are breaking the query. I'm currently using OleDb to dig into the database and didn't have an issue until now. I'd rather not gut what I've currently done if it can be helped, at least not until I'm ready for a proper refactor.
This is actually not as big problem as you may see it: just do NOT handle SQL queries by building them as plain strings. Use SqlCommand class and use query parameters. This way, the SQL engine will escape everything properly for you, because it will know what is the code to be read directly, and what is the parameter's value to be escaped.
You are trying to protect against a SQL Inject attack; see https://www.owasp.org/index.php/SQL_Injection.
The easiest way to prevent these attacks is to use query parameters; http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlparameter.aspx
var cmd = new SqlCommand("select * from someTable where id = #id");
cmd.Parameters.Add("#id", SqlDbType.Int).Value = theID;
At least for single quotes, adding another quote seems to work: '' becomes '.
Even though injection shouldn't be an issue, I would still look into using parameters. They are the simpler option at the end of the day as they avoid a number of unforeseen problems, injection being only one of them.
So as I read your question, you are building up a query as a string in C#, concatenating already queried column values, and the resulting string is either ceasing to be a string in C#, or it won't match stuff in the access db.
If the problem is in C#, I guess you'll need some sort of escaping function like
stringvar += escaped(columnvalue)
...
private static void escaped(string cv) as string {
//code to put \ in front of problem characters in cv
}
If the problem is in access, then
' escapes '
" escapes "
& you can put a column value containing " inside of '...' and it should work.
However my real thought is that, the SQL you're trying to run might be better restructured to use subqueries to get the matched value(s) and then you're simply comparing column name with column name.
If you post some more information re exactly what the query you're producing is, and some hint of the table structures, I'll try and help further - or someone else is bound to be able to give you something constructive (though you may need to adjust it per Jet SQL syntax)

Categories