Sqlserver
 sql >> база данни >  >> RDS >> Sqlserver

Параметризирайте SQL IN клауза

Можете да параметризирате всеки стойност, така че нещо като:

string[] tags = new string[] { "ruby", "rails", "scruffy", "rubyonrails" };
string cmdText = "SELECT * FROM Tags WHERE Name IN ({0})";

string[] paramNames = tags.Select(
    (s, i) => "@tag" + i.ToString()
).ToArray();

string inClause = string.Join(", ", paramNames);
using (SqlCommand cmd = new SqlCommand(string.Format(cmdText, inClause))) {
    for(int i = 0; i < paramNames.Length; i++) {
       cmd.Parameters.AddWithValue(paramNames[i], tags[i]);
    }
}

Което ще ви даде:

cmd.CommandText = "SELECT * FROM Tags WHERE Name IN (@tag0, @tag1, @tag2, @tag3)"
cmd.Parameters["@tag0"] = "ruby"
cmd.Parameters["@tag1"] = "rails"
cmd.Parameters["@tag2"] = "scruffy"
cmd.Parameters["@tag3"] = "rubyonrails"

Не, това не е отворено за SQL инжекция. Единственият инжектиран текст в CommandText не се основава на въвеждане от потребителя. Той се основава единствено на твърдо кодирания префикс "@tag" и индекса на масив. Индексът ще винаги да бъде цяло число, не е генерирано от потребителя и е безопасно.

Въведените от потребителя стойности все още са напълнени в параметри, така че там няма уязвимост.

Редактиране:

Като оставим настрана проблемите с инжектирането, внимавайте да отбележите, че конструирането на командния текст, за да побере променлив брой параметри (както по-горе) пречи на способността на SQL сървъра да се възползва от кешираните заявки. Нетният резултат е, че почти сигурно губите стойността на използването на параметри на първо място (за разлика от простото вмъкване на предикатни низове в самия SQL).

Не че кешираните планове за заявки не са ценни, но IMO тази заявка не е достатъчно сложна, за да видите голяма полза от нея. Въпреки че разходите за компилация може да се доближат (или дори да надхвърлят) разходите за изпълнение, вие все още говорите за милисекунди.

Ако имате достатъчно RAM, предполагам, че SQL Server вероятно ще кешира и план за общия брой параметри. Предполагам, че винаги можете да добавите пет параметъра и да оставите неопределените тагове да бъдат NULL - планът на заявката трябва да е същият, но ми се струва доста грозен и не съм сигурен, че си струва микрооптимизацията (въпреки че, на Stack Overflow – може много да си струва).

Освен това SQL Server 7 и по-нови версии автоматично параметризират заявките, така че използването на параметри не е необходимо от гледна точка на производителността – обаче е критично от гледна точка на сигурността – особено с въведени от потребителя данни като тази.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Как да премахнете ограничението на външния ключ в базата данни на SQL Server - SQL Server / TSQL урок, част 75

  2. Как да определим дали числото е с плаваща или цяло число

  3. Има ли сериозен спад в производителността при използване на външни ключове в SQL Server?

  4. Как да инсталирате SQL Server на Windows

  5. Какво се случва с идентификатора на първичния ключ, когато надхвърли лимита?