V5629. Code contains invisible characters that may alter its logic. Consider enabling the display of invisible characters in the code editor.
Анализатор обнаружил в тексте программы символы, которые могут ввести программиста в заблуждение. Эти символы могут не отображаться и изменять видимое представление кода в среде разработки. Комбинации таких символов могут привести к тому, что человек и компилятор будут интерпретировать код по-разному.
В некоторых случаях это делается намеренно. Такой вид атаки называется Trojan Source. Подробнее:
- Атака Trojan Source для внедрения в код изменений, незаметных для разработчика;
- Атака Trojan Source: скрытые уязвимости.
Обозначение |
Код |
Название |
Описание |
---|---|---|---|
LRE |
U+202A |
LEFT-TO-RIGHT EMBEDDING |
Текст после символа LRE интерпретируется как вставленный и отображается слева направо. Действие LRE прерывается символом PDF или символом перевода строки. |
RLE |
U+202B |
RIGHT-TO-LEFT EMBEDDING |
Текст после символа RLE интерпретируется как вставленный и отображается справа налево. Действие RLE прерывается символом PDF или символом перевода строки. |
LRO |
U+202D |
LEFT-TO-RIGHT OVERRIDE |
Текст после символа LRO принудительно отображается слева направо. Действие LRO прерывается символом PDF или символом перевода строки. |
RLO |
U+202E |
RIGHT-TO-LEFT OVERRIDE |
Текст после символа RLO принудительно отображается справа налево. Действие RLO прерывается символом PDF или символом перевода строки. |
|
U+202C |
POP DIRECTIONAL FORMATTING |
Символ PDF прерывает действие одного из символов LRE, RLE, LRO или RLO, встреченного ранее. Прерывает ровно один символ, последний из встреченных. |
LRI |
U+2066 |
LEFT‑TO‑RIGHT ISOLATE |
Текст после символа LRI отображается слева направо и интерпретируется как изолированный. Это означает, что другие управляющие символы не влияют на отображение этого фрагмента текста. Действие LRI прерывается символом PDI или символом перевода строки. |
RLI |
U+2067 |
RIGHT‑TO‑LEFT ISOLATE |
Текст после символа RLI отображается справа налево и интерпретируется как изолированный. Это означает, что другие управляющие символы не влияют на отображение этого фрагмента текста. Действие RLI прерывается символом PDI или символом перевода строки. |
FSI |
U+2068 |
FIRST STRONG ISOLATE |
Направление текста после символа FSI задается первым управляющим символом, не входящим в этот фрагмент текста. Другие управляющие символы не влияют на отображение этого текста. Действие FSI прерывается символом PDI или символом перевода строки. |
PDI |
U+2069 |
POP DIRECTIONAL ISOLATE |
Символ PDI прерывает действие одного из символов LRI, RLI или FSI, встреченного ранее. Прерывает ровно один символ, последний из встреченных. |
LRM |
U+200E |
LEFT-TO-RIGHT MARK |
Текст после символа LRM отображается слева направо. Действие LRM прерывается символом перевода строки. |
RLM |
U+200F |
RIGHT-TO-LEFT MARK |
Текст после символа RLM отображается справа налево. Действие RLM прерывается символом перевода строки. |
ALM |
U+061C |
ARABIC LETTER MARK |
Текст после символа ALM отображается справа налево. Действие ALM прерывается символом перевода строки. |
ZWSP |
U+200B |
ZERO WIDTH SPACE |
Неотображаемый пробельный символ. Использование символа ZWSP привести к тому, что разные строки будут отображаться одинаково. Например, |
Рассмотрим следующий фрагмент кода:
bool isAdmin = false;
/*[RLO] } [LRI] if (isAdmin)[PDI] [LRI] begin admins only */ // (1)
Console.WriteLine("You are an admin.");
/* end admins only [RLO]{ [LRI]*/ // (2)
Изучим детально строку (1).
[LRI] if (isAdmin)[PDI]
Здесь символ [LRI] действует до символа [PDI]. Строка if (isAdmin)
будет отображаться слева направо и считается изолированной, получаем if (isAdmin)
.
[LRI] begin admins only */
Здесь символ [LRI] действует до конца строки. Получаем изолированную строку: begin admins only */
[RLO] {пробел1}, '}', {пробел2}, 'if (isAdmin)', 'begin admins only */'
Здесь символ [RLO] действует до конца строки и отображает текст справа налево. Каждая из полученных в предыдущих пунктах изолированных строк рассматривается как отдельный неделимый символ. Получаем такую последовательность:
'begin admins only */', 'if (isAdmin)', {пробел2}, '{', {пробел1}
Обратите внимание, что символ закрывающей фигурной скобки теперь отображается как {
вместо }
.
Итоговый вид строки (1), который может быть отображен в редакторе:
/* begin admins only */ if (isAdmin) {
Похожие преобразования затронут и строку (2), которая отобразится так:
/* end admins only */ }
Финальный вид кода, который может отобразиться в редакторе:
bool isAdmin = false;
/* begin admins only */ if (isAdmin) {
Console.WriteLine("You are an admin.");
/* end admins only */ }
Ревьюер может посчитать, что в коде выполняется некоторая проверка перед выводом сообщения. Он проигнорирует комментарии и подумает, что код должен выполняться так:
bool isAdmin = false;
if (isAdmin) {
Console.WriteLine("You are an admin.");
}
Однако на самом деле проверки нет. Для компилятора рассмотренный код выглядит так:
bool isAdmin = false;
Console.WriteLine("You are an admin.");
Теперь рассмотрим более простой и в то же время более опасный пример использования неотображаемых символов:
enum BlockSipherType { DES, TripleDES, AES };
BlockSipherType StringToBlockSypherType(string str)
{
if (str == "AES[ZWSP]")
return BlockSipherType.AES;
else if (str == "TripleDES[ZWSP]")
return BlockSipherType.TripleDES;
else return BlockSipherType.DES;
}
Метод StringToBlockCipherType
производит конвертацию строки в одно из значений перечисления BlockCipherType
. По коду можно сделать вывод, что функция возвращает три разных значения, однако это не так. Из-за того, что в конце каждого строкового литерала добавлен неотображаемый пробельный символ [ZWSP], проверки на равенство со строками AES
и TripleDES
будут ложными. В итоге из трех ожидаемых значений функция будет возвращать лишь BlockCipherType.DES
. В то же время код в редакторе может отображаться следующим образом:
enum BlockSipherType { DES, TripleDES, AES };
BlockSipherType StringToBlockSypherType(string str)
{
if (str == "AES")
return BlockSipherType.AES;
else if (str == "TripleDES")
return BlockSipherType.TripleDES;
else return BlockSipherType.DES;
}
Если анализатор выдал предупреждение о неотображаемых символах в коде, включите отображение невидимых символов в вашем редакторе и убедитесь, что они не изменяют логику выполнения программы.
Данная диагностика классифицируется как:
|