Like (transact-sql)like (transact-sql)
Содержание:
- Example — Using % Wildcard in the LIKE Condition
- Описание
- Пример сопоставления несколько альтернатив.
- SQL Учебник
- Frequently Asked Questions
- SQL Справочник
- SQL LIKE
- What Is Escaping?
- Пример
- Типы возвращаемых данныхReturn Types
- ПримерыExamples
- Пример с числами
- Example — Using Escape Characters with the LIKE Condition
- Неэффективные способы защиты от SQL-инъекций
Example — Using % Wildcard in the LIKE Condition
Let’s explain how the wildcard works in the SQL LIKE condition. Remember that the wildcard matches any string of any length (including zero length).
In this first example, we want to find all of the records in the customers table where the customer’s last_name begins with ‘J’.
In this example, we have a table called customers with the following data:
customer_id | last_name | first_name | favorite_website |
---|---|---|---|
4000 | Jackson | Joe | techonthenet.com |
5000 | Smith | Jane | digminecraft.com |
6000 | Ferguson | Samantha | bigactivities.com |
7000 | Reynolds | Allen | checkyourmath.com |
8000 | Anderson | Paige | NULL |
9000 | Johnson | Derek | techonthenet.com |
Enter the following SQL statement:
Try It
SELECT * FROM customers WHERE last_name LIKE 'J%' ORDER BY last_name;
There will be 2 records selected. These are the results that you should see:
customer_id | last_name | first_name | favorite_website |
---|---|---|---|
4000 | Jackson | Joe | techonthenet.com |
9000 | Johnson | Derek | techonthenet.com |
This example returns the records in the customers table where the last_name starts with ‘J’. As you can see, the records for the last names Jackson and Johnson have been returned.
Because the LIKE condition is not case-sensitive, the following SQL statement would return the same results:
Try It
SELECT * FROM customers WHERE last_name LIKE 'j%' ORDER BY last_name;
Using Multiple Wildcards in the LIKE Condition
You can also using the wildcard multiple times with the LIKE condition.
Using the same customers table with the following data:
customer_id | last_name | first_name | favorite_website |
---|---|---|---|
4000 | Jackson | Joe | techonthenet.com |
5000 | Smith | Jane | digminecraft.com |
6000 | Ferguson | Samantha | bigactivities.com |
7000 | Reynolds | Allen | checkyourmath.com |
8000 | Anderson | Paige | NULL |
9000 | Johnson | Derek | techonthenet.com |
Let’s try to find all last_name values from the customers table where the last_name contains the letter ‘e’. Enter the following SQL statement:
Try It
SELECT last_name FROM customers WHERE last_name LIKE '%e%' ORDER BY last_name;
There will be 3 records selected. These are the results that you should see:
last_name |
---|
Anderson |
Ferguson |
Reynolds |
Описание
Отличное описание приведено в статье на habrahabr.ru :
SQL инъекция — это атака на базу данных, которая позволит выполнить некоторое действие, которое не планировалось создателем скрипта. Пример из жизни:
Отец, написал в записке маме, чтобы она дала Васе 100 рублей и положил её на стол. Переработав это в шуточный SQL язык, мы получим:
ДОСТАНЬ ИЗ кошелька 100 РУБЛЕЙ И ДАЙ ИХ Васе
Так-как отец плохо написал записку (Корявый почерк), и оставил её на столе, её увидел брат Васи — Петя. Петя, будучи хакер, дописал там «ИЛИ Пете» и получился такой запрос:
ДОСТАНЬ ИЗ кошелька 100 РУБЛЕЙ И ДАЙ ИХ Васе ИЛИ Пете
Мама прочитав записку, решила, что Васе она давала деньги вчера и дала 100 рублей Пете. Вот простой пример SQL инъекции из жизни 🙂 Не фильтруя данные (Мама еле разобрала почерк), Петя добился профита.
А теперь рассмотрим реальный пример, взятый с ru.wikipedia.org .
Допустим, серверное ПО, получив входной параметр id, использует его для создания SQL-запроса. Рассмотрим следующий PHP-скрипт:
# Предыдущий код скрипта... $id = $_REQUEST'id'; $res = mysql_query("SELECT * FROM news WHERE id_news =".$id); # Следующий код скрипта...
Если на сервер передан параметр id, равный 5 ( например так: http://example.org/script.php?id=5 ), то выполнится следующий SQL-запрос:
SELECT * FROM news WHERE id_news = 5
Но если злоумышленник передаст в качестве параметра id строку (например, так: http://example.org/script.php?id=-1+OR+1=1 ), то выполнится запрос:
SELECT * FROM news WHERE id_news = -1 OR 1=1
Таким образом, изменение входных параметров путём добавления в них конструкций языка SQL вызывает изменение в логике выполнения SQL-запроса (в данном примере вместо новости с заданным идентификатором будут выбраны все имеющиеся в базе новости, поскольку выражение 1=1 всегда истинно — вычисления происходят по кратчайшему контуру в схеме
Пример сопоставления несколько альтернатив.
Следующий пример, который мы рассмотрим, включает использование | шаблон. | шаблон используется как «ИЛИ», чтобы указать несколько альтернатив. Например:
Oracle PL/SQL
SELECT REGEXP_SUBSTR (‘AeroSmith’, ‘a|e|i|o|u’)
FROM dual;
—Результат: ‘e’
1 2 3 |
SELECTREGEXP_SUBSTR(‘AeroSmith’,’a|e|i|o|u’) FROMdual; |
Этот пример вернет ‘e’, потому что он ищет первую гласную (a, e, i, o или u) в строке. Поскольку мы не указали значение match_parameter, функция REGEXP_SUBSTR выполнит поиск с учетом регистра, что означает, что ‘A’ в ‘AeroSmith’ сопоставляться не будет.
Чтобы выполнить поиск без учета регистра изменим наш запрос следующим образом:
Oracle PL/SQL
SELECT REGEXP_SUBSTR (‘AeroSmith’, ‘a|e|i|o|u’, 1, 1, ‘i’)
FROM dual;
—Результат: ‘A’
1 2 3 4 |
SELECTREGEXP_SUBSTR(‘AeroSmith’,’a|e|i|o|u’,1,1,’i’) FROMdual; |
Теперь, поскольку мы предоставили match_parameter = ‘i’, запрос в качестве результата вернет ‘A’. На этот раз ‘A’ в ‘AeroSmith’ будет сопоставляться.
Теперь рассмотри, как вы будете использовать эту функцию со столбцом. Итак, допустим, у нас есть таблица contact со следующими данными:
contact_id | last_name |
---|---|
1000 | AeroSmith |
2000 | Joy |
3000 | Scorpions |
Теперь давайте запустим следующий запрос:
Oracle PL/SQL
SELECT contact_id, last_name, REGEXP_SUBSTR (last_name, ‘a|e|i|o|u’, 1, 1, ‘i’) AS «First Vowel»
FROM contacts;
1 2 |
SELECTcontact_id,last_name,REGEXP_SUBSTR(last_name,’a|e|i|o|u’,1,1,’i’)AS»First Vowel» FROMcontacts; |
Результаты, которые будут возвращены запросом:
contact_id | last_name | First Vowel |
---|---|---|
1000 | AeroSmith | A |
2000 | Joy | o |
3000 | Scorpions | o |
SQL Учебник
SQL ГлавнаяSQL ВведениеSQL СинтаксисSQL SELECTSQL SELECT DISTINCTSQL WHERESQL AND, OR, NOTSQL ORDER BYSQL INSERT INTOSQL Значение NullSQL Инструкция UPDATESQL Инструкция DELETESQL SELECT TOPSQL MIN() и MAX()SQL COUNT(), AVG() и …SQL Оператор LIKESQL ПодстановочныйSQL Оператор INSQL Оператор BETWEENSQL ПсевдонимыSQL JOINSQL JOIN ВнутриSQL JOIN СлеваSQL JOIN СправаSQL JOIN ПолноеSQL JOIN СамSQL Оператор UNIONSQL GROUP BYSQL HAVINGSQL Оператор ExistsSQL Операторы Any, AllSQL SELECT INTOSQL INSERT INTO SELECTSQL Инструкция CASESQL Функции NULLSQL ХранимаяSQL Комментарии
Frequently Asked Questions
Question: How do you incorporate the Oracle UPPER function with the SQL LIKE condition? I’m trying to query against a free text field for all records containing the word «test». The problem is that it can be entered in the following ways: TEST, Test, or test.
Answer: To answer this question, let’s look at an example.
Let’s say that we have a suppliers table with a field called supplier_name that contains the values TEST, Test, or test.
If we wanted to find all records containing the word «test», regardless of whether it was stored as TEST, Test, or test, we could run either of the following SQL SELECT statements:
SELECT * FROM suppliers WHERE UPPER(supplier_name) LIKE ('TEST%');
OR
SELECT * FROM suppliers WHERE UPPER(supplier_name) LIKE UPPER('test%')
SQL Справочник
SQL Ключевые слова
ADD
ADD CONSTRAINT
ALTER
ALTER COLUMN
ALTER TABLE
ALL
AND
ANY
AS
ASC
BACKUP DATABASE
BETWEEN
CASE
CHECK
COLUMN
CONSTRAINT
CREATE
CREATE DATABASE
CREATE INDEX
CREATE OR REPLACE VIEW
CREATE TABLE
CREATE PROCEDURE
CREATE UNIQUE INDEX
CREATE VIEW
DATABASE
DEFAULT
DELETE
DESC
DISTINCT
DROP
DROP COLUMN
DROP CONSTRAINT
DROP DATABASE
DROP DEFAULT
DROP INDEX
DROP TABLE
DROP VIEW
EXEC
EXISTS
FOREIGN KEY
FROM
FULL OUTER JOIN
GROUP BY
HAVING
IN
INDEX
INNER JOIN
INSERT INTO
INSERT INTO SELECT
IS NULL
IS NOT NULL
JOIN
LEFT JOIN
LIKE
LIMIT
NOT
NOT NULL
OR
ORDER BY
OUTER JOIN
PRIMARY KEY
PROCEDURE
RIGHT JOIN
ROWNUM
SELECT
SELECT DISTINCT
SELECT INTO
SELECT TOP
SET
TABLE
TOP
TRUNCATE TABLE
UNION
UNION ALL
UNIQUE
UPDATE
VALUES
VIEW
WHERE
MySQL Функции
Функции строк
ASCII
CHAR_LENGTH
CHARACTER_LENGTH
CONCAT
CONCAT_WS
FIELD
FIND_IN_SET
FORMAT
INSERT
INSTR
LCASE
LEFT
LENGTH
LOCATE
LOWER
LPAD
LTRIM
MID
POSITION
REPEAT
REPLACE
REVERSE
RIGHT
RPAD
RTRIM
SPACE
STRCMP
SUBSTR
SUBSTRING
SUBSTRING_INDEX
TRIM
UCASE
UPPER
Функции чисел
ABS
ACOS
ASIN
ATAN
ATAN2
AVG
CEIL
CEILING
COS
COT
COUNT
DEGREES
DIV
EXP
FLOOR
GREATEST
LEAST
LN
LOG
LOG10
LOG2
MAX
MIN
MOD
PI
POW
POWER
RADIANS
RAND
ROUND
SIGN
SIN
SQRT
SUM
TAN
TRUNCATE
Функции дат
ADDDATE
ADDTIME
CURDATE
CURRENT_DATE
CURRENT_TIME
CURRENT_TIMESTAMP
CURTIME
DATE
DATEDIFF
DATE_ADD
DATE_FORMAT
DATE_SUB
DAY
DAYNAME
DAYOFMONTH
DAYOFWEEK
DAYOFYEAR
EXTRACT
FROM_DAYS
HOUR
LAST_DAY
LOCALTIME
LOCALTIMESTAMP
MAKEDATE
MAKETIME
MICROSECOND
MINUTE
MONTH
MONTHNAME
NOW
PERIOD_ADD
PERIOD_DIFF
QUARTER
SECOND
SEC_TO_TIME
STR_TO_DATE
SUBDATE
SUBTIME
SYSDATE
TIME
TIME_FORMAT
TIME_TO_SEC
TIMEDIFF
TIMESTAMP
TO_DAYS
WEEK
WEEKDAY
WEEKOFYEAR
YEAR
YEARWEEK
Функции расширений
BIN
BINARY
CASE
CAST
COALESCE
CONNECTION_ID
CONV
CONVERT
CURRENT_USER
DATABASE
IF
IFNULL
ISNULL
LAST_INSERT_ID
NULLIF
SESSION_USER
SYSTEM_USER
USER
VERSION
SQL Server функции
Функции строк
ASCII
CHAR
CHARINDEX
CONCAT
Concat with +
CONCAT_WS
DATALENGTH
DIFFERENCE
FORMAT
LEFT
LEN
LOWER
LTRIM
NCHAR
PATINDEX
QUOTENAME
REPLACE
REPLICATE
REVERSE
RIGHT
RTRIM
SOUNDEX
SPACE
STR
STUFF
SUBSTRING
TRANSLATE
TRIM
UNICODE
UPPER
Функции чисел
ABS
ACOS
ASIN
ATAN
ATN2
AVG
CEILING
COUNT
COS
COT
DEGREES
EXP
FLOOR
LOG
LOG10
MAX
MIN
PI
POWER
RADIANS
RAND
ROUND
SIGN
SIN
SQRT
SQUARE
SUM
TAN
Функции дат
CURRENT_TIMESTAMP
DATEADD
DATEDIFF
DATEFROMPARTS
DATENAME
DATEPART
DAY
GETDATE
GETUTCDATE
ISDATE
MONTH
SYSDATETIME
YEAR
Функции расширений
CAST
COALESCE
CONVERT
CURRENT_USER
IIF
ISNULL
ISNUMERIC
NULLIF
SESSION_USER
SESSIONPROPERTY
SYSTEM_USER
USER_NAME
MS Access функции
Функции строк
Asc
Chr
Concat with &
CurDir
Format
InStr
InstrRev
LCase
Left
Len
LTrim
Mid
Replace
Right
RTrim
Space
Split
Str
StrComp
StrConv
StrReverse
Trim
UCase
Функции чисел
Abs
Atn
Avg
Cos
Count
Exp
Fix
Format
Int
Max
Min
Randomize
Rnd
Round
Sgn
Sqr
Sum
Val
Функции дат
Date
DateAdd
DateDiff
DatePart
DateSerial
DateValue
Day
Format
Hour
Minute
Month
MonthName
Now
Second
Time
TimeSerial
TimeValue
Weekday
WeekdayName
Year
Другие функции
CurrentUser
Environ
IsDate
IsNull
IsNumeric
SQL ОператорыSQL Типы данныхSQL Краткий справочник
SQL LIKE
Оператор LIKE используется в предложении WHERE для поиска указанного шаблона в столбце.
Есть два подстановочных знака, часто используемых в сочетании с оператором LIKE:
- % — Знак процента представляет собой ноль, один или несколько символов
- _ — Подчеркивание представляет собой один символ
Примечание: MS Access использует звездочку (*) вместо знака процента (%) и вопросительный знак (?) вместо подчеркивания (_).
Знак процента и подчеркивание также могут использоваться в комбинациях!
Синтаксис LIKE
SELECT column1, column2, …
FROM table_name
WHERE columnN LIKE pattern;
Совет: Вы также можете комбинировать любое количество условий с помощью операторов AND или OR.
Вот несколько примеров, показывающих различные операторы LIKE с подстановочными знаками ‘%’ и ‘_’:
Оператор LIKE | Описание |
---|---|
WHERE CustomerName LIKE ‘a%’ | Находит любые значения, которые начинаются с «a» |
WHERE CustomerName LIKE ‘%a’ | Находит любые значения, которые заканчиваются на «a» |
WHERE CustomerName LIKE ‘%or%’ | Находит любые значения, которые имеют «or» в любой позиции |
WHERE CustomerName LIKE ‘_r%’ | Находит любые значения, имеющие букву «r» во второй позиции |
WHERE CustomerName LIKE ‘a__%’ | Находит любые значения, начинающиеся с буквы «a» и имеющие длину не менее 3 символов |
WHERE ContactName LIKE ‘a%o’ | Находит любые значения, которые начинаются с «a» и заканчиваются «о» |
What Is Escaping?
When you are working with text values in Oracle SQL, you use single quote characters.
This could be when you’re selecting them:
Or, when you’re inserting them:
The single quote character indicates the start and end position of your string.
But what if you want to have a single quote as part of your string?
For example:
This would cause an issue, because there are three single quotes. Oracle doesn’t know where your string should end.
So, to allow values within single quotes (and some other special characters) to be used within a string, you need to “escape” them.
Escaping a character is where you say to the database, “Hey, this character here is part of my string, don’t treat it as a special character like you normally would”.
There are a few SQL escape single quote methods that I’ll cover in this article.
Пример
Рассмотрим некоторые примеры функций Oracle FIRST_VALUE и рассмотрим, как использовать функцию FIRST_VALUE в Oracle / PLSQL.
Самая высокая зарплата для всех сотрудников
Начнем с простого примера и воспользуйтесь функцией FIRST_VALUE, чтобы вернуть самую высокую зарплату в таблице employees. В этом примере нам не потребуется запрос query_partition_clause, потому что мы оцениваем всю таблицу employees. В этом примере у нас есть таблица employees со следующими данными:
EMPLOYEE_ID | FIRST_NAME | LAST_NAME | SALARY | DEPARTMENT_ID |
---|---|---|---|---|
100 | Anita | Borg | 2500 | 10 |
200 | Alfred | Aho | 3200 | 10 |
300 | Bill | Gates | 2100 | 10 |
400 | Linus | Torvalds | 3700 | 20 |
500 | Michael | Dell | 3100 | 20 |
600 | Nello | Cristianini | 2950 | 20 |
700 | Rasmus | Lerdorf | 4900 | 20 |
800 | Steve | Jobs | 2600 | 30 |
900 | Thomas | Kyte | 5000 | 30 |
Чтобы найти самую высокую зарплату, введите следующий SELECT:
Oracle PL/SQL
SELECT DISTINCT FIRST_VALUE(salary)
OVER (ORDER BY salary DESC
RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)
AS «HIGHEST»
FROM employees;
1 2 3 4 5 |
SELECTDISTINCTFIRST_VALUE(salary) OVER(ORDERBYsalaryDESC RANGEBETWEENUNBOUNDEDPRECEDINGANDUNBOUNDEDFOLLOWING) AS»HIGHEST» FROMemployees; |
Результат, который вы должны получить:
HIGHEST |
---|
5000 |
В этом примере FIRST_VALUE возвращает самое высокое значение salary (зарплаты), указанное FIRST_VALUE (salary). Аналитическое окно сортирует данные по зарплате в порядке убывания, как указано ORDER BY salary DESC. Параметр windowing_clause = RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING используется для обеспечения включения всех строк независимо от текущей строки.
И поскольку мы хотим получить самую высокую зарплату в таблице, нам не нужно было включать query_partition_clause для разделения данных.
Самая высокая зарплата по department_id
Теперь давайте покажем вам, как использовать функцию FIRST_VALUE с query_partition_clause. В следующем примере вернем самую высокую зарплату для department_id 10 и 20.
На основе той же таблицы employees введите следующий оператор SQL:
Oracle PL/SQL
SELECT DISTINCT department_id, FIRST_VALUE(salary)
OVER (PARTITION BY department_id ORDER BY salary DESC
RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)
AS «HIGHEST»
FROM employees
WHERE department_id in (10,20)
ORDER BY department_id;
1 2 3 4 5 6 7 |
SELECTDISTINCTdepartment_id,FIRST_VALUE(salary) OVER(PARTITIONBYdepartment_idORDERBYsalaryDESC RANGEBETWEENUNBOUNDEDPRECEDINGANDUNBOUNDEDFOLLOWING) AS»HIGHEST» FROMemployees WHEREdepartment_idin(10,20) ORDERBYdepartment_id; |
Вот результаты, которые вы должны получить:
DEPARTMENT_ID | HIGHEST |
---|---|
10 | 3200 |
20 | 4900 |
В этом примере FIRST_VALUE возвращает самое высокое значение зарплаты, указанное FIRST_VALUE (salary). Аналитическое окно будет делить результаты по DEPARTMENT_ID и упорядочит данные по salary в порядке убывания, как указано PARTITION BY DEPARTMENT_ID ORDER BY зарплата DESC.
Самая низкая зарплата по department_id
Теперь давайте покажем вам, как использовать функцию FIRST_VALUE, чтобы вернуть самую низкую зарплату для department_id 10 и 20.
Снова на основе данных в таблице employee введите следующий оператор SQL:
Oracle PL/SQL
SELECT DISTINCT department_id, FIRST_VALUE(salary)
OVER (PARTITION BY department_id ORDER BY salary ASC
RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)
AS «LOWEST»
FROM employees
WHERE department_id in (10,20)
ORDER BY department_id;
1 2 3 4 5 6 7 |
SELECTDISTINCTdepartment_id,FIRST_VALUE(salary) OVER(PARTITIONBYdepartment_idORDERBYsalaryASC RANGEBETWEENUNBOUNDEDPRECEDINGANDUNBOUNDEDFOLLOWING) AS»LOWEST» FROMemployees WHEREdepartment_idin(10,20) ORDERBYdepartment_id; |
Вот результаты, которые вы должны получить:
DEPARTMENT_ID | LOWEST |
---|---|
10 | 2100 |
20 | 2950 |
В этом примере мы изменили порядок сортировки на возрастание по разделу, как указано PARTITION BY DEPARTMENT_ID ORDER BY salary ASC, и теперь мы получаем самую низкую зарплату, основанную на DEPARTMENT_ID.
Типы возвращаемых данныхReturn Types
Текст nvarchar(max) с экранированными специальными и управляющими символами.nvarchar(max) text with escaped special and control characters. В настоящее время с помощью функции STRING_ESCAPE можно экранировать только специальные символы JSON, представленные в таблицах ниже.Currently STRING_ESCAPE can only escape JSON special characters shown in the following tables.
Специальный символSpecial character | Закодированная последовательностьEncoded sequence |
---|---|
Кавычки («»)Quotation mark («) | \»\» |
Обратный солидус (\)Reverse solidus (\) | \\ |
Солидус (/)Solidus (/) | \/ |
ОтменаBackspace | \b\b |
Перевод страницыForm feed | \f\f |
Новая строкаNew line | \n\n |
Возврат кареткиCarriage return | \r\r |
Горизонтальная табуляцияHorizontal tab | \t\t |
Управляющий символControl character | Закодированная последовательностьEncoded sequence |
---|---|
CHAR(0)CHAR(0) | \u0000\u0000 |
CHAR(1)CHAR(1) | \u0001\u0001 |
…… | …… |
CHAR(31)CHAR(31) | \u001f\u001f |
ПримерыExamples
A.A. Экранирование текста согласно правилам форматирования JSONEscape text according to the JSON formatting rules
Приведенный ниже запрос экранирует специальные символы с использованием правил JSON и возвращает экранированный текст.The following query escapes special characters using JSON rules and returns escaped text.
Результирующий набор:Here is the result set.
Б.B. Форматирование объекта JSONFormat JSON object
Приведенный ниже запрос создает текст в формате JSON на основе числовых и строковых переменных, а затем экранирует все специальные символы JSON в переменных.The following query creates JSON text from number and string variables, and escapes any special JSON character in variables.
Пример с числами
Рассмотрим пример Oracle условия IN, с использованием числовых значений.
Например:
Oracle PL/SQL
SELECT *
FROM orders
WHERE order_id IN (10000, 10001, 10003, 10005);
1 2 3 |
SELECT* FROMorders WHEREorder_idIN(10000,10001,10003,10005); |
Этот пример Oracle условия IN возвратит все orders, где order_id является или 10000 или 10001 или 10003 или 10005.
Пример выше эквивалентен следующему запросу SELECT:
Oracle PL/SQL
SELECT *
FROM orders
WHERE order_id = 10000
OR order_id = 10001
OR order_id = 10003
OR order_id = 10005;
1 2 3 4 5 6 |
SELECT* FROMorders WHEREorder_id=10000 ORorder_id=10001 ORorder_id=10003 ORorder_id=10005; |
Example — Using Escape Characters with the LIKE Condition
It is important to understand how to «Escape Characters» when pattern matching. You can escape or and search for the literal versions instead.
Let’s say you wanted to search for as a literal in the LIKE condition. You can do this using an Escape character. In our example, we will use as the escape character in the LIKE condition.
NOTE: You can only define an escape character as a single character. It is best to choose a character that will not appear in your data very often such as ! or #.
In this example, we a table called test with the following data:
test_id | test_value |
---|---|
1 | 10% |
2 | 25% |
3 | 100 |
4 | 99 |
We could return all records from the test table where the test_value contains the literal. Enter the following SQL statement:
SELECT * FROM test WHERE test_value LIKE '%!%%' escape '!';
These are the results that you should see:
test_id | test_value |
---|---|
1 | 10% |
2 | 25% |
This example identifies the character as an escape character. The first and last values in the LIKE condition are treated as regular wildcards. The is an escaped so it is treated as a literal value.
You could further modify the above example and only return test_values that start with 1 and contain the literal. Enter the following SQL statement:
SELECT * FROM test WHERE test_value LIKE '1%!%%' escape '!';
These are the results that you should see:
test_id | test_value |
---|---|
1 | 10% |
Неэффективные способы защиты от SQL-инъекций
Очевидно, самый худший вариант — не иметь никакой защиты от SQL инъекций и передавать данные, полученные от пользователя, напрямую в SQL-запрос.
Никогда так не делай! Любые данные перед подстановкой в SQL-запрос должны проходить фильтрацию и/или валидацию.
1. Функция htmlspecialchars()
Время от времени встречаю статьи, где авторы используют функцию htmlspecialchars() для экранирования данных:
Это опасно! Штука в том, что функция htmlspecialchars() пропускает без экранирования опасные символы: \ (слеш), \0 (nul-байт) и \b (backspace).
Вот полный пример кода, демонстрирующего уязвимость:
В итоге SQL-запрос будет таким:
С помощью / экранируется кавычка, идущая сразу после $login. `login` = ‘$login’ по факту превращается в `login` = ‘\’ AND `password` = ‘. После этого любой код, который мы напишем, будет выполнен, в нашем случае это просто OR 1=1. В конце добавляем # (комментарий), чтобы скрыть последнюю кавычку.
2. Фильтрация по чёрному списку символов
По каким-то непонятным мне причинам ещё существуют разработчики, использующие чёрные списки символов:
Все символы, входящие в чёрный список, удаляются из строки перед вставкой в базу.
Я не хочу сказать, что этот подход не будет работать, но его применение под большим вопросом:
- Зачем вообще составлять какие-то списки, если есть более простые и надёжные способы защиты?
- Нужно знать все потенциально опасные символы.
- Что делать если нужно разрешить пользователям использовать какие-либо символы из списка?
Кроме этого, я считаю фильтрацию в SQL-запросах плохой идеей. Если в строке есть недопустимые символы — лучше сообщить о них пользователю и попросить исправить, а не просто обрезать часть контента.
К примеру, пользователь хочет использовать логин ~!Mega_!Pihar!_!9000!~, а после регистрации оказывается, что его ник превратился в MegaPihar9000.
Я считаю, лучше уточнить у пользователя, нравится ли ему такой отфильтрованный логин или он хотел бы что-то поменять. Короче, я за валидацию по белому списку вместо фильтрации по чёрному.
3. Функция stripslashes()
Редко, но встречается код, использующий stripslashes() перед записью в базу. Поскольку новички до сих пор копируют этот код в свои проекты, объясню, зачем эта функция нужна.
Раньше в PHP была такая штука как волшебные кавычки (Документация). Если эта директива была включена, то все данные, содержащиеся в $_GET, $_POST и $_COOKIE автоматически экранировались.
Сделано это было для защиты новичков, которые подставляли данные напрямую в SQL-запросы. На практике это было не самое удачное решение:
- Не очень удобно, когда все данные по-умолчанию экранируются, ведь зачастую они нужны в исходном виде.
- В идеале экранирование должно учитывать кодировку соединения с базой данных, о чём мы поговорим чуть позже. Из-за этого разработчикам приходилось убирать экранирование функцией stripslashes() и затем опять экранировать данные более подходящими функциями, в случае MySQL это была mysql_real_escape_string().
Вот почему функцию stripslashes() можно встретить в старых учебниках. Чтобы отменить экранирование символов и получить исходную строку.
Начиная с PHP 5.4 функционал волшебных кавычек удалён, поэтому использовать stripslashes() перед записью в базу нет никакого смысла.
4. Функция addslashes()
В некоторых книгах ещё можно встретить рекомендации экранировать данные функцией addslashes().
Эта функция надёжней, чем htmlspecialchars(), поскольку экранирует и обратный слеш, и nul-байт. Однако эта функция хуже, чем mysql_real_escape_string, поскольку не учитывает кодировку текущего соединения с базой.
Поэтому даже в документации прямо написано, что эту функцию не нужно использовать для защиты от SQL инъекций.
Вырезка из документации про функцию addslashes()