src/AppBundle/EventSubscriber/XSSSubscriber.php line 18

Open in your IDE?
  1. <?php
  2. namespace AppBundle\EventSubscriber;
  3. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  4. use Symfony\Component\HttpKernel\Event\RequestEvent;
  5. use Symfony\Component\HttpKernel\KernelEvents;
  6. class XSSSubscriber implements EventSubscriberInterface
  7. {
  8.     public static function getSubscribedEvents(): array
  9.     {
  10.         return [
  11.             KernelEvents::REQUEST => ['onKernelRequest'1000],
  12.         ];
  13.     }
  14.     public function onKernelRequest(RequestEvent $event): void
  15.     {
  16.         $postValues $event->getRequest()->request->all();
  17.         if (count($postValues) > 0) {
  18.             $postValues $this->getProtectedValues($postValues);
  19.             $event->getRequest()->request->replace($postValues);
  20.         }
  21.         $getValues $event->getRequest()->query->all();
  22.         if (count($getValues) > 0) {
  23.             $getValues $this->getProtectedValues($getValues);
  24.             $event->getRequest()->query->replace($getValues);
  25.         }
  26.     }
  27.     private function getProtectedValues(array &$data): array
  28.     {
  29.         foreach ($data as $key => &$value) {
  30.             if (is_array($value)) {
  31.                 $this->getProtectedValues($value);
  32.             } else {
  33.                 $data[$key] = $this->filterText($value);
  34.             }
  35.         }
  36.         return $data;
  37.     }
  38.     private function filterText(?string $value): string
  39.     {
  40.         if(null === $value || '' === trim($value)) {
  41.             return '';
  42.         }
  43.         return $this->escapeJsEvent($this->removeScriptTag(trim($value)));
  44.     }
  45.     private function escapeJsEvent(string $value): string
  46.     {
  47.         /** @var string $value */
  48.         $value = (string) preg_replace('/(<.+?)(?<=\s)on[a-z]+\s*=\s*(?:([\'"])(?!\2).+?\2|(?:\S+?\(.*?\)(?=[\s>])))(.*?>)/i'"$1 $3"$value);
  49.         return $value;
  50.     }
  51.     private function removeScriptTag(string $text): string
  52.     {
  53.         $search = [
  54.             sprintf("'<%s[^>]*?>.*?</%s>'si"'script''script'),
  55.             sprintf("'<%s[^>]*?>.*?</%s>'si"'iframe''iframe'),
  56.         ];
  57.         /** @var string $text */
  58.         $text = (string) preg_replace($search, [''''], $text);
  59.         return (string) preg_replace_callback("'&#(\d+);'", static function ($m) { return chr($m[1]); }, $text);
  60.     }
  61. }