Как вы используете cfqueryparam в предложении ORDER BY? - PullRequest
7 голосов
/ 20 мая 2009

Я пытаюсь быть хорошим веб-разработчиком CF и использую <cfqueryparam> вокруг всех элементов FORM или URL, которые соответствуют моим запросам SQL.

В этом случае я пытаюсь разрешить пользователю динамически управлять предложением ORDER BY.

<cfquery datasource="MyDSN" name="qIncidents">
  SELECT IncidentID, AnimalID, IntakeDate, DxDate, OutcomeDate
  FROM Incidents
  WHERE ShelterID = <cfqueryparam cfsqltype="cf_sql_integer" value="#Arguments.ShelterID#">
  ORDER BY <cfqueryparam cfsqltype="cf_sql_varchar" value="#SortBy#">
</cfquery>

Когда я это делаю, я получаю следующую ошибку:

Элемент SELECT, определенный номером 1 ORDER BY, содержит переменную как часть выражения, идентифицирующую позицию столбца. Переменные допускаются только при упорядочении по выражению, ссылающемуся на имя столбца.

Любые предложения о том, как сделать это безопасно?

Ответы [ 5 ]

12 голосов
/ 20 мая 2009

К сожалению, вы не можете использовать CFQUERYPARAM непосредственно в предложении Order By.

Если вы хотите использовать Order By динамически, но при этом делать это безопасно, вы можете настроить CFSWITCH или аналогичную структуру для изменения переменной SortBy в зависимости от некоторого условия (например, переменной URL). Как всегда, не передавайте никаких значений непосредственно от пользователя, просто посмотрите на ввод пользователя и выберите из заранее определенного списка возможных значений, основанных на этом. Затем просто используйте стандартный синтаксис:

ORDER BY #SortBy#
4 голосов
/ 21 мая 2009

Я просто уточню ответ Аарона. Одна из вещей, которые я делаю, - это использование listfindnocase (), чтобы убедиться, что аргументы, переданные в order by, действительны:

<cfset variables.safeSortColumn = "name">
<cfset variables.safeSortOrder = "desc">

<cfparam name="url.sortcolumn" type="string" default="#variables.safeSortColumn#">
<cfparam name="url.sortorder" type="string" default="#variables.safeSortOrder#">

<cfif listfindnocase("name,age,address", url.sortcolumn)>
    <cfset variables.safeSortColumn = url.sortcolumn>
</cfif>

<cfif listfindnocase("desc,asc", url.sortorder)>
    <cfset variables.safeSortOrder = url.sortorder>
</cfif>

<cfquery>
select *
from mytable
order by #variables.safeSortcolumn# #variables.safeSortorder#
</cfquery>
2 голосов
/ 21 мая 2009

проблема с использованием порядкового значения для ссылки на столбец состоит в том, что это (я полагаю) порядковое значение во время выполнения оператора SQL создания таблицы - так, как вы добавляете столбцы в таблицу базы данных с течением времени, инструмент GUI вы используете для отображения столбцов может не представлять его фактическое порядковое значение. я бы действительно избежал использования cfqueryparam для этого.

Мне нравится идея использовать число в переменных запроса (url, form), чтобы указать, по какому столбцу сортировать, а затем использовать его в коммутаторе и преобразовать его в фактическое имя столбца, чтобы вы не выставляли свой столбец. имена для пользователя.

Что касается того, когда / зачем использовать cfqueryparam, имейте в виду, что он НЕ только для проверки ввода и предотвращения внедрения SQL (хотя это очень приятный бонус) - с помощью cfqueryparam базовый SQL в базу данных отправляется обратно через драйвер используя переменные связывания SQL - значения местозаполнителя, поэтому оптимизатор базы данных может определить, какой индекс использовать в более общем формате ... поэтому, когда вы отправляете инструкцию SQL следующим образом: SELECT * FROM product WHERE ID = 1 и SELECT * FROM product WHERE ID = 2 оптимизатор работает оба раза. но с переменными связывания SQL выглядит так: SELECT * FROM product WHERE ID =? (? = 1) и ВЫБРАТЬ * ИЗ ПРОДУКТА, ГДЕ ID =? (? = 2), поэтому оптимизатор может использовать кэшированные результаты первого анализа, чтобы точно знать, какой индекс использовать во втором запросе. в зависимости от сложности SQL и базы данных это может быть ОГРОМНОЙ экономией времени. По моему опыту, это очень полезно для производительности с колонками оракула и даты / времени в предложении where.

что касается того, где использовать cfqueryparam, то где можно использовать переменную связывания SQL ...

НТН джон

0 голосов
/ 25 июня 2009

Думаю, я бы скинул меньший код на эту проблему:

<cfset sortColumns = {IncidentID = "IncidentID", AnimalID = "AnimalID", IntakeDate = "IntakeDate", DxDate = "DxDate", OutcomeDate = "OutcomeDate"}>
<cfset sortDirections = {ASC = "ASC", DESC = "DESC"}>

<cfquery datasource="MyDSN" name="qIncidents">
    SELECT IncidentID, AnimalID, IntakeDate, DxDate, OutcomeDate
    FROM Incidents
    WHERE ShelterID = <cfqueryparam cfsqltype="cf_sql_integer" value="#Arguments.ShelterID#">
    ORDER BY #sortColumns[sortBy]# #sortDirections[sortDirection]#
</cfquery>

Где sortBy и sortDirection входят через URL или где-либо еще.

Мне это нравится, потому что он чистый, и вы ничего не можете ввести через предложение ORDER BY.

Есть комментарии?

0 голосов
/ 21 мая 2009

Относительно комментария об использовании "cfqueryparam в предложении порядка хорошо с MySQL". Да, я считаю, что это разрешено с источниками данных MySQL. Хотя используется столбец ordinal , а не имя столбца (которое вместо этого представляется как постоянная строка).

К сожалению, он не работает вообще для источников данных MS SQL. По крайней мере, не из того, что я могу сказать.

<!--- this works --->
<cfset url.sortColumnNumber = "3">
<cfquery name="getDataByPosition" datasource="MySQLDSN">
   SELECT  RecordID, ProductName, DateAdded
   FROM TestTable
   ORDER BY <cfqueryparam value="#url.sortColumnNumber#" cfsqltype="cf_sql_integer"> ASC
</cfquery>
<cfdump var="#getDataByPosition#">

<!--- this does NOT work --->
<cfset url.sortColumnName = "DateAdded">
<cfquery name="getDataByName" datasource="MySQLDSN">
   SELECT  RecordID, ProductName, DateAdded
   FROM    TestTable
   ORDER BY <cfqueryparam value="DateAdded" cfsqltype="cf_sql_varchar"> ASC
</cfquery>
<cfdump var="#getDataByName#">

Обновление: Что касается комментариев по порядковому номеру: Нет, я полагаю, что это относится к позиции столбца в списке выбора, а не к базовой таблице. Так должно быть хорошо.

Да, я согласен, защита от инъекций sql не является основной целью cfqueryparam. Поэтому описание переменных связывания было хорошим дополнением.

...