2012-08-15 8 views
34

huh?Come proteggersi segni diacritici come Zalgo testo

Il personaggio nella foto sopra è stato inviato un tweet di qualche mese fa da Mikko Hyppönen, un esperto di sicurezza informatica noto per il suo lavoro sui virus informatici e TED talks sulla sicurezza informatica. Nel rispetto di SO, pubblicherò solo un'immagine di esso, ma tu hai l'idea. Ovviamente non è qualcosa che vorresti diffondere sul tuo sito web e spaventare i visitatori.

Dopo un'ulteriore ispezione, il personaggio sembra essere una lettera dell'alfabeto tailandese combinata con oltre diacritici (c'è anche un limite ?!). Questo mi ha fatto pensare a sicurezza, localizzazione e come si possa gestire questo tipo di input. La mia ricerca mi porta a this question su Stack e, a sua volta, a un post di Michael Kaplan su stripping diacritics. In esso, egli dimostra come si può scomporre una stringa nelle sue caratteri "base" (semplificato qui per brevità):

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 

posso vedere quanto che questo è sarebbe utile, in alcuni casi, ma in termini di input dell'utente, sarebbe togliere tutti i segni diacritici. Come sottolinea Kaplan, rimuovere i segni diacritici in alcune lingue può cambiare completamente il significato della parola. Questo solleva la domanda: In che modo si permettono alcuni segni diacritici nell'input/output dell'utente, ma si escludono altri casi estremi come il carattere über di Mikko Hyppönen?

+1

Whitelist attraverso una classe statica/classe di utilità? E merita di andare su programmers.stackexchange.com. –

+2

@MonsterTruck, abbastanza giusto, ma quale whitelist esattamente? Questi sono personaggi Unicode di cui sto parlando. –

+4

È possibile impostare un numero massimo di segni diacritici per carattere base. Scegli un valore abbastanza alto in modo che vietnamita e greca siano ancora a posto, ma abbastanza bassi da respingere i casi folle. –

risposta

20

c'è anche un limite ?!

Non intrinsecamente in Unicode. Esiste il concetto di un formato 'Stream-Safe' in UAX-15 che imposta un limite di 30 combinatori ... Le stringhe Unicode in generale non sono garantite come Stream-Safe, ma questo potrebbe certamente essere preso come un segno che Unicode non intendo standardizzare nuovi personaggi che richiederebbero un grafo grafo più lungo di quello.

30 è ancora un sacco. Il cluster grafema in lingua naturale più lungo conosciuto è il tibetano Hakṣhmalawarayaṁ a 1 base più 8 combinatori, quindi per ora sarebbe ragionevole normalizzare a NFD e non consentire alcuna sequenza di più di 8 combinatori di fila.

Se ti interessano solo le comuni lingue dell'Europa occidentale, puoi probabilmente ridurlo a 2. In questo modo potresti comprometterti da qualche parte.

2

Penso di aver trovato una soluzione utilizzando NormalizationForm.FormC anziché NormalizationForm.FormD. Secondo il MSDN:

[FormC] Indica che una stringa Unicode è normalizzata con piena decomposizione canonica, seguito dalla sostituzione di sequenze con loro compositi primari, se possibile.

Prendo questo per indicare che decompone i caratteri nella loro forma base, quindi li ricompone in base a un insieme di regole che rimangono coerenti. Ho capito che questo è utile per scopi di confronto, ma nel mio caso funziona perfettamente. Personaggi come ü, é e Ä vengono decomposti/ricomposto precisione, mentre i caratteri falsi riescono a ricomporre, e quindi rimangono nella loro forma di base:

enter image description here

+2

La richiesta di caratteri solo composti è OK se si desidera limitare le stringhe ai caratteri utilizzati storicamente - Unicode include caratteri composti per tutti i caratteri che sono stati composti in una codifica legacy, per compatibilità. Tuttavia, le nuove aggiunte a Unicode possono essere disponibili solo in una forma scomposta. – bobince

+0

Suggerisci controllo per SpacingCombiningMark o EnclosingMark e NonSpacingMark, per ottenere altri combinatori. Anche l'iterazione su 'char' andrà oltre le unità di codice UTF-16, quindi non sarà possibile controllare i caratteri al di fuori del piano multilingue di base per il quale vedrete solo i surrogati. Suggerisci di usare un'espressione regolare per trovare e sostituire le classi di caratteri sull'intera stringa contemporaneamente. – bobince

+0

Grazie per le informazioni! Se questo funziona solo su personaggi storicamente usati, l'impostazione di un limite di 2-8 combinatori suona come una soluzione molto migliore! Per favorire il tuo punto, questo metodo riduce il simbolo tibetano a ཧ. Prova a spiegarlo a un monaco tibetano! –

1

Here's regex che dovrebbe pescare fuori tutto lo zalgo compresi quelli bypassati nella gamma "normale".

([\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,}) 

La cosa più difficile è identificarli, una volta che l'hai fatto, c'è una moltitudine di soluzioni.

Spero che questo ti salvi un po 'di tempo.