Npgsql CREATE USER using ExcuteNonQuery parameter - c#

Hi I am trying to use SQL CREATE USER with NpgsqlParameter (to prevent sql injection):
var p = new NpgsqlParameter("p1", "testuser");
using (var cmd = new NpgsqlCommand("CREATE USER #p1", (NpgsqlConnection)sqlConn))
{
cmd.Parameters.Add(p)
cmd.ExecuteNonQuery();
}
I get a run time error
syntax error at or near $1
Can anyone help me out please?

Alas, you can't use binding variables with CREATE USER. To prevent sql injection use quotation: "me; delete from myTable" -> "'me; delete from myTable'":
string userName = ...
using (var cmd = new NpgsqlCommand(
$"CREATE USER '{userName.Repace("'", "''")}'",
(NpgsqlConnection)sqlConn)) {
cmd.ExecuteNonQuery();
}
Here we double each apostrophe which is within userName and then wrap chnaged name into apostrophes

Related

Change user password for Oracle database using sql statement in C#

I'm working on a requirement where I have to change the oracle connection password of the current user from my application.
I have found that I can use the following statement to achieve this task using SQL:
ALTER USER *username* IDENTIFIED BY *password*
However because the username and password aren't sent to the database as quoted strings, I can't use bind parameters. (Which is also stated by this answer)
I have a working solution when I concatenate a string and sent it as a regular sql query over my Entity Framework DbContext instance like this:
using (var context = _dbContextFactory.CreateContext())
{
await context.Database.ExecuteSqlCommandAsync(
$"ALTER USER {username} IDENTIFIED BY \"{newPassword}\"");
}
The downsides of this approach is that by concatinating the password in the string I have SQL injection vulnerabilities and the user can't use some reserved characters in their passwords, like e.g. ; and "
I'm not concerned about the username parameter because this is managed within the backend code, however the password is directly from user input.
Is there any way to change the current users password in the Oracle database from C# using a safe approach? I'm also open to other approaches like a diffrent method or creating a stored procedure in the database, as long as it can be implemented in a C# client application.
We are using Oracle version 12+, so I can't use the IDENTIFIED BY VALUES '' syntax
For username we have to provide Oracle Identifier (in case we keep the original query) which is
Up to 30 characters in length
Must start with a letter
Can include $ (dollar sign), _ (underscore), and # (hash sign)
we can validate provided value via regular expressions:
if (!Regex.IsMatch(username, #"^[A-Za-z][A-Za-z0-9_#\$]{0,29}$")) {
// username is invalid
}
For the password we can
Double all quotations: my"password -> my""password
Ensure that the password contains valid characters only (e.g. let's exclude unicode control characters like back space and other)
So the code will be something like this
if (!Regex.IsMatch(username, #"^[A-Za-z][A-Za-z0-9_#\$]$")) {
// username is invalid
}
if (string.IsNullOrEmpty(newPassword) || newPassword.Any(c => char.IsControl(c))) {
// password is invalid
}
using (var context = _dbContextFactory.CreateContext()) {
await context.Database.ExecuteSqlCommandAsync(
$"ALTER USER {username} IDENTIFIED BY \"{newPassword.Replace("\"", "\"\"")}\"");
}
This seems to be working on my local Oracle test db (from ODP.net driver). The important bit seemed to be BEGIN / END; (wouldn't work without it).
using (var con = (OracleConnection)db.Server.GetConnection())
{
con.Open();
//string pw = "'''';++";
string pw = "newpass";
var cmd = new OracleCommand(#"
BEGIN
EXECUTE IMMEDIATE CONCAT('ALTER USER B identified by ',:pw);
END;", con);
cmd.CommandType = CommandType.Text;
var p2 = cmd.CreateParameter();
p2.ParameterName = "pw";
p2.Value = pw;
p2.DbType = DbType.String;
cmd.Parameters.Add(p2);
cmd.ExecuteNonQuery();
}

MySQL truncate command with parameter not working

Why do I get an exception when trying to truncate a MySQL table (using MySQL Connector/Net)? I am trying to give the table name with a parameter.
This is the code I'm executing:
var connectionString = "Server="+_server+";Uid="+_user+";Pwd="+_password+";Database="+_database+";";
try
{
using (var conn = new MySqlConnection(connectionString))
{
conn.Open();
const string sql = "TRUNCATE TABLE #tablename"; // also tried with TRUNCATE #tablename
var cmd = new MySqlCommand(sql, conn);
cmd.Parameters.AddWithValue("#tablename", "test");
cmd.ExecuteNonQuery();
conn.Close();
}
}
catch (MySqlException ex)
{
Console.WriteLine(ex.ToString());
}
And this is the execption:
MySql.Data.MySqlClient.MySqlException (0x80004005): You have an error
in your SQ L syntax; check the manual that corresponds to your MySQL
server version for the right syntax to use near ''test'' at line 1
When I try a select query, for example, then I don't have any problems. This runs fine and returns correct data:
conn.Open();
const string sql = "SELECT body FROM test WHERE id=#pid";
var cmd = new MySqlCommand(sql, conn);
cmd.Parameters.AddWithValue("#pid", 1);
cmd.ExecuteScalar();
conn.Close();
Parameters are used for query values, not object names like tables.
So this will not work for sure.
You need to set the table name in the command string by using string concatenation. You can avoid sql injection attacks by manually checking for weird characters in the table name (spaces, dashes, semicolons, etc..)
I've been playing around with this for a while now, and i can't seem to get it to work either. I can't find any documentation online, so i'm starting to think you may not be able to truncate with a parameter like you've tried.
However, is there really a need to prevent SQL injection on this command? Does the user enter the name of the table they want to truncate, and if so, they're just going to truncate a table which...is essentially what the command does anyway?

I am creating a website which enables the end users to create applications, where i will use the user entered value as the database name

i am retrieving AppName from the Text box.
string AppName = TextBox1.Text;
Now i want to create a database Whose name will be retrieved from text box, i.e AppName
string Text = "create database AppName";
MySqlCommand cmd = new MySqlCommand(Text,Connection);
but the above code is creating database named AppName But not the user entered name.
string Text = "create database " + AppName;
You're not using the actual value in your SQL query, you're just using the same literal string every time:
"create database AppName"
Instead, you need to incorporate the actual value being entered. I'm not 100% familiar with the MySQL syntax or query objects, but in general it would look something like this:
string appName = TextBox1.Text;
string commandText = "CREATE DATABASE #DBName";
using (MySqlCommand cmd = new MySqlCommand(commandText, connection))
{
cmd.Parameters.Add("#DBName", System.Data.SqlDbType.NVarChar, 50);
cmd.Parameters["#DBName"].Value = appName;
cmd.Connection.Open();
cmd.ExecuteNonQuery();
}
This is free-hand code, since I don't have the relevant objects available. But the idea is that you would create a variable parameter within the query (#TableName) and then populate that parameter with the desired runtime value before executing the query (cmd.Parameters["#TableName"].Value = appName;).

Determining if user login already exists in database?

I am building a web application in asp.net using C#. I have the Form where the user should register and then can login. I am having a problem in making the web app know that the name which the user picks is either "already exists" or not. If it already exists it should not insert the same name and display a message saying "user name already exists". I have tried the SqlDataReader but no luck.
protected void Register_Button_Click(object sender, EventArgs e)
{
SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["BJ_Player_String"].ToString());
SqlCommand cmd = new SqlCommand();
SqlCommand cmd2 = new SqlCommand();
SqlDataReader data_reader;
String name = TextBox2.Text;
String date = TextBox3.Text;
try
{
conn.Open();
cmd = new SqlCommand("Insert into BJ_Player (Player_Name, D_O_B) Values (#Player_name, #D_O_B)", conn);
cmd = new SqlCommand("Select Player_Name from BJ_Player WHERE Player_Name = #Player_name", conn);
cmd.Parameters.Add("#Player_name", SqlDbType.NVarChar).Value = name;
cmd.Parameters.Add("#D_O_B", SqlDbType.Date).Value = date;
cmd.Connection = conn;
data_reader = cmd.ExecuteReader();
cmd.ExecuteNonQuery();
if (data_reader.HasRows)
{
lblPlayerNameExists.Visible = true;
}
else
{
// do nothing
}
}
Make Player_Name unique in database then it will give you exception when you try to insert. You have to use unique constraint.
You have to give command type also and check you assigned both queries to same cmd object
in your code you're inserting data in your DB and then you are examining that the name is the same or not.
first you should search the name in your DB and then if there isn't any record with that name ,you should add your record.
I usually do it in one of two ways:
Create stored procedure that will check for name uniqueness and insert new record if everything is ok. It should return status as numeric code that you will check.
Check for name uniqueness before saving it using as a part of validation process.
Using the merge statement may help with this. Merge performs insert, update, or delete operations on a target table based on the results of a join with a source table.
Basically it inserts when needed, and updates when needed. Often times referred to as an upsert. but it gets the job done.
Here is a link to a site explaining how to use merge. Looks like a good article.
http://www.kodyaz.com/articles/sql-server-2008-t-sql-merge-statement-example.aspx
If you would like to write a model function to do that then
Leave it for ajax check which is pretty similar to the second
method
Issue "Select username from DB-table" to retrieve
usernames then check the username input against them before
displaying a view to report a problem if any or showing a message to
tell the user that "this name is valid", for example.

How to save a SQL "Select" result in a variable in C#

I'm using Visual C# connected to MySQL for study purposes and I'm stuck in throwing an error to the user when he types a username that already exists.
Current code to put things into the database (it may be useless, once my question may be much more about SQL):
s = new sql(); // This calls a class that works as an adapter to connect form with the database
Conn = s.Connection;
Conn.Open();
coma = Conn.CreateCommand();
coma.CommandText = "INSERT INTO test.test (`user`,`password`) VALUES ('"+username.Text+"','"+password.Text+"');";
coma.ExecuteNonQuery();
What I want to do it compare "username.Text" ("username" is a TextBox) with the values on database's "test" table and, if some value match, evoke a MessageBox.Show("Hey guy, this username is already in use! Try something different)
Some points about your code sample
You want to be sure that you dispose of your connection and command objects. For my answer, I've wrapped them in using statements which will take care of that for me.
You do not want to go to the database with unsanitized inputs. I am going to use parameterized queries in the example.
It's not a good idea to store passwords in plain text. I am not going to demonstrate more secure techniques, just know to look for information about encrypting passwords, salt keys, etc.
And now for some code. In this, I'm using OleDb objects, retrofit to your particular database. And, of course, provide appropriate names to tables, columns, etc.
using (OleDbConnection connection = SomeMethodReturningConnection())
using (OleDbCommand command = SomeMethodReturningCommand())
{
command.Parameters.Add(new OleDbParameter("#username", username));
command.CommandText = "Select Count(*) From Users where Username = #username";
connection.Open();
int output = (int)command.ExecuteScalar();
if (output > 0)
{
// username already exists, provide appropriate action
}
else
{
// perform insert
// note: #username parameter already exists, do not need to add again
command.Parameters.Add(new OleDbParameter("#password", password));
command.CommandText = "Insert Into Users (Username, Password) Values (#username, #password)";
command.ExecuteNonQuery();
}
}
Thank you Anthony! Your answer put me on the right track. Although there is something that the people who will read this post should change from your code in order to get it working with Odbc connectors: the way as parameters are parsed and the way as the textbox content is extracted:
using (OdbcConnection connection = SomeMethodReturningConnection())
using (OdbcCommand command = SomeMethodReturningCommand())
{
command.Parameters.Add(new OdbcParameter("#username", username.Text));
command.CommandText = "Select Count(*) From Users where Username = ?";
connection.Open();
int output = (int)command.ExecuteScalar();
if (output > 0)
{
// username already exists, provide appropriate action
}
else
{
// perform insert
// note: #username parameter already exists, do not need to add again
command.Parameters.Add(new OdbcParameter("#password", password.Text));
command.CommandText = "Insert Into Users (Username, Password) Values (?,?)**";
command.ExecuteNonQuery();
}
}
Thank you anyway!

Categories