We launched new forums in March 2019—join us there. In a hurry for help with your website? Get Help Now!
    • 1887
    • 50 Posts
    Hello

    I am reading about the security issues with that target="_blank" can create where a malicious page can take over the previous tab.

    Is there a way to automatically add rel="noopener" to all external links?

    Kind regards
    James
      • 3749
      • 24,544 Posts
      The only easy way I can think of without hacking the parser code would be a plugin. I think you could attach the plugin to OnWebPagePrerender.

      Something like this:

      if (strpos($modx->resource->_output, '_blank') !== false) {
          $modx->resource->_output = str_replace('target="_blank"', 'target="_blank" rel="noopener noreferrer" ', $modx->resource_output);
      }
      
      return;



      (The noreferrer is to make it work in Firefox.)

      This will slow down your page loads a little. A better method would be to search the site and modify all the resources, templates, and chunks, although that wouldn't fix any hrefs created dynamically in code.

      A snippet to make the modifications would look like this (tested):

      [[!FixHref]]


      /* FixHref snippet */
      $objectTypes = array(
          'modResource' =>  'pagetitle',
          'modChunk' => 'name',
          'modTemplate' => 'name',
      );
      $count = 0;
      $nl = (php_sapi_name() == 'cli')? "\n" : "<br>";
      $output = '';
      
      $typeCounts = array();
      
      foreach ($objectTypes as $type => $nameAlias) {
          $typeCounts[$type] = 0;
          $objs = $modx->getCollection($type);
      
          foreach ($objs as $obj) {
      
              if ($obj->get('class_key') === 'Article') {
                  $content = $obj->get('content');
              } else {
                  $content = $obj->getContent();
              }
      
              if (empty($content)) {
                  // $modx->log(modX::LOG_LEVEL_ERROR, 'Could not get content for ' . $type . ' ' . $obj->get('id'));
                  continue;
              }
      
              if ((strpos($content, '_blank') !== false) && (strpos($content, 'noopener') === false)) {
                  $pattern = '/target\s*=\s*[\'"]_blank[\'"]/i';
                  $newContent = preg_replace($pattern, 'target="_blank" rel="noopener noreferrer" ', $content);
                  $obj->setContent($newContent);
                  if ($obj->save()) {
                      if ($content !== $newContent) {
                          $output .= $nl . 'Modified ' . $type . '  ' . $obj->get($nameAlias);
                      } else {
                          $output .=  $nl . 'Failed to modify ' . $type . '  ' . $obj->get($nameAlias);
                      }
                  }
      
                  $typeCounts[$type]++;
                  $count++;
              }
      
          }
      }
      
      $output .=  $nl . "Finished -- found " . $count . " total objects with _blank and not noopener" . $nl;
      $output .=  "Changed: " . $nl . print_r($typeCounts, true);
      if (php_sapi_name() == 'cli') {
          echo $output;
      } else {
          return $output;
      }
      


      I would back up the DB before running this, just in case. [ed. note: BobRay last edited this post 6 years, 1 month ago.]
        Did I help you? Buy me a beer
        Get my Book: MODX:The Official Guide
        MODX info for everyone: http://bobsguides.com/modx.html
        My MODX Extras
        Bob's Guides is now hosted at A2 MODX Hosting
        • 1887
        • 50 Posts
        Thanks Bob for a very comprehensive reply. As the content in the site in questions does not change that often, I will go with your second suggestion.
          • 3749
          • 24,544 Posts
          Thanks for the kind words.

          BTW, you shouldn't have to modify the Tpl chunks -- the snippet will do it.

          FYI, I'm working on a more reliable version of the snippet.

            Did I help you? Buy me a beer
            Get my Book: MODX:The Official Guide
            MODX info for everyone: http://bobsguides.com/modx.html
            My MODX Extras
            Bob's Guides is now hosted at A2 MODX Hosting