Выражение для SQL WHERE - PullRequest
       5

Выражение для SQL WHERE

2 голосов
/ 15 октября 2008

Для веб-приложения я хочу создать предложение WHERE и отправить его на сервер. Там я добавлю это к запросу. Предложение будет что-то вроде

LASTNAME LIKE 'Pep%' AND (DOB BETWEEN '19600101' AND '19601231 OR SALARY<35000)

Можете ли вы предложить регулярное выражение для проверки предложения перед его отправкой на SQL Server?

(Да, конечно, я хотел бы получить регулярное выражение для предложения ORDER)

Ответы [ 7 ]

16 голосов
/ 15 октября 2008

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

В качестве примера того, что может пойти не так, рассмотрим следующее:

LASTNAME LIKE 'Pep%'--
DROP TABLE People
--

Это добавит команду DROP TABLE в ваш SQL, что будет трудно обнаружить. Конечно, вы можете удалить такие вещи, как - и / *, но я гарантирую, что кто-то может найти выход, если вы сделаете это.

6 голосов
/ 15 октября 2008

Вы не строите

LASTNAME LIKE 'Pep%' AND (DOB BETWEEN '19600101' AND '19601231 OR SALARY<35000)

вы строите

LASTNAME LIKE @LastName AND (DOB BETWEEN @dobStart AND @dobEnd OR SALARY<@MaxSalary)

и передайте этих парней в качестве параметров. Нет регулярных выражений, нет суеты.

2 голосов
/ 15 октября 2008

Несколько других комментаторов обратили внимание на то, что предоставление пользователю ввода для определения синтаксиса SQL является плохой идеей и создало уязвимости внедрения SQL.

Обратите внимание, что комментаторы единодушны в этом мнении и имеют общую репутацию StackOverflow, превышающую 14 000!

Но, оставив в стороне этот пункт, вы спросили, как написать регулярное выражение, соответствующее произвольному синтаксису SQL. Ответ в том, что вы не можете сделать это с помощью регулярных выражений .

«Регулярный» в этом контексте означает, что выражение может соответствовать определенному классу языка ввода, который также может быть представлен детерминированным конечным автоматом (вроде как блок-схема). 1011 *

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

2 голосов
/ 15 октября 2008

Я хочу немного расширить ответ Джимми.

LASTNAME LIKE 'Pep%' 

Это просто ЗЛО . НИКОГДА не делай этого. Вместо этого строка SQL должна выглядеть следующим образом:

LASTNAME LIKE @LastName + '%'

Теперь проблема в том, что в вашем случае вы не знаете, нужно ли вам вообще проверять фамилию. Все, что у вас есть, это предложения SELECT и FROM и текстовое поле для столбца фамилии, которое может иметь или не иметь значение в нем. Хорошо. Это все еще не оправдание для того, чтобы сделать это как в первом примере. Вместо этого вам нужно построить свой запрос следующим образом (используя C #, поскольку вы не указали язык клиента):

//create a place to keep parameters until we can construct the SqlCommand object
List<SqlParameter> params = new List<SqlParameter>();
SqlParameter p;

// the StringBuilder is MUCH more efficient the concatenating strings
// the 1=1 is a placeholder so you can always just append " AND whatever"
StringBuilder sql = new StringBuilder("SELECT ... \nFROM .... \nWHERE 1=1\n");

// Check and add a parameter for the LastName column if needed
if (!String.IsNullOrEmpty(txtLastName.Text))
{
   sql.AppendLine("AND LASTNAME LIKE @LastName + '%'");
   p = new SqlParameter("@LastName", SqlDbType.VarChar, 50);  // use the actual datatype here
   p.Value = txtLastName.Text;
   params.Add(p);      
}

// Check and add a parameter for another field if needed
if (!String.IsNullOrEmpty(txtSomeOtherField.Text))
{
   sql.AppendLine("AND OtherField LIKE @OtherParam + '%'");
   p = new SqlParameter("@OtherParam", SqlDbType.VarChar, 255);
   p.Value = txtSomeOtherField.Text;
   params.Add(p);
}

// ...  You could also write a method to abstract the code in the if blocks ...

// you haven't told us _how_ the user will specify the order, so I'm leaving that implementation detail out for now
sql.Append(" ORDER BY LastName, OtherField");  

// now we can finally get our SQL String and build the (SAFE!) SqlCommand object:
SqlCommand cmd = new SqlCommand(sql.ToString(), YourSqlConnectionObjectHere);
cmd.Parameters.AddRange(params.ToArray());

Теперь у вас есть динамически сгенерированное предложение where без возможности внедрения. Это работает, потому что каждая часть строки, отправляемая в базу данных, является точным литералом в вашем коде, даже если эти литералы собраны за несколько шагов. Значения, используемые в параметрах, никогда не подставляются в строку, а вместо этого отправляются на сервер отдельно в виде данных.

Конечно, это был C # (.Net), но почти на каждой современной платформе есть какая-то особенность параметризованного запроса / подготовленного оператора, которую вы должны использовать.

0 голосов
/ 15 октября 2008

Возможно, вы захотите взглянуть на Дозвуковой . Он предназначен для создания слоя данных для вас и позволяет вам использовать объекты для создания предложений where.

0 голосов
/ 15 октября 2008

Как уже было сказано, регулярное выражение - это не тот инструмент для работы, что вам действительно нужно, это анализатор SQL. Я не знаю ни одного парсера .Net SQL, но уверен, что поиск в Google покажет несколько.

0 голосов
/ 15 октября 2008

Количество возможностей элементов в предложении where огромно. Очевидно, у вас есть списки AND, OR, списки BETWEEN, IN и другие операторы, а также парены, но вы также можете вызывать системные процедуры, пользовательские функции и, в зависимости от СУБД, с которой вы работаете, целые подзапросы. Кроме того, существуют запросы, которые могут быть синтаксически правильными, но по-прежнему незаконными.

Одно регулярное выражение для покрытия этого было бы (а) безумно большим и (б), вероятно, не охватывало бы все случаи. Вы не только на самом деле не хотите этого делать, но это, вероятно, даже невозможно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...