Проблема одинарной кавычки ColdFusion с SQL Query

В моем приложении ColdFusion 11 с SQL Server 2008-R2 я использую следующий тег cfquery внутри компонента CF:

<cfquery name="result_set" dataSource="#request.dsn_name#">
    select name, state from myTable #REReplace(where_clause,"''","'","ALL")#        
</cfquery>

Здесь where_clause — переменная. CF заменяет одну одинарную кавычку двумя, поэтому я использую функцию REReplace, чтобы заменить две одинарные кавычки обратно в одну. Итак, мой запрос меняется, например. от

select name, state from myTable WHERE name IN (''ABC'') 

к этому:

 select name, state from myTable WHERE name IN ('ABC') 

Проблема заключается в том, что значение столбца имени также содержит одинарную кавычку. Например.

select name, state from myTable WHERE name IN ('Smith's bat') 

В таких случаях запрос не выполняется. Как я могу решить такие случаи. Я попробовал PreserveSingleQuotes, но возникла та же проблема, что и столбец имеет значения в одинарных кавычках.

ОБНОВЛЕНИЕ

Это приложение было разработано несколько лет назад кем-то, кто использовал ColdFusion MX 7. Первоначальный автор создает динамическую строку для переменной where_clause на основе определенных условий. Это длинный файл cfs с несколькими условиями, используемыми для создания динамической строки для where_clause. Следовательно, использование cfqueryparam может быть либо неприемлемым, либо может потребовать полного пересмотра кода, чего заказчик не допустит.


person nam    schedule 06.11.2015    source источник
comment
Гораздо лучший подход — переписать запрос, чтобы использовать параметры (<cfqueryparam>). Выполнение этого так, как вы это делаете, чрезвычайно подвержено ошибкам и может привести к SQL-инъекция уязвимость.   -  person elixenide    schedule 07.11.2015
comment
... и это причина, по которой у вас возникли проблемы с запросом в первую очередь. Не используйте такой динамический sql. Вместо этого создайте sql внутри cfquery и используйте cfqueryparam для всех параметров (или рассмотрите использование запросов cfscript, которые обеспечивают немного большую гибкость с параметризованным sql). Это защитит базу данных и устранит этот тип ошибок.   -  person Leigh    schedule 07.11.2015
comment
Если вы хотите продолжать создавать свою строку SQL за пределами вызова <cfquery>, используйте вместо этого queryExecute(), что позволит вам поместить заполнители параметров в строку SQL; а затем передать значения параметров в отдельный массив/структуру. Просто не жестко кодируйте значения в строку SQL. Это ужасно, неудобно и опасно.   -  person Adam Cameron    schedule 07.11.2015
comment
@AdamCameron Я добавил раздел ОБНОВЛЕНИЕ в свой исходный пост. Использование cfqueryparam не может быть вариантом в моей ситуации, так как я просто исправляю проблему с одинарными кавычками. И заказчик не позволит переделывать весь файл .cfc.   -  person nam    schedule 07.11.2015
comment
@nam - тот факт, что их БД в настоящее время подвержены очень высокому риску внедрения sql, должен дать им сильную мотивацию. Хотя я уверен, что вы могли бы найти уродливый обходной путь на данный момент, честно говоря, это только продлевает неизбежное и, что более важно, увеличивает риск того, что их БД может быть взломана в то же время...   -  person Leigh    schedule 07.11.2015
comment
Использование cfqueryparam может быть неприемлемым Еще раз взгляните на предложение Адама. Переключение с cfquery на queryExecute устранило бы проблему, позволяя вам по-прежнему использовать динамический sql. Только более чистым и безопасным способом.   -  person Leigh    schedule 07.11.2015
comment
Я поддержу решение @AdamCameron, но если есть условия, препятствующие перезаписи, я просто укажу, что если исходная строка в последнем примере — это WHERE name IN («летучая мышь Смита»), ранее существовавшей разницы между содержимым ' и квалификатор '. Вам нужно было бы решить это в первую очередь, если бы это было так. Можете ли вы привести пример этой строки where_clause в том виде, в каком она передается?   -  person GumbyG    schedule 13.11.2015
comment
Также стоит отметить, что переписать его части для использования queryExecute должно быть намного проще, поскольку он уже поддерживает динамические строки sql (своего рода). Вместо встраивания значений параметров в строку sql используйте маркер параметров и добавляйте значения в отдельный массив. Затем просто вызовите queryExecute(sqlString, parameters) вместо cfquery.   -  person Leigh    schedule 14.11.2015


Ответы (2)


Это неприятная проблема. Боюсь, я могу придумать только неприятное «решение».

  • Замените разделители значений: <cfset where_clause = replace(where_clause, "''", "§§", "ALL")>
  • Затем избегайте фактических одинарных кавычек: <cfset where_clause = replace(where_clause, "'", "\'", "ALL")>
  • Теперь верните замену и нормализуйте разделители: <cfset where_clause = replace(where_clause, "§§", "'", "ALL")>

Складываем вместе:

<cfset substitution = "§§"> <!--- use whatever char sequence works best for your data --->

<!--- fallback in case the substitution is part of your data --->
<cfif where_clause contains substitution>

    <cfset substitution = "°°°">
    <!---
        you can basically start looping through a bunch of alternatives
        or even expand the substition with an additional character
        ...you get the idea
    --->

</cfif>

<cfset where_clause = replace(where_clause, "''", substitution, "ALL")>
<cfset where_clause = replace(where_clause, "'", "\'", "ALL")>
<cfset where_clause = replace(where_clause, substitution, "'", "ALL")>

<cfquery...

Как вы можете видеть, это все еще очень проблематично и может когда-нибудь выйти из строя. Но, вероятно, нет лучшей альтернативы, если вам приходится иметь дело с переменной where_clause.

person Alex    schedule 07.11.2015

Вам нужно использовать функцию PreserveSingleQuotes таким образом:

<cfquery name="result_set" dataSource="#request.dsn_name#">
    select name, state from myTable #PreserveSingleQuotes(REReplace(where_clause,"''","'","ALL"))#        
</cfquery>

Хорошего дня!

person Paulo Teixeira    schedule 10.11.2015
comment
@ПаулоТексейра. Ваше предложение дает ошибку: Complex constructs are not supported with function PreserveSingleQuotes - person nam; 11.11.2015
comment
Распечатайте cfdump вашей строки, чтобы помочь нам понять данные. - person Paulo Teixeira; 11.11.2015
comment
Имейте в виду, что это работает только в том случае, если одинарные кавычки правильно экранированы, а это не так (судя по ОП). Говоря из личного опыта, этот вид динамического sql чрезвычайно подвержен ошибкам и требует королевской боли для отладки ... Не говоря уже о том, что он оставляет базу данных широко открытой для sql-инъекций. Хотя это можно заставить работать, переход на параметризованные запросы является более безопасным и разумным вариантом IMO. - person Leigh; 13.11.2015