Add rel="noreferrer noopener" when target attribute would open window
authorBrian Wolff <bawolff+wn@gmail.com>
Mon, 25 Apr 2016 18:08:46 +0000 (14:08 -0400)
committerChad Horohoe <chadh@wikimedia.org>
Fri, 20 May 2016 16:49:41 +0000 (09:49 -0700)
noreferrer is used as support for noopener is very limited.
This is to prevent the attack detailed at
https://mathiasbynens.github.io/rel-noopener/ where you can
navigate the parent window, even if the new window is a cross-origin.

Bug: T133507
Change-Id: I6e4ab938861e246ff44048077b94847e303f1859

Signed-off-by: Chad Horohoe <chadh@wikimedia.org>
includes/DefaultSettings.php
includes/Linker.php
includes/parser/Parser.php
tests/parser/parserTests.txt

index 6ebbf32..0e06bce 100644 (file)
@@ -4261,7 +4261,13 @@ $wgDebugTidy = false;
 $wgRawHtml = false;
 
 /**
- * Set a default target for external links, e.g. _blank to pop up a new window
+ * Set a default target for external links, e.g. _blank to pop up a new window.
+ *
+ * This will also set the "noreferrer" and "noopener" link rel to prevent the
+ * attack described at https://mathiasbynens.github.io/rel-noopener/ .
+ * Some older browsers may not support these link attributes, hence
+ * setting $wgExternalLinkTarget to _blank may represent a security risk
+ * to some of your users.
  */
 $wgExternalLinkTarget = false;
 
index 6a869dd..b090817 100644 (file)
@@ -1084,7 +1084,16 @@ class Linker {
                if ( !$title ) {
                        $title = $wgTitle;
                }
-               $attribs['rel'] = Parser::getExternalLinkRel( $url, $title );
+               $newRel = Parser::getExternalLinkRel( $url, $title );
+               if ( !isset( $attribs['rel'] ) || $attribs['rel'] === '' ) {
+                       $attribs['rel'] = $newRel;
+               } elseif( $newRel !== '' ) {
+                       // Merge the rel attributes.
+                       $newRels = explode( ' ', $newRel );
+                       $oldRels = explode( ' ', $attribs['rel'] );
+                       $combined = array_unique( array_merge( $newRels, $oldRels ) );
+                       $attribs['rel'] = implode( ' ', $combined );
+               }
                $link = '';
                $success = Hooks::run( 'LinkerMakeExternalLink',
                        [ &$url, &$text, &$link, &$attribs, $linktype ] );
index a3abcad..b5e5d80 100644 (file)
@@ -1863,11 +1863,22 @@ class Parser {
         */
        public function getExternalLinkAttribs( $url = false ) {
                $attribs = [];
-               $attribs['rel'] = self::getExternalLinkRel( $url, $this->mTitle );
-
-               if ( $this->mOptions->getExternalLinkTarget() ) {
-                       $attribs['target'] = $this->mOptions->getExternalLinkTarget();
+               $rel = self::getExternalLinkRel( $url, $this->mTitle );
+
+               $target = $this->mOptions->getExternalLinkTarget();
+               if ( $target ) {
+                       $attribs['target'] = $target;
+                       if ( !in_array( $target, [ '_self', '_parent', '_top' ] ) ) {
+                               // T133507. New windows can navigate parent cross-origin.
+                               // Including noreferrer due to lacking browser
+                               // support of noopener. Eventually noreferrer should be removed.
+                               if ( $rel !== '' ) {
+                                       $rel .= ' ';
+                               }
+                               $rel .= 'noreferrer noopener';
+                       }
                }
+               $attribs['rel'] = $rel;
                return $attribs;
        }
 
index 2f88f92..5fffde3 100644 (file)
@@ -13159,7 +13159,7 @@ Image with link parameter, wgExternalLinkTarget
 !! config
 wgExternalLinkTarget='foobar'
 !! html/php
-<p><a href="http://example.com/" target="foobar" rel="nofollow"><img alt="Foobar.jpg" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a>
+<p><a href="http://example.com/" target="foobar" rel="nofollow noreferrer noopener"><img alt="Foobar.jpg" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a>
 </p>
 !! end
 
@@ -13193,7 +13193,7 @@ Image with link parameter, wgExternalLinkTarget, unnamed parameter
 !! config
 wgExternalLinkTarget='foobar'
 !! html/php
-<p><a href="http://example.com/" title="Title" target="foobar" rel="nofollow"><img alt="Title" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a>
+<p><a href="http://example.com/" title="Title" target="foobar" rel="nofollow noreferrer noopener"><img alt="Title" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a>
 </p>
 !! end