Does anyone know how to store a single backslash into PostgreSQL Database?
I am using C# and Nqgsql to access PostgreSQL, and my case is I want to store "1\\0\\0\\0\\1\\0" into the database, and the expected string in DB field will be "1\0\0\0\1\0", that is I only need one backslash in the db field, thus when I get the data from db, it will still be "1\\0\\0\\0\\1\\0" in memory. But my problem is when the memory string is "1\\0\\0\\0\\1\\0", the string stored into db field is also "1\\0\\0\\0\\1\\0", then when I get the data from db, the memory string will be "1\\\\0\\\\0\\\\0\\\\1\\\\0".
The variables I used in c# code is set as the following format:
var a = "1\\0\\0\\0\\1\\0";
var b = #"1\0\0\0\1\0";
when store into db, it seems that the backslashes in both variables have been doubled. How to deal with this issue?
You should avoid this entirely by using parametrized queries. Consult an example in Npgsql: User's Manual in Using parameters in a query section.
But if you really want to construct a literal query then you can use E'' syntax, like this:
var sql = #"insert into table_name (column_name) values (E'1\\0\\0\\0\\1\\0')";
This syntax is independent of server or connection configuration like standard_conforming_strings. But it is Postgres specific.
If you want your code be portable between different database engines the you can issue set standard_conforming_strings=on just after connecting. Then this works:
var sql = #"insert into table_name (column_name) values ('1\0\0\0\1\0')";
This option is turned on by default since PostgreSQL 9.1 and available since 8.2.
I had this problem as well. I was able to solve it by going in the database's config and changing "standard_conforming_strings" to OFF.
Related
I am converting a winforms application from MS Access to SQLServer Express.
I have some code which is used throughout the application for updating the database, I pass in the table name, ID for the entry the fields to update and the values in an array... works ok with access
The code generates an SQL statememnt, which is passed as a query along with the values as parameters... an example output is
UPDATE userVersion SET lastUpdated=?, userId=?, userName=?, version=? WHERE userId = 1299
if I try run this on sqlserver, the system crashes with this error
System.Data.SqlClient.SqlException: 'Incorrect syntax near '?'.
Incorrect syntax near '?'.'
What is the correct format for sql server?
Based on the error you are using SQLClient to execute the query, but the structure of the query looks like it may be closer to ODBC's command.
In case it helps, System.Data.ODBC.ODBCCommand uses the "?" symbol as a place holder for parameters. The order of the parameters is important in this case.
https://msdn.microsoft.com/en-us/library/system.data.odbc.odbccommand.parameters(v=vs.110).aspx
The System.Data.SQLClient.SQLCommand uses named variables (for example #MyVariable) to specify variables. In this case, order is not important as long as the names are specified correctly.
https://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlcommand.parameters(v=vs.110).aspx
ODBCCommand would look like:
UPDATE Sales.Store SET Demographics = #demographics WHERE CustomerID = ?;
While SQLCommand would look like:
UPDATE Sales.Store SET Demographics = #demographics WHERE CustomerID = #ID;
I'm having trouble doing case insensitive string comparison using code first against an Oracle db. Code looks something like this;
String filter = "Ali";
var employee = dbContext.Employees.Where(x => x.Name.Contains(filter)).FirstOrDefault();
The code above acts to be case sensitive. So I converted both the Name and filter to Uppercase;
String filter = "Ali";
filter = filter.ToUpper();
var employee = dbContext.Employees.Where(x => x.Name.ToUpper().Contains(filter)).FirstOrDefault();
Everything seemed to work at first, but then I realized it's not working when the employee's name or the filter contains the character 'i'. The problem is how the letter i works in Turkish.
In most languages, 'i' stands for the lowercase, and 'I' stands for the uppercase version of the character. However in Turkish, 'i's uppercase is 'İ', and 'I's lowercase is 'ı'. Which is a problem as Oracle uppercases the letter 'i' in the db as 'I'.
We do not have access to the db's character encoding settings as its effects cannot be foreseen easily.
What I've come up with is this, and it is very ugly.
String filterInvariant = filter.ToUpper(CultureInfo.InvariantCulture);
String filterTurkish = filter.ToUpper(CultureInfo.CreateSpecificCulture("tr-TR"));
var employee = dbContext.Employees.Where(x => x.Name.ToUpper().Contains(filterInvariant) || x.Name.ToUpper().Contains(filterTurkish)).FirstOrDefault();
It seems to fix some of the issues, but feels like a brute force workaround rather than a solid solution. What are the best practices, or alternatives to this workaround, while using Code First C# against an Oracle database?
Thanks in advance
Ditch using all the UPPER functions. Simply let Oracle do your language aware case-insensitive matching. This is done by setting your DB connection from C# to have the appropriate language parameters. This setting is just for your DB session, not a global change for the whole DB. I'm no C# wizard, so you'd have to figure out where to make these session settings in your db connection/pool code.
ALTER SESSION SET nls_language=TURKISH;
ALTER SESSION SET nls_comp=LINGUISTIC;
ALTER SESSION SET nls_sort=BINARY_CI;
If C# proves too difficult to find where to change this, you could set this up as a user/schema logon trigger (below), which sets these automatically for you at db connect time (replace SOMEUSER with your actual db username). This only affects any NEW db sessions, so if you have connections pooled, you'll want to cycle the DB connection pool to refresh the connections.
CREATE OR REPLACE TRIGGER SOMEUSER.SET_NLS_CASE_INSENSITIVE_TRG AFTER
LOGON ON SOMEUSER.SCHEMA
BEGIN
EXECUTE IMMEDIATE 'ALTER SESSION SET nls_language=TURKISH';
EXECUTE IMMEDIATE 'ALTER SESSION SET nls_comp=LINGUISTIC';
EXECUTE IMMEDIATE 'ALTER SESSION SET nls_sort=BINARY_CI';
END;
/
Here's a little test I did in an Oracle DB:
CREATE TABLE mypeople (name VARCHAR2(10 CHAR));
INSERT INTO mypeople VALUES ('Alİ Hassan');
INSERT INTO mypeople VALUES ('AlI Hassan');
INSERT INTO mypeople VALUES ('Ali Hassan');
INSERT INTO mypeople VALUES ('Alı Hassan');
SELECT name FROM mypeople WHERE name LIKE 'Ali%';
NAME
----------
Ali Hassan
ALTER SESSION SET nls_language=TURKISH;
ALTER SESSION SET nls_comp=LINGUISTIC;
ALTER SESSION SET nls_sort=BINARY_CI;
SELECT name FROM mypeople WHERE name LIKE 'Ali%';
NAME
----------
Alİ Hassan
AlI Hassan
Ali Hassan
The implementation of String.Contains is different for different providers, for example Linq2Sql is always case insensitive. The search is case sensitive or not depends on server settings. For example SQL Server by default has SQL_Latin1_General_CP1_CI_AS Collation and that is NOT case sensitive. For Oracle you can change this behavior at the session level: Case insensitive searching in Oracle (Issue a raw SQL query using context.Database.ExecuteSqlCommand method at the beginning of the session)
The problem is in the database, not in .NET, for example this query:
FILES.Where(t => t.FILE_NAME.ToUpper() == "FILE.TXT") // Get rows from file-table
translates into this Oracle SQL with the oracle provider I have:
SELECT t0.BINARY_FILE, t0.FILE_NAME, t0.FILE_SIZE, t0.INFO, t0.UPLOAD_DATE
FROM FILES t0
WHERE (UPPER(t0.FILE_NAME) = :p0)
-- p0 = [FILE.TXT]
The contains with First() becomes this:
SELECT * FROM (SELECT t0.BINARY_FILE, t0.FILE_NAME, t0.FILE_SIZE, t0.INFO, t0.UPLOAD_DATE
FROM FILES t0
WHERE ((UPPER(t0.FILE_NAME) LIKE '%' || :p0 || '%')
OR (UPPER(t0.FILE_NAME) LIKE '%' || :p1 || '%')))
WHERE ROWNUM<=1
-- p0 = [FILE.TXT]
-- p1 = [FİLE.TXT]
So it depends on your database's culture settings, ie without knowing them I would say the "overlap" with your solution is the best way to solve it. Why can't you just check the database culture settings?
As an extension to How to protect user specified table name from SQL Injection in C#, using MySQL, I'm trying to figure out how to protect the user-specified-table-query from SQL Injection:
string createEventSQL = "INSERT INTO " + TableNameFromUser +
" (" + TableColumnNames + ") " +
"VALUES(" + ParametrizedTableColumnParams + ")";
To be clear: I would love to use a predefined library to parametrize the input, but I can't find one.
I don't want additional queries (e.g. SHOW TABLES LIKE #TableNameFromUser;) to secure this, since performance is an issue.
It seems to me that many people claim that it isn't possible to to make a 100% secure solution, but that doesn't make sense to me, since resorting to parametrization should be just as "insecure" as doing all the work yourself. Essentially, I just want to replicate what the MySQL Connector would do, if it supported parametrized table names.
I'm not very experienced with SQL yet, but so far I've found that I need to:
Escape/disable all escapable characters.
Disable "--"
What else is can be done to protect from SQL Injection?
The MySQL Ado connector supports parameters on MySqlCommand - here.
As you've identified, in general, you should always pass parameters instead of mangling ad hoc SQL.
Unfortunately, this won't parameterize the table name, as per this SO post : MySqlParameter as TableName.
So it looks like you will need to validate and sanitize the table name.
Can you compare the table name against a white list? Or possibly keep a list of valid tables names somewhere else in the database?
You can, and should, parameterize your data values. You know that.
You can't parameterize your table names and column names using SQL's prepared statement feature. However, you should establish and enforce constraints on what can be in your user-furnished table and column names. For example, you could insist that table and column names all start with a letter, and consist of between 3 and 15 characters from the set of letters, numbers, and underscores. You can easily write a checker function that will throw an exception for user-furnished names that break the constraint, and always check the names with that function when composing a query.
For the sake of performance, you've ruled out checking the table and column names against the schema in your dbms. You might want to reconsider that decision: these queries aren't as slow as you think they are. The MySQL information schema lets you do queries like this:
SELECT COLUMN_NAME
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = 'zip'
AND TABLE_NAME= 'zip'
This will give you a nice list of columns in the table you've specified.
I like to find a way to handle multiple updates to a sql db (with one singe db roundtrip). I read about table-valued parameters in SQL Server 2008 http://www.codeproject.com/KB/database/TableValueParameters.aspx which seems really useful. But it seems I need to create both a stored procedure and a table type to use it. Is that true? Perhaps due to security? I would like to run a text query simply like this:
var sql = "INSERT INTO Note (UserId, note) SELECT * FROM #myDataTable";
var myDataTable = ... some System.Data.DataTable ...
var cmd = new System.Data.SqlClient.SqlCommand(sql, conn);
var param = cmd.Parameters.Add("#myDataTable", System.Data.SqlDbType.Structured);
param.Value=myDataTable;
cmd.ExecuteNonQuery();
So
A) do I have to create both a stored procedure and a table type to use TVP's? and
B) what alternative method is recommended to send multiple updates (and inserts) to SQL Server?
Yes, you need to create the types.
Alternatives are sending a big string sql batch or passing XML to sprocs.
The downside to big sql string batches is it can blow the sql proc cache and might cause sql to recompile - especially if the batch is unique because of input data being part of that large string. By definition each batch would be unique.
XML was the main alternative before TVPs. The one downside to XML, for at least awhile, sql azure didn't support it (that might change?) so it limits your options.
TVPs seem to be the way to do this. Our project just converted to using TVPs.
Hope that helps.
public static bool TruncateTable(string dbAlias, string tableName)
{
string sqlStatement = string.Format("TRUNCATE TABLE {0}", tableName);
return ExecuteNonQuery(dbAlias, sqlStatement) > 0;
}
The most common recommendation to fight SQL injection is to use an SQL query parameter (several people on this thread have suggested it).
This is the wrong answer in this case. You can't use an SQL query parameter for a table name in a DDL statement.
SQL query parameters can be used only in place of a literal value in an SQL expression. This is standard in every implementation of SQL.
My recommendation for protecting against SQL injection when you have a table name is to validate the input string against a list of known table names.
You can get a list of valid table names from the INFORMATION_SCHEMA:
SELECT table_name
FROM INFORMATION_SCHEMA.Tables
WHERE table_type = 'BASE TABLE'
AND table_name = #tableName
Now you can pass your input variable to this query as an SQL parameter. If the query returns no rows, you know that the input is not valid to use as a table. If the query returns a row, it matched, so you have more assurance you can use it safely.
You could also validate the table name against a list of specific tables you define as okay for your app to truncate, as #John Buchanan suggests.
Even after validating that tableName exists as a table name in your RDBMS, I would also suggest delimiting the table name, just in case you use table names with spaces or special characters. In Microsoft SQL Server, the default identifier delimiters are square brackets:
string sqlStatement = string.Format("TRUNCATE TABLE [{0}]", tableName);
Now you're only at risk for SQL injection if tableName matches a real table, and you actually use square brackets in the names of your tables!
As far as I know, you can't use parameterized queries to perform DDL statements/ specify table names, at least not in Oracle or Sql Server. What I would do, if I had to have a crazy TruncateTable function, that had to be safe from sql injection would be to make a stored procedure that checks that the input is a table that is safe to truncate.
-- Sql Server specific!
CREATE TABLE TruncableTables (TableName varchar(50))
Insert into TruncableTables values ('MyTable')
go
CREATE PROCEDURE MyTrunc #tableName varchar(50)
AS
BEGIN
declare #IsValidTable int
declare #SqlString nvarchar(50)
select #IsValidTable = Count(*) from TruncableTables where TableName = #tableName
if #IsValidTable > 0
begin
select #SqlString = 'truncate table ' + #tableName
EXECUTE sp_executesql #SqlString
end
END
If you're allowing user-defined input to creep into this function via the tablename variable, I don't think SQL Injection is your only problem.
A better option would be to run this command via its own secure connection and give it no SELECT rights at all. All TRUNCATE needs to run is the ALTER TABLE permission. If you're on SQL 2005 upwards, you could also try using a stored procedure with EXECUTE AS inside.
CREATE OR REPLACE PROCEDURE truncate(ptbl_name IN VARCHAR2) IS
stmt VARCHAR2(100);
BEGIN
stmt := 'TRUNCATE TABLE '||DBMS_ASSERT.SIMPLE_SQL_NAME(ptbl_name);
dbms_output.put_line('<'||stmt||'>');
EXECUTE IMMEDIATE stmt;
END;
Use a stored procedure. Any decent db library (MS Enterprise Library is what I use) will handle escaping string parameters correctly.
Also, re:parameterized queries: I prefer to NOT have to redeploy my app to fix a db issue. Storing queries as literal strings in your source increases maintenance complexity.
Have a look at this link
Does this code prevent SQL injection?
Remove the unwanted from the tableName string.
I do not think you can use param query for a table name.
There are some other posts which will help with the SQL injection, so I'll upvote those, but another thing to consider is how you will be handling permissions for this. If you're granting users db+owner or db_ddladmin roles so that they can truncate tables then simply avoiding standard SQL injection attacks isn't sufficient. A hacker can send in other table names which might be valid, but which you wouldn't want truncated.
If you're giving ALTER TABLE permissions to the users on the specific tables that you will allow to be truncated then you're in a bit better shape, but it's still more than I like to allow in a normal environment.
Usually TRUNCATE TABLE isn't used in normal day-to-day application use. It's used for ETL scenarios or during database maintenance. The only situation where I might imagine it would be used in a front-facing application would be if you allowed users to load a table which is specific for that user for loading purposes, but even then I would probably use a different solution.
Of course, without knowing the specifics around why you're using it, I can't categorically say that you should redesign, but if I got a request for this as a DBA I'd be asking the developer a lot of questions.
Use parameterized queries.
In this concrete example you need protection from SQL injection only if table name comes from external source.
Why would you ever allow this to happen?
If you are allowing some external entity (end user, other system, what?)
to name a table to be dropped, why won't you just give them admin rights.
If you are creating and removing tables to provide some functionality for end user,
don't let them provide names for database objects directly.
Apart from SQL injection, you'll have problems with name clashes etc.
Instead generate real table names yourself (e.g DYNTABLE_00001, DYNTABLE_00002, ...) and keep a table that connects them to the names provided by user.
Some notes on generating dynamic SQL for DDL operations:
In most RDBMS-s you'll have to use dynamic SQL and insert table names as text.
Be extra careful.
Use quoted identifiers ([] in MS SQL Server, "" in all ANSI compliant RDBMS).
This will make avoiding errors caused by invalid names easier.
Do it in stored procedures and check if all referenced objects are valid.
Do not do anything irreversible. E.g. don't drop tables automatically.
You can flag them to be dropped and e-mail your DBA.
She'll drop them after the backup.
Avoid it if you can. If you can't, do what you can to minimize rights to other
(non-dynamic) tables that normal users will have.
You could use SQLParameter to pass in tableName value. As far as I know and tested, SQLParameter takes care of all parameter checking and thus disables possibility of injection.
If you can't use parameterized queries (and you should) ... a simple replace of all instances of ' with '' should work.
string sqlStatement = string.Format("TRUNCATE TABLE {0}", tableName.Replace("'", "''"));