параметризованные запросы против SQL-инъекций
Я новичок в Asp.net, и я только начинаю работать с classами. Недавно я создал class, который будет обрабатывать большинство моих SQL-запросов для меня, чтобы мне не приходилось многократно создавать новые подключения по всем моим файлам.
Один из методов, которые я создал, принимает SQL-запрос в качестве параметра и возвращает результат. Я знаю, что я должен использовать параметризованные запросы, чтобы избежать инъекций SQL. Мой вопрос в том, как я могу это сделать, когда передаю запрос как строковый параметр?
Например, вот метод, который я буду называть:
- Передача только типа параметра в C #
- Измененный массив в области файлов
- Общий список - перемещение элемента в списке
- Как delete знает, что это массив?
- Какова механика оптимизации коротких строк в libc ++?
public static DataTable SqlDataTable(string sql) { using (SqlConnection conn = new SqlConnection(DatabaseConnectionString)) { SqlCommand cmd = new SqlCommand(sql, conn); cmd.Connection.Open(); DataTable TempTable = new DataTable(); TempTable.Load(cmd.ExecuteReader()); return TempTable; } }
Поэтому из другого файла я бы хотел использовать этот метод следующим образом:
DataTable dt = new DataTable(); dt = SqlComm.SqlDataTable("SELECT * FROM Users WHERE UserName='" + login.Text + "' and Password='" + password.Text + "'"); if (dt.Rows.Count > 0) { // do something if the query returns rows }
Это работает, но все равно будет уязвимым для инъекций? Есть ли способ передать переменные в строку в качестве параметров? Я знаю, что могу сделать это, если я создам новый объект SQLCommand для запроса и использую Parameters.AddWithValue, но я хотел, чтобы все мои команды SQL были в отдельном classе.
- multimap в .NET.
- C: время ожидания подключения сокета
- Как подключиться к GetWindowLongPtr и SetWindowLongPtr на 32-битных платформах?
- Загрузка пользовательских файлов конфигурации
- что означает преобразовать int в void * или наоборот?
- Посмотрите, вызван ли метод внутри метода с использованием отражения
- Как скопировать данные в буфер обмена в C #
- Событие, которое срабатывает во время DataGridViewComboBoxColumn SelectedIndexChanged
Это работает, но все равно будет уязвимым для инъекций?
Да, ваш код ужасно уязвим для SQL-инъекций.
Я знаю, что я должен использовать параметризованные запросы, чтобы избежать инъекций SQL.
Ах, да.
Мой вопрос в том, как я могу это сделать, когда передаю запрос как строковый параметр?
Вы просто не должны передавать запрос как строковый параметр. Вместо этого вы должны передавать запрос как строковый параметр, содержащий заполнители и значения для этих заполнителей:
public static DataTable SqlDataTable(string sql, IDictionary values) { using (SqlConnection conn = new SqlConnection(DatabaseConnectionString)) using (SqlCommand cmd = conn.CreateCommand()) { conn.Open(); cmd.CommandText = sql; foreach (KeyValuePair item in values) { cmd.Parameters.AddWithValue("@" + item.Key, item.Value); } DataTable table = new DataTable(); using (var reader = cmd.ExecuteReader()) { table.Load(reader); return table; } } }
а затем используйте свою функцию следующим образом:
DataTable dt = SqlComm.SqlDataTable( "SELECT * FROM Users WHERE UserName = @UserName AND Password = @Password", new Dictionary { { "UserName", login.Text }, { "Password", password.Text }, } ); if (dt.Rows.Count > 0) { // do something if the query returns rows }
То, что вы пытаетесь сделать, имеет прекрасный логический смысл, и я могу понять, почему вы пришли к этой реализации. Однако то, что вы пытаетесь сделать, очень опасно и, будучи новичком в ASP.NET, возможно, вам не известно, что есть множество других доступных вам вариантов, которые упрощают и значительно упрощают управление вашими данными.
@iamkrillin намекнул на одну из таких технологий – Object Relational Mapping (ORM). У платформы .NET действительно есть поддержка первого classа для ORM, называемого Entity Framework . Я считаю, что причина, по которой он предположил, что вы заглядываете в ORM, заключается в том, что ваш дизайн на самом деле очень похож на принцип работы ORM. Они являются абстрагированными classами, которые представляют таблицы в вашей базе данных, которые можно легко запросить с помощью LINQ. Запросы LINQ автоматически параметризуются и избавляют вас от стресса в управлении безопасностью ваших запросов. Они генерируют SQL «на лету» (так же, как вы передаете строки вашему classу доступа к данным), и намного более гибки в том, как они могут возвращать данные (массивы, списки, вы называете это).
Однако один из недостатков ORM заключается в том, что они имеют довольно крутые кривые обучения. Более простой вариант (хотя и немного старше EF) заключается в использовании Typed Datasets. Типизированные наборы данных намного проще создавать, чем создавать ORM и, как правило, намного проще реализовать. Хотя они не так гибки, как ORM, они выполняют именно то, что вы пытаетесь сделать в простой, безопасной и уже решенной манере. К счастью, когда ASP.NET впервые выпустила обучающие видеоролики, ориентированные в основном на типизированные наборы данных, и как таковые, есть множество высококачественных свободно доступных видео / учебников, которые помогут вам быстро и быстро.
Вы на правильном пути, и я действительно сделал то, что вы тоже ищете. Однако вместо того, чтобы просто передавать строку в вашу функцию, я передаю объект SQL Command … Таким образом, вы можете правильно построить все свои команды и параметры, а затем сказать … здесь, запустите это, это готов к работе. Что-то вроде
public static DataTable SqlDataTable(SqlCommand cmd) { using (SqlConnection conn = new SqlConnection(DatabaseConnectionString)) { cmd.Connection = conn; // store your connection to the command object.. cmd.Connection.Open(); DataTable TempTable = new DataTable(); TempTable.Load(cmd.ExecuteReader()); return TempTable; } } public DataTable GetMyCustomers(string likeName) { SqlCommand cmd = new SqlCommand(); cmd.CommandText = "select * from SomeTable where LastName like "@someParm%"; cmd.Parameters.Add( "whateverParm", likeName ); // don't have SQL with me now, guessing syntax // so now your SQL Command is all built with parameters and ready to go. return SqlDataTable( cmd ); }
Мое предложение: используйте орму. Есть много вариантов отныне дней