Purificatore HTML: rimozione di un elemento in base ai suoi attributi

Come per il purificatore HTML , gli URI "malformati" vengono occasionalmente scartati per lasciare un tag di ancoraggio senza attributi, ad esempio

<a href="javascript:document.location='http://www.google.com/'">XSS</a> diventa <a>XSS</a>

… e occasionalmente vengono ridotti al protocollo, ad es

<a href="http://1113982867/">XSS</a> diventa <a href="http:/">XSS</a>

Anche se non è problematico, di per sé, è un po 'brutto. Invece di provare a eliminarli con espressioni regolari, speravo di utilizzare le funzionalità della libreria / iniettori / plug-in / whathaveyou di HTML Purifier.

Punto di riferimento: gestione degli attributi

La rimozione condizionale di un attributo in HTMLPurifier è semplice. Qui la libreria offre la class HTMLPurifier_AttrTransform con il metodo confiscateAttr() .

Anche se non utilizzo personalmente la funzionalità di confiscateAttr() , utilizzo un HTMLPurifier_AttrTransform come da questa discussione per aggiungere target="_blank" a tutti gli anchor.

 // more configuration stuff up here $htmlDef = $htmlPurifierConfiguration->getHTMLDefinition(true); $anchor = $htmlDef->addBlankElement('a'); $anchor->attr_transform_post[] = new HTMLPurifier_AttrTransform_Target(); // purify down here 

HTMLPurifier_AttrTransform_Target è una class molto semplice, ovviamente.

 class HTMLPurifier_AttrTransform_Target extends HTMLPurifier_AttrTransform { public function transform($attr, $config, $context) { // I could call $this->confiscateAttr() here to throw away an // undesired attribute $attr['target'] = '_blank'; return $attr; } } 

Quella parte funziona come un incantesimo, naturalmente.

Gestione degli elementi

Forse non sto guardando abbastanza bene in HTMLPurifier_TagTransform , o sto cercando nei posti sbagliati, o in generale non riesco a capirlo, ma non riesco a capire un modo per rimuovere gli elementi in modo condizionale.

Dì, qualcosa all'effetto di:

 // more configuration stuff up here $htmlDef = $htmlPurifierConfiguration->getHTMLDefinition(true); $anchor = $htmlDef->addElementHandler('a'); $anchor->elem_transform_post[] = new HTMLPurifier_ElementTransform_Cull(); // add target as per 'point of reference' here // purify down here 

Con la class Cull estendere qualcosa che ha un'abilità confiscateElement() , o comparabile, in cui posso verificare la presenza di un attributo href mancante o di un attributo href con il contenuto http:/ .

HTMLPurifier_Filter

Capisco che potrei creare un filter, ma gli esempi (Youtube.php e ExtractStyleBlocks.php) suggeriscono che userò espressioni regolari in questo, che preferirei davvero evitare, se ansible . Spero in una soluzione onboard o quasi-onboard che faccia uso delle eccellenti capacità di analisi di HTML Purifier.

Restituire null in una class figlio di HTMLPurifier_AttrTransform purtroppo non lo taglia.

Qualcuno ha qualche idea intelligente, o sono bloccato con espressioni regex? 🙂

Successo! Grazie ad Ambush Commander e mcgrailm in un'altra domanda , sto usando una soluzione esilarante e semplice:

 // a bit of context $htmlDef = $this->configuration->getHTMLDefinition(true); $anchor = $htmlDef->addBlankElement('a'); // HTMLPurifier_AttrTransform_RemoveLoneHttp strips 'href="http:/"' from // all anchor tags (see first post for class detail) $anchor->attr_transform_post[] = new HTMLPurifier_AttrTransform_RemoveLoneHttp(); // this is the magic! We're making 'href' a required attribute (note the // asterisk) - now HTML Purifier removes <a></a>, as well as // <a href="http:/"></a> after HTMLPurifier_AttrTransform_RemoveLoneHttp // is through with it! $htmlDef->addAttribute('a', 'href*', new HTMLPurifier_AttrDef_URI()); 

Funziona, funziona , bahahahaHAHAHAHAnhͥͤͫğͮ͑̆ͦó̓̉ͬ͋hͧ̆̈̉ğ̈͐̈a̾̈̑ͨô̔̄̑̇ḡh̘̝͊̐ͩͥ̋ͤ͛g̦̣̙̙̒ͥ̐̔o̤̣hg͓̈͋̇̓̆ä͖̩̯̥͕̐ͮ̒o̶ͬ̽̍ͮ̾ͮ͢҉̩͉̘͓̙̦̩̹͍̹̠̕g̵̡͔̙͉̠̙̩͚͑ͥ̓͛̋͗̍̽͋͑̈̚ … ! * risate maniacali, rumori gorgoglianti, ribalta con un sorriso sul suo viso *

Il fatto che non sia ansible rimuovere elementi con TagTransform sembra essere stato un dettaglio di implementazione. Il classico meccanismo per la rimozione dei nodes (un livello di smidge più alto rispetto ai soli tag) è quello di utilizzare un iniettore.

Ad each modo, la particolare funzionalità che stai cercando è già implementata come% AutoFormat.RemoveEmpty

Per lettura, questa è la mia soluzione attuale. Funziona, ma ignora completamente il purificatore HTML.

 /** * Removes <a></a> and <a href="http:/"></a> tags from the purified * HTML. * @todo solve this with an injector? * @param string $purified The purified HTML * @return string The purified HTML, sans pointless anchors. */ private function anchorCull($purified) { if (empty($purified)) return ''; // re-parse HTML $domTree = new DOMDocument(); $domTree->loadHTML($purified); // find all anchors (even good ones) $anchors = $domTree->getElementsByTagName('a'); // collect bad anchors (destroying them in this loop breaks the DOM) $destroyNodes = arrays(); for ($i = 0; ($i < $anchors->length); $i++) { $anchor = $anchors->item($i); $href = $anchor->attributes->getNamedItem('href'); // <a></a> if (is_null($href)) { $destroyNodes[] = $anchor; // <a href="http:/"></a> } else if ($href->nodeValue == 'http:/') { $destroyNodes[] = $anchor; } } // destroy the collected nodes foreach ($destroyNodes as $node) { // preserve content $retain = $node->childNodes; for ($i = 0; ($i < $retain->length); $i++) { $rnode = $retain->item($i); $node->parentNode->insertBefore($rnode, $node); } // actually destroy the node $node->parentNode->removeChild($node); } // strip out HTML out of DOM structure string $html = $domTree->saveHTML(); $begin = strpos($html, '<body>') + strlen('<body>'); $end = strpos($html, '</body>'); return substr($html, $begin, $end - $begin); } 

Avrei ancora molto di più una buona soluzione di purificatore HTML per questo, quindi, proprio come un punto a testa, questa risposta non finirà per essere accettata da sé. Ma nel caso in cui nessuna risposta migliore finisca per aggirare, alless potrebbe aiutare quelli con problemi simili. 🙂