Veracode report is showing a SQL injection flaw for the below query.
private const string DropDatabaseTemplate = #"DROP DATABASE [{0}]";
ExecuteNonQuery(connection, string.Format(DropDatabaseTemplate, databaseName));
private static int ExecuteNonQuery(SqlConnection connection, string commandText)
{
using (var command = new SqlCommand(commandText, connection))
{
return command.ExecuteNonQuery();
}
}
they suggested using parameterized prepared statements.
What would be my approach to remove this security vulnerability
Thanks in advance.
Ans :
You can simply avoid security vulnerability with this
private static void ExecuteNonQuery(SqlConnection connection, string commandText)
{
using (var command = new SqlCommand("exec sp_executesql #sqlCommandText", connection))
{
command.Prepare();
command.Parameters.Add("#sqlCommandText", SqlDbType.NVarChar);
command.Parameters["#sqlCommandText"].Value = commandText;
command.ExecuteNonQuery();
}
}
I've never tried it, but I suspect it will work:
private static void DropDbNamed(SqlConnection connection, string name)
{
using (var command = new SqlCommand("EXEC #q", connection))
{
command.Parameters.AddWithValue("#q", $"DROP DATABASE [{name}]");
var command.ExecuteScalar();
}
}
Note: Joel's standard "stop using AddWithValue" doesn't apply here
How it could look like.
private const string DropDatabaseTemplate = #"DROP DATABASE [{0}]";
private static int ExecuteNonQuery(SqlConnection connection, string commandText)
{
string dbNamesQuery_ = #"SELECT [name]
FROM sys.databases d
WHERE d.database_id > 4";
DataTable tableNames = new DataTable();
using (var command = new SqlCommand(dbNamesQuery_, connection))
{
SqlDataReader dataReader_ = command.ExecuteReader();
tableNames.Load(dataReader_); //allow you dynamically load actual list DB, but you can fill table manually.
//find exactly same name of DB that user requared.
var rowsData_ = tableNames.Select(String.Format("name = '{0}'", commandText));
if (rowsData_.Length == 1) //it will be prevent any kind of injection.
{
command.CommandText = String.Format(DropDatabaseTemplate, commandText);
return command.ExecuteNonQuery();
}
else
{
return -1;
}
}
}
Related
I'm trying to write a function -like Dcount and Dlookup in VBA Access- in a public class to use it everywhere in my project so I did the following :
public class MyTools
{
SqlConnection Cn = new SqlConnection(#"Server = AMR-PC\SQLEXPRESS ; Database=PlanningDB ; Integrated Security = True");
SqlDataAdapter da;
DataTable dt = new DataTable();
// DataView dv = new DataView();
SqlCommand cmd;
SqlDataReader DataRead;
// Variables
string MyColumn, MyTable, MyCondition,DlookResult;
int DcountResult;
// Methods & Functions
// Dcount
public int DCount(string MyColumn, string MyTable, string MyCondition)
{
da = new SqlDataAdapter("Select Count(#MyColumn) from #MyTable where #MyColumn = #MyCondition", Cn);
da.Fill(dt);
DcountResult = int.Parse(dt.Rows[0].ToString());
return DcountResult;
}
}
// Dlookup
}
And tried to use it like this :
int Result = DCount(txtColumn.Text, txtTable.Text, txtCond.Text);
txtResult.Text = null;
txtResult.Text = Result.ToString();
But it throws the error "Must declare the scalar variable "#MyColumn".
I tried to use sqlcommand and DataRead but I need to close the connection after the return and it became Unreachable or close before the return so it returns nothing , That's why i used SqlDataAdapter.
Thanks in advance .
It would have to look something more like this:
public class MyTools
{
private static string ConnectionString {get;} = #"Server = AMR-PC\SQLEXPRESS ; Database=PlanningDB ; Integrated Security = True";
public static int DCount(string MyTable, string MyColumn, string MyCondition)
{
string sql = $"Select Count({MyColumn}) from {MyTable} where {MyColumn} = #MyCondition";
using (var cn = new SqlConnection(ConnectionString))
using (var cmd = new SqlCommand(sql, cn))
{
cmd.Parameters.AddWithValue("#MyCondition", MyCondition);
cn.Open();
return (int)cmd.ExecuteScalar();
}
}
}
Just be aware this uses dynamic SQL, and is more than a little dangerous. In fact, you should not do this. I know you don't want to "keep typing SQL queries", but that might be exactly what you should do.
I have a class file where I declare readonly string of my query to be used in a method. I met the error of
Must declare the scalar variable "#DBID"
May I know if I declare my variables wrongly?
Below are the code snippets:
Class file:
private static readonly string QUERY_GETMATCHEDRECORD = "SELECT [Title], [ItemLink], [RecordDocID] FROM [ERMS].[dbo].[Records] WHERE [ID] = #DBID AND [V1RecordID] = #recID AND [V1RecordDocID] = #recDocID";
public DataTable GetMatchedRecord(string DBID, string recID, string recDocID)
{
string Method = System.Reflection.MethodBase.GetCurrentMethod().Name;
DataTable dt = new DataTable();
try
{
using (DB db = new DB(_datasource, _initialCatalog))
{
db.OpenConnection();
using (SqlCommand command = new SqlCommand())
{
string commandText = QUERY_GETMATCHEDRECORD .FormatWith(DBID,recID,recDocID);
_log.LogDebug(Method, "Command|{0}".FormatWith(commandText));
command.CommandText = commandText;
dt = db.ExecuteDataTable(command);
}
db.CloseConnection();
}
}
catch (Exception ex)
{
_log.LogError(Method, "Error while retrieving matching records |{0}".FormatWith(ex.Message));
_log.LogError(ex);
}
return dt;
}
Program .cs file:
MatchedRecords = oDB.GetMatchedRecord(DBID, RecID, RecDocID);
using '#'-notated variables will only work if you add the parameters to the commands parameter-collection.
try the following:
using (DB db = new DB(_datasource, _initialCatalog))
{
db.OpenConnection();
using (SqlCommand command = new SqlCommand())
{
command.CommandText = QUERY_GETMATCHEDRECORD;
command.Parameters.AddWithValue("#DBID", DBID);
command.Parameters.AddWithValue("#recID", recID);
command.Parameters.AddWithValue("#recDocID",recDocID);
dt = db.ExecuteDataTable(command);
}
db.CloseConnection();
}
Is the code below implementing the secure way to retrieve the data from database?
help me please, I don't understand about SQL Injection. Someone told me this code can easily get injected. If yes, can somebody explain it? Thank you.
public int CheckID(string column, string table, string wheres)
{
int i = 0;
sqlcon = ConnectToMain();
string sqlquery = "SELECT "+column+" FROM "+table+" "+wheres+"";
using (sqlcon)
{
sqlcon.Open();
SqlCommand sqlcom = new SqlCommand(sqlquery, sqlcon);
using (sqlcom)
{
SqlDataReader dr = sqlcom.ExecuteReader();
dr.Read();
if (dr.HasRows)
{
i = dr.GetInt32(0);
}
else
{
i = 0;
}
}
sqlcon.Close();
}
return i;
}
This code has far too many problems.
Table, column and criteria are passed as strings and concatenated, which means that the code is prone to SQL injection.
Database details like table, column criteria are spilled into the function's caller. Are you going to use this method to query anything other than a Visitor table?
A reader is used when only a single value is wanted.
The connection is created outside the using block and stored in a field.
This is definitelly a memory leak and probably a connection leak as well. Just create the connection locally.
A simple command call fixes all of these problems:
public int CheckIDVisitor(visitorName)
{
string query = "SELECT ID FROM Visitors where Name=#name";
using (var sqlConn=new SqlConnection(Properties.Default.MyDbConnectionString))
using( var cmd=new SqlCommand(query,sqlConn))
{
var cmdParam=cmd.Parameters.Add("#name",SqlDbType.NVarChar,20);
cmdParam.Value=visitorName;
sqlConn.Open();
var result=(int?)cmd.ExecuteScalar();
return result??0;
}
}
You could also create the command in advance and store it in a field. You can attach the connection to the command each time you want to execute it:
public void InitVisitorCommand()
{
string query = "SELECT ID FROM Visitors where Name=#name";
var cmd=new SqlCommand(query,sqlConn);
var cmdParam=cmd.Parameters.Add("#name",SqlDbType.NVarChar,20);
_myVisitorCommand=cmd;
}
...
public int CheckIDVisitor(visitorName)
{
using (var sqlConn=new SqlConnection(Properties.Default.MyDbConnectionString))
{
_myVisitorCommand.Parameters.["#name"]Value=visitorName;
_myVisitorCommand.Connection=sqlConn;
sqlConn.Open();
var result=(int?)cmd.ExecuteScalar();
return result??0;
}
}
An even better option would be to use a micro-ORM like Dapper.Net to get rid of all this code:
public int CheckIDVisitor(visitorName)
{
using (var sqlConn=new SqlConnection(Properties.Default.MyDbConnectionString))
{
string sql = "SELECT ID FROM Visitors WHERE name=#name"
var result = conn.Query<int?>(sql, new { name = visitorName);
return result??0;
}
}
Or
public int[] CheckIDVisitors(string []visitors)
{
using (var sqlConn=new SqlConnection(Properties.Default.MyDbConnectionString))
{
string sql = "SELECT ID FROM Visitors WHERE name IN #names"
var results = conn.Query<int?>(sql, new { names = visitors);
return results.ToArray();
}
}
I tried below code for cheking SP is alredy exist or not. if not exist i am creating..
But every time it is showing sp is not created.....But my database already have this sp.
Let me know where i am doing mistake.
string checkSP = String.Format(
"IF OBJECT_ID('{0}', 'U') IS NOT NULL SELECT 'true' ELSE SELECT 'false'",
"GP_SOP_AdjustTax");
SqlCommand command = new SqlCommand(checkSP, myConnection);
command.CommandType = CommandType.Text;
if (myConnection == null || myConnection.State == ConnectionState.Closed)
{
try
{
myConnection.Open();
}
catch (Exception a)
{
MessageBox.Show("Error " + a.Message);
}
}
bool Exist = false;
Exist = Convert.ToBoolean(command.ExecuteScalar());
if (Exist == false) //false : SP does not exist
{
// here i am writing code for creating SP
}
Try:
if exists(select * from sys.objects where type = 'p' and name = '<procedure name>' )
Also you can check that with c#:
string connString = "";
string query = "select * from sysobjects where type='P' and name='MyStoredProcedureName'";
bool spExists = false;
using (SqlConnection conn = new SqlConnection(connString))
{
conn.Open();
using (SqlCommand command = new SqlCommand(query, conn))
{
using (SqlDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
spExists = true;
break;
}
}
}
}
For those who use Entity Framework and a DbContext:
create an extension class for DbContext:
internal static class DbContextExtensions
{
public static bool StoredProcedureExists(this DbContext context,
string procedureName)
{
string query = String.Format(
#"select top 1 from sys.procedures " +
"where [type_desc] = '{0}'", procedureName);
return dbContext.Database.SqlQuery<string>(query).Any();
}
}
As robIII remarked, this code should not be published to the outside world as it makes the database vulnerable for hackers (thank you RobIII!). To prevent this use a parameterized statement. The problem with the above mentioned method is described here
The solution is to put procedureName as a parameter in an SQL statement. SQL will check if the string parameter has the desired format, thus inhibiting malicious calls:
public static bool ImprovedExists(this DbContext dbContext, string procedureName)
{
object[] functionParameters = new object[]
{
new SqlParameter(#"procedurename", procedureName),
};
const string query = #"select [name] from sys.procedures where name= #procedurename";
return dbContext.Database.SqlQuery<string>(query, functionParameters).Any();
}
I found this on MSDN
select * from sys.objects where type_desc = 'SQL_STORED_PROCEDURE' AND name = 'Sql_PersonInsert'
Try:
SELECT *
FROM sys.objects
WHERE object_id = OBJECT_ID(N'GP_SOP_AdjustTax') AND type in (N'P', N'PC')
My stab at it:
Reusable extension method
Minimal Sql / Minimal C#
Called from .Net as the OP implicitly requested
Could be faster because of the object_id function
public static bool StoredProcedureExists(this string source)
{
using (var conn = new SqlConnection(ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString))
{
conn.Open();
using (var cmd = new SqlCommand($"select object_id('{source}')", conn))
return !cmd.ExecuteScalar().ToString().IsNullOrWhiteSpace();
}
}
You can check with following tsql query (suitable for SQL Server):
select * from sysobjects where ytype='P' and name='MyStoredProcedureName'
If query returns row then stored procedure named 'MyStoredProcedureName' exists.
And here is how you can use it in code:
//TODO: set connection string
string connString = "";
string query = "select * from sysobjects where ytype='P' and name='MyStoredProcedureName'";
bool spExists = false;
using (SqlConnection conn = new SqlConnection(connString))
{
conn.Open();
using (SqlCommand command = new SqlCommand(query,conn))
{
using (SqlDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
spExists = true;
break;
}
}
}
}
string checkSP = String.Format(
"IF OBJECT_ID('{0}', 'U') IS NOT NULL SELECT 'true' ELSE SELECT 'false'",
"GP_SOP_AdjustTax");
is fine if you change the 'U' to 'P'.
With 'U' you query for user-tables, where 'P' gives you stored-procedures.
private static bool StoredProcedureExists(string sp)
{
var connString = #"<your string here>";
var query = string.Format("SELECT COUNT(0) FROM INFORMATION_SCHEMA.ROUTINES WHERE ROUTINE_NAME = '{0}'", sp);
using (var conn = new SqlConnection(connString))
{
conn.Open();
using (var cmd = new SqlCommand(query, conn))
{
return Convert.ToInt32(cmd.ExecuteScalar()) > 0;
}
}
}
Handles procedure names with different schemas
Names with and without brackets ([])
Uses parameter to avoid SQL injection
Note: Caller owns SQL Connection
public static class SqlConnectionExtensions
{
public static Task<bool> StoredProcedureExistsAsync(this SqlConnection sqlConnection, string storedProcedureName)
{
string query = "SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(#storedProcedureName) AND type in (N'P', N'PC')";
using (SqlCommand command = new SqlCommand(query, sqlConnection))
{
command.Parameters.AddWithValue("#storedProcedureName", storedProcedureName);
using (SqlDataReader reader = command.ExecuteReader())
{
return reader.ReadAsync();
}
}
}
}
The following works with MySQL, SQL Server, and Oracle I think:
SELECT * FROM INFORMATION_SCHEMA.ROUTINES
WHERE ROUTINE_TYPE='PROCEDURE'
AND (ROUTINE_SCHEMA='questionnaire' OR ROUTINE_CATALOG = 'questionnaire')
AND SPECIFIC_NAME='create_question';
Usage:
string procedureName = "create_question";
using (DbConnection conn = new SqlConnection("Server=localhost;Database=questionnaire;Trusted_Connection=True;")) // Connection is interchangeable
{
conn.Open();
using (var cmd = conn.CreateCommand())
{
cmd.CommandText = $"SELECT * FROM INFORMATION_SCHEMA.ROUTINES WHERE ROUTINE_TYPE='PROCEDURE' AND (ROUTINE_SCHEMA='{conn.Database}' OR ROUTINE_CATALOG = '{conn.Database}') AND SPECIFIC_NAME='{procedureName}';";
return cmd.ExecuteScalar() != null;
}
}
If you use Microsoft.SqlServer.Management.Smo, try
private static bool CheckIfStoredProcedureExists(Database db, string spName, string schema)
{
db.StoredProcedures.Refresh();
return (db.StoredProcedures[spName, schema] != null);
}
Try this;
if object_id('YourStoredProcedureName') is null
exec ('create procedure dbo.YourSp as select 1')
go
alter procedure dbo.YourStoredProcedure
as
i have a php code.here is the code,i gonna to translate it to .NET but in some point i'm getting some trouble.
function processInput($conn, $MessageArray, $mobilenumber, $date, $odd)
{
$strSQLUSER="SELECT * FROM tbl_tiduser WHERE username='".addslashes($MessageArray[0])."' AND stat!='1' AND stat!='4'";
$result_user=odbc_exec($conn,$strSQLUSER) or die("Could not connect to database");
here is the converted .NET code
public class ProcessInput
{
private string msg_arr;
private string MooseSeenInput(string MobileNo,string Date,string odd,params Array[] msg_arr)
{
SqlCommand com = new SqlCommand("SELECT * FROM tbl_tiduser WHERE username=#username AND stat!='1' AND stat!='4'", mycon);
com.Parameters.AddWithValue("#username",username);
using (SqlDataReader reader = com.ExecuteReader())
// whats the next part need to come here ???
}
this is incomplete.i'm not going to compile it....
private static void ReadOrderData(string connectionString)
{
string queryString =
"SELECT OrderID, CustomerID FROM dbo.Orders;";
using (SqlConnection connection =
new SqlConnection(connectionString))
{
SqlCommand command =
new SqlCommand(queryString, connection);
connection.Open();
SqlDataReader reader = command.ExecuteReader();
// Call Read before accessing data.
while (reader.Read())
{
Console.WriteLine(String.Format("{0}, {1}",
reader[0], reader[1]));
}
// Call Close when done reading.
reader.Close();
}
}
http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqldatareader.aspx
I would use something like this to get the column(s) you're after:
string username = null;
using (SqlDataReader reader = com.ExecuteReader()) {
if (reader.read()) {
username = (string)reader["mydbcolumnname"];
}
reader.Close();
}
Note that if you want to pull all the result rows (as opposed to stepping through them) then you'd normally use a SqlDataAdapter to fill a DataSet (instead of the reader), eg:
string username;
using (SqlDataAdapter adapter = new SqlDataAdapter(com))
{
using (DataSet ds)
{
adapter.Fill(ds);
username = (string)ds.Tables[0].Rows[0]["mycolumnname"];
}
}
I'm all for easy; I would write a class that mirrors the record I'm reading, i.e.
public class User {
public int Id {get;set;}
public string Name {get;set;}
}
and use "dapper":
var user = myCon.Query<User>(
"SELECT * FROM tbl_tiduser WHERE username=#username AND stat not in ('1','4')",
new {username}).SingleOrDefault();
if(user == null) { /* not found, presumably throw an exception */ }
string name = user.Name; // etc
Then you don't need to mess with commands, readers, parameters etc (see how the username is being made into a db parameter cleanly?).