Используйте параметризованные SQL-запросы, когда SQLCommand используется в отдельном классе.
Мне интересно добавить параметризовать SQL-запросы в моем приложении ASP.net. Я видел несколько хороших статей, касающихся Avoid SQL Injection.
string sql = string.Format("INSERT INTO [UserData] (Username, Password, Role, Membership, DateOfReg) VALUES (@Username, @Password, @Role, @Membership, @DateOfReg)");
SqlCommand cmd = new SqlCommand(sql, conn);
try
{
cmd.Parameters.AddWithValue("Username", usernameTB.Text);
cmd.Parameters.AddWithValue("Password", passwordTB.Text);
cmd.Parameters.AddWithValue("Role", roleTB.Text);
cmd.Parameters.AddWithValue("Membership", membershipTB.Text);
cmd.Parameters.AddWithValue("DateOfReg", dorTB.Text);
conn.Open();
cmd.ExecuteNonQuery();
conn.Close();
Однако этот способ для меня бесполезен, так как я соединяю соединение БД с отдельным классом, так как я использовал его повторно.
public class DBconnection{
public int insertQuery(String query) {
int affectedRowCount = 0;
SqlConnection conn = null;
try{
conn = new SqlConnection("Server=localhost;Database=master;UID=sa;PWD=sa;");
SqlCommand cmd = new SqlCommand( query, conn );
cmd.CommandType = CommandType.Text;
conn.Open( );
affectedRowCount = cmd.ExecuteNonQuery( );
conn.Close( );
} catch ( Exception e ){
String error = e.Message;
}
return affectedRowCount;
}
}
Поэтому я использую только часть кода ниже для вызова выше класса и вставки значений в БД.
String SQLQuery1 = insert into Article values('" + Txtname.Text + "','" + TxtNo.Text + "','" + Txtdescription.Text + "' ,0)");
DBconnection dbConn = new DBconnection();
SqlDataReader Dr = dbConn.insertQuery(SQLQuery1);
Пожалуйста, помогите мне использовать Parameterize sqlString, чтобы избежать меня Sql Injection. Использовать @name, @ No и @description без ввода текстовых полей.
3 ответа
Совершенно разумно сделать это, но попросите ваш класс перезвонить (лямбда / делегат), чтобы получить параметры. Это статический метод в классе, который вызывается различными перегруженными методами экземпляра:
private static int SqlExec(string ConnectionString, string StoredProcName, Action<SqlCommand> AddParameters, Action<SqlCommand> PostExec)
{
int ret;
using (var cn = new SqlConnection(ConnectionString))
using (var cmd = new SqlCommand(StoredProcName, cn))
{
cn.Open();
cmd.CommandType = CommandType.StoredProcedure;
if (AddParameters != null)
{
AddParameters(cmd);
}
ret = cmd.ExecuteNonQuery();
if (PostExec != null)
{
PostExec(cmd);
}
}
return ret;
}
Затем пример использования:
public void Save()
{
Data.Connect().Exec("Project_Update", Cm =>
{
Cm.Parameters.AddWithValue("@ProjectID", ID);
Cm.Parameters.AddWithValue("@PrimaryApplicantID", PrimaryApplicant.IdOrDBNull());
Cm.Parameters.AddWithValue("@SecondaryApplicantID", SecondaryApplicant.IdOrDBNull());
Cm.Parameters.AddWithValue("@ProjectName", ProjectName.ToDBValue());
});
}
Это также возможно сделать с помощью вызовов хранимых процедур.
В вашем случае это будет выглядеть так:
DBconnection.InsertQuery(
"INSERT INTO [UserData]
(Username, Password, Role, Membership, DateOfReg)
VALUES (@Username, @Password, @Role, @Membership, @DateOfReg)"
,cmd => {
cmd.Parameters.AddWithValue("Username", usernameTB.Text);
cmd.Parameters.AddWithValue("Password", passwordTB.Text);
cmd.Parameters.AddWithValue("Role", roleTB.Text);
cmd.Parameters.AddWithValue("Membership", membershipTB.Text);
cmd.Parameters.AddWithValue("DateOfReg", dorTB.Text);
}
);
Это объединяет все ваши базы данных так, как вы хотите, и позволяет DBconnection сохранять свою внутреннюю изоляцию.
Как насчет того, чтобы вместо универсального метода InsertQuery() вы писали конкретные методы InsertQuery?
Например:
public void AddNewUser(User u)
{
var query = "insert Users (name, password) values (@0, @1)";
SqlCommand cmd = new SqlCommand(query, conn);
try
{
cmd.Parameters.AddWithValue("@0", u.UserName);
cmd.Parameters.AddWithValue("@1", u.Password);
}
}
Это имеет преимущество ВСЕХ вашей логики SQL, находящейся в этом другом классе, по сравнению с вызывающим классом, который должен знать, как построить запрос и т. Д.
Это также делает ваш код более читабельным, потому что вы видите AddUser
или же UpdateUser
или же ChangePassword
как вызовы метода, и не нужно читать SQL в этот момент, чтобы попытаться угадать, что происходит в программе.
ОДНАКО, если вы собираетесь сделать что-то подобное, вы должны проверить некоторые MicroORM, мой личный фаворит - PetaPoco (или версия NuGet)
PetaPoco и другие, такие как Massive и Dapper, позволят вам сделать что-то вроде:
database.Insert(u);
Где u - объект User, который отображается в таблицу вашей БД. Он использует ADO.NET и обязательно использует параметры SQL.
Я бы предложил использовать LINQ to SQL, который автоматически все параметризует.
В. Как LINQ to SQL защищен от атак с использованием SQL-инъекций?
A. SQL-инъекция представляет значительный риск для традиционных SQL-запросов, сформированных путем объединения пользовательских данных. LINQ to SQL позволяет избежать такого внедрения, используя SqlParameter в запросах. Пользовательский ввод превращается в значения параметров. Такой подход предотвращает использование вредоносных команд из пользовательского ввода.
Вы можете вставлять, обновлять и удалять из базы данных SQL простым способом, используя DataContext
(щелкните правой кнопкой мыши на своем проекте, чтобы добавить новый элемент и добавить LINQ to SQL Classes
шаблон, а затем использовать обозреватель сервера для добавления объектов к нему).
Я не работал с этим некоторое время, но я считаю, что ваш код будет выглядеть примерно так:
UserData user = new UserData();
user.Username = ...;
user.Password = ...;
user.Role = ...;
user.Membership = ...;
user.DateOfReg = ...;
db.UserDatas.InsertOnSubmit(user);
db.SubmitChanges();
Когда вы вызываете SubmitChanges, LINQ to SQL автоматически генерирует и выполняет команды SQL, необходимые для передачи ваших изменений обратно в базу данных.
Edit1:
Как добавленное примечание, чтобы извлечь существующий элемент из базы данных, вы можете сделать это:
var user = (from i in db.UserDatas
where i.UserName == "devan"
select i).Single();
Да, и, как моя стандартная политика, отвечая на вопросы о базах данных с регистрационной информацией, я должен умолять вас, ради любви к Богу и всему святому, солить и хэшировать пароли ваших пользователей.