Come si usa Markdown in modo sicuro?

41

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 fidati di inserire il contenuto (in formato Markdown). Userò il processore Markdown per generare HTML e mi piacerebbe includere quell'HTML nella mia pagina web. Cosa devo fare per assicurarmi che sia sicuro e non sia una vulnerabilità XSS autoinflitta? Quali argomenti devo passare? C'è qualche pre-elaborazione o postelaborazione che devo fare? Sto usando la libreria python-markdown, se pertinente.

    
posta D.W. 06.05.2012 - 05:51
fonte

2 risposte

14

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

Assicurati di avere una versione aggiornata della libreria Markdown, in quanto le versioni precedenti presentano alcuni problemi di sicurezza.

Potresti anche 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 di markdown di Python saranno disabilitano enable_attributes di default se imposti safe_mode , le versioni precedenti non lo facevano. Di conseguenza, 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 a meno che non si imposti 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 riguardo a questi problemi. Dice cose come "Si potrebbe anche voler impostare enable_attributes=False quando si usa safe_mode ", senza rivelare che non riuscendo a farlo si crea un buco XSS con tutte le ultime versioni della libreria. Versioni successive della documentazione dicono che l'impostazione di enable_attributes "potrebbe potenzialmente consentire ad un utente non fidato 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 molto insicuro se il Markdown provenga da una fonte non attendibile.

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

"safe-mode" was a poor name choice that we continue to use for backward comparability (old code still works with our newer versions). What it really is is a no-markup mode. In other words, it is just a way to disallow raw html and really doesn't guarantee safety.

Quei tipi di commenti sono un po 'spaventosi.

Nelle precedenti versioni della libreria Python Markdown, la sua sanitizzazione HTML mi sembra un po 'fragile, quindi non sono sicuro se mi fiderei delle versioni precedenti della libreria Markdown, indipendentemente da quali flag vengono 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 agli URL javascript: -style tramite l'elaborazione di Markdown mi sembra una decisione di design piuttosto discutibile. Sembra che si tratti di un salto, di un salto e di un salto di XSS. Tutto ciò che manca è un modo per rompere il commento in stile C ++ (il // ), ed è game over. Ad 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 so, ma non mi sta dando sensazioni calde e confuse. Se è sicuro, è solo cieca fortuna.

Fortunatamente, l'ultima versione rilasciata di Markdown sembra fare un filtraggio più rigoroso dello script se si imposta enable_attributes=False . Ma assicurati di impostare enable_attributes=False , altrimenti Markdown ricade sulla fragile sanitizzazione HTML trovata nelle versioni precedenti e non sono sicuro della sicurezza di tale schema.

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

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

Se usi Django. Se usi Django, il seguente 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 . Ma assicurati di aggiornare a Django 1.4 o versioni successive; nelle versioni precedenti, questo utilizzo non era sicuro .

    
risposta data 06.05.2012 - 22:46
fonte
13

Markdown da solo non sarebbe sufficiente per santizing l'output, dal momento che consente l'input HTML / Javascript arbitrario e semplicemente lo passa non elaborato.

es. questo è un markdown valido:

## heading

text

Ma anche questo:

## heading

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

Dalla pagina di sintassi del markdown :

For any markup that is not covered by Markdown’s syntax, you simply use HTML itself. There’s no need to preface it or delimit it to indicate that you’re switching from Markdown to HTML; you just use the tags.

Ho appena fatto un rapido test usando python-markdown e sembra che funzioni in questo modo.

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

UPDATE:

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

Ho quindi cercato ulteriormente e ho scoperto il parametro safe_mode ( menzionato qui e here ).

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 di opzioni completo per safe_mode disponibile nella pagina della documentazione - che indica anche come enable_attributes impostato a False per sicurezza.

    
risposta data 06.05.2012 - 12:00
fonte

Leggi altre domande sui tag