Используйте параметризованные 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();

Да, и, как моя стандартная политика, отвечая на вопросы о базах данных с регистрационной информацией, я должен умолять вас, ради любви к Богу и всему святому, солить и хэшировать пароли ваших пользователей.

Другие вопросы по тегам