Like (transact-sql)like (transact-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’

Этот пример вернет ‘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;
 
—Результат: ‘A’

Теперь, поскольку мы предоставили 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()

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Adblock
detector