it-swarm.dev

Come posso usare Markdown in modo sicuro?

Come posso utilizzare la libreria Markdown in modo sicuro? Cosa devo fare per assicurarmi che il suo output sia sicuro da includere nella mia pagina Web?

Voglio consentire agli utenti non attendibili di inserire il contenuto (in formato Markdown). Userò il processore Markdown per generare HTML e mi piacerebbe includerlo nella mia pagina web. Cosa devo fare per assicurarmi che sia sicuro e non sia una vulnerabilità XSS autoinflitta? Quali argomenti devo superare? C'è qualche pre-elaborazione o post-elaborazione che devo fare? Sto usando la libreria python-markdown, se questo è rilevante.

45
D.W.

Utilizzo raccomandato. La risposta breve è: Usa markdown(untrusted, safe_mode=remove, enable_attributes=False).

Assicurati di disporre di una versione aggiornata della libreria Markdown, poiché le versioni precedenti presentano alcuni problemi di sicurezza.

È inoltre possibile eseguire l'output tramite un disinfettante HTML, come HTML Purifier.

Motivazione. È una buona idea disabilitare enable_attributes. Mentre le ultime versioni di sviluppo della libreria markdown Python disabilita enable_attributes Per impostazione predefinita se imposti safe_mode , le versioni precedenti non lo hanno fatto. Di conseguenza, solo l'impostazione di safe_mode È non sufficiente sulla maggior parte delle versioni della libreria Markdown . Se hai appena impostato safe_mode, Il risultato non è sicuro:

import markdown
>>> markdown.markdown("{@onclick=alert('hi')}some paragraph", safe_mode=True)
u'<p onclick="alert(\'hi\')">some paragraph</p>'

Al momento, le correzioni sono presenti solo in git. Al momento della stesura di questo documento, l'ultima versione rilasciata di Python Markdown (2.1.1) rimane vulnerabile se non si imposta esplicitamente enable_attributes=False. Pertanto, è plausibile che molti sistemi che attualmente utilizzano Python Markdown possano essere vulnerabili.

La documentazione potrebbe essere migliore per avvisare gli utenti di Markdown su queste insidie. Dice cose come "Potresti anche voler impostare enable_attributes=False Quando usi safe_mode", Senza rivelare che non farlo crea un buco XSS con tutte le versioni tranne la più recente della libreria. Le versioni successive della documentazione affermano che l'impostazione enable_attributes "Potrebbe potenzialmente consentire a un utente non attendibile di inserire JavaScript nei tuoi documenti"; sarebbe più chiaro dire che l'impostazione enable_attributes consente agli utenti di iniettare Javascript nei tuoi documenti ed è quindi altamente insicuro se il Markdown potrebbe provenire da una fonte non attendibile.

Dubbi. Detto questo, non sono sicuro al 100% se il risultato sarà sicuro, anche quando lo usi come raccomandato sopra. Gli sviluppatori hanno fatto commenti come i seguenti:

"modalità provvisoria" è stata una scelta di nome scadente che continuiamo a utilizzare per la comparabilità all'indietro (il vecchio codice funziona ancora con le nostre versioni più recenti). In realtà è una modalità senza markup. In altre parole, è solo un modo per non consentire l'html grezzo e in realtà non garantisce la sicurezza.

Questi commenti sono un po 'spaventosi.

Nelle versioni precedenti della libreria Markdown Python, la sua disinfezione HTML mi sembra un po 'fragile, quindi non sono sicuro che mi fiderei delle versioni precedenti della libreria Markdown, indipendentemente dai flag passati. Considera quanto segue:

>>> markdown.markdown("[Example](javascript://alert%28%22xss%22%29)", safe_mode=True)
u'<p><a href="javascript://alert%28%22xss%22%29">Example</a></p>'

Consentire gli URL di stile javascript: Attraverso l'elaborazione di Markdown mi sembra una decisione di progettazione piuttosto dubbia. Sembra che questo sia dentro un salto, saltare e un salto di XSS. Tutto ciò che manca è un modo per uscire dal commento in stile C++ (il //), Ed è finito il gioco. Per esempio:

>>> markdown.markdown("[Example](javascript://\nalert%28%22xss%22%29)", safe_mode=True)
u'<p><a href="javascript://&#10;alert%28%22xss%22%29">Example</a></p>'

Quanto dovrei essere sicuro che nessun browser eseguirà quel Javascript? Non lo so, ma non mi sta dando sentimenti caldi e sfocati. Se è sicuro, è solo cieca fortuna.

Fortunatamente, l'ultima versione rilasciata di Markdown sembra fare un filtro più rigoroso dello script se imposti enable_attributes=False. Ma assicurati di impostare enable_attributes=False, Altrimenti Markdown ricade sulla fragile sanificazione HTML presente nelle versioni precedenti e non sono sicuro della sicurezza di quello schema.

Cosa non fare. Non è sicuro quanto segue: markdown(escape(untrusted)).

  • Si potrebbe pensare che la prima fuga dall'input rimuova tutto l'HTML e rendere sicuro questo utilizzo. In effetti l'ho visto usato in alcuni sistemi e consigliato da alcuni. Tuttavia, in realtà non è sicuro, poiché l'escape non è sufficiente per rendere sicuri gli URL. Ad esempio, questo uso di Markdown può essere sconfitto da "[clickme](javascript:alert%28%22xss%22%29)". In generale, sfuggire all'input per Markdown è non l'approccio giusto ; l'approccio giusto è invocare Markdown nel modo appropriato (e possibilmente applicare un filtro HTML anche al suo output, se si desidera una protezione aggiuntiva).

Se usi Django. Se usi Django, dovrebbe essere un modo sicuro per usare Markdown:

{{ untrusted | markdown:"safe" }}

A partire da Django 1.4 , questo è sicuro. quando passi l'argomento "safe", Django ora ha un supporto speciale per impostare safe_mode e disabilitare enable_attributes. Assicurati di aggiornare a Django 1.4 o successivo; nelle versioni precedenti, questo utilizzo era insicuro .

16
D.W.

Il markdown da solo non sarebbe sufficiente per santizzare l'output, poiché consente input HTML/Javascript arbitrari e semplicemente lo passa non elaborato.

Per esempio. questo è un markdown valido:

## heading

text

Ma anche questo:

## heading

text <script>alert('hello');</script>

Dalla pagina della sintassi del markdown :

Per qualsiasi markup non coperto dalla sintassi di Markdown, devi semplicemente usare lo stesso HTML. Non è necessario prefigurarlo o delimitarlo per indicare che stai passando da Markdown a HTML; basta usare i tag.

Ho appena fatto un rapido test usando Python-Markdown e sembra funzionare in questo modo.

Detto questo, dato il set di caratteri limitato utilizzato dalla sintassi del markdown, potrebbe essere più semplice filtrare il set di caratteri che consenti agli utenti di fornire prima che lo alimenti markdown (ad esempio qualcosa come a-zA-Z* #+:/&?=-_()>), ma anche quelli potrebbero essere sufficienti per confondere un codice che lo analizza/lo codifica ... Quindi non sono davvero sicuro di quanta sicurezza ottieni puramente dal fatto che usi il markdown.

AGGIORNARE:

dopo ulteriori ricerche I ho trovato questa risposta su SO che sembra abbastanza ragionevole.

Ho anche cercato ulteriormente e scoperto l'opzione safe_mode ( menzionato qui e qui ).

Un test rapido sembra funzionare abbastanza bene, ma potrebbe meritare ulteriori ricerche ...

>>> import markdown
>>> markdown.markdown("<script>alert('hello');</script> hello <strong>world</strong>")
u"<script>alert('hello');</script>\n\n<p>hello <strong>world</strong></p>"
>>> markdown.markdown("<script>alert('hello');</script> hello <strong>world</strong>", safe_mode=True)
u'<p>[HTML_REMOVED]</p>\n<p>hello [HTML_REMOVED]world[HTML_REMOVED]</p>'

Set completo di opzioni per safe_mode disponibile nella pagina della documentazione - che menziona anche se enable_attributes È impostato su False per sicurezza.

13
Yoav Aner