Как защититься от таких диакритических знаков, как текст Zalgo

да

Изображенный выше персонаж был опубликован в Твиттере несколько месяцев назад Микко Хиппоненом, экспертом по компьютерной безопасности, известным своей работой над компьютерными вирусами и беседами TED по компьютерной безопасности. Что касается SO, я буду публиковать только его изображение, но вы поняли идею. Очевидно, это не то, что вы хотели бы распространять по вашему сайту и сводить с ума посетителей.

При дальнейшем осмотре персонаж представляется буквой тайского алфавита в сочетании с более чем 87 диакритическими знаками (есть ли предел?!). Это заставило меня задуматься о безопасности, локализации и о том, как можно справиться с такого рода вводом. Мои поиски привели меня к этому вопросу о стеке и, в свою очередь, к сообщению в блоге Майкла Каплана о разборке диакритических знаков. В нем он демонстрирует, как можно разложить строку на ее "базовые" символы (здесь для краткости упрощено):

StringBuilder sb = new StringBuilder();
foreach (char c in "façade".Normalize(NormalizationForm.FormD))
{
    if (char.GetUnicodeCategory(c) != UnicodeCategory.NonSpacingMark)
        sb.Append(c);
}
Response.Write(sb.ToString()); // facade 

Я могу видеть, как это было бы полезно в некоторых случаях, но с точки зрения пользовательского ввода, это исключило бы ВСЕ диакритические знаки. Как указывает Каплан, удаление диакритических знаков в некоторых языках может полностью изменить значение слова. Возникает вопрос: как разрешить некоторые диакритические знаки в пользовательском вводе / выводе, но исключить другие крайние случаи, такие как über характер Микко Хиппонена?

3 ответа

Решение

есть ли предел?!

Не по сути в Юникоде. В UAX-15 существует концепция формата Stream-Safe, который устанавливает ограничение в 30 объединителей... Строки Unicode в общем случае не гарантируются как Stream-Safe, но это, безусловно, может восприниматься как признак того, что Unicode не намеревайтесь стандартизировать новые символы, которые требуют кластера графемы дольше.

30 все еще очень много. Самым длинным из известных кластеров графем на естественном языке является тибетский Hakṣhmalawarayaṁ на 1 базе плюс 8 сумматоров, поэтому на данный момент было бы разумно нормализовать NFD и запретить любую последовательность из более чем 8 сумматоров подряд.

Если вам небезразличны только распространенные западноевропейские языки, вы, вероятно, можете довести их до 2. Так что, возможно, существует компромисс между ними

Я думаю, что нашел решение, используя NormalizationForm.FormC вместо NormalizationForm.FormD, Согласно MSDN:

[FormC] Указывает, что строка Unicode нормализуется с использованием полной канонической декомпозиции с последующей заменой последовательностей их первичными композитами, если это возможно.

Я понимаю, что это означает, что он разлагает символы до их базовой формы, а затем перекомпоновывает их на основе набора правил, которые остаются согласованными. Я понимаю, что это полезно для сравнения, но в моем случае это работает отлично. Персонажи как ü, é, а также Ä точно разложены / перекомпонованы, в то время как поддельные символы не могут перекомпоноваться и, таким образом, остаются в своей базовой форме:

Вот регулярное выражение, которое должно вылавливать все zalgo, в том числе и обходимые в "нормальном" диапазоне

([\u0300–\u036F\u1AB0–\u1AFF\u1DC0–\u1DFF\u20D0–\u20FF\uFE20–\uFE2F\u0483-\u0486\u05C7\u0610-\u061A\u0656-\u065F\u0670\u06D6-\u06ED\u0711\u0730-\u073F\u0743-\u074A\u0F18-\u0F19\u0F35\u0F37\u0F72-\u0F73\u0F7A-\u0F81\u0F84\u0e00-\u0eff\uFC5E-\uFC62]{2,})

Самое сложное - это определить их, как только вы это сделаете - есть множество решений.

Надеюсь, это сэкономит вам время.

Другие вопросы по тегам