You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@zeppelin.apache.org by pd...@apache.org on 2021/09/10 11:53:09 UTC

[zeppelin] branch branch-0.10 updated: [ZEPPELIN-5395] Address tab nabbing vulnerability

This is an automated email from the ASF dual-hosted git repository.

pdallig pushed a commit to branch branch-0.10
in repository https://gitbox.apache.org/repos/asf/zeppelin.git


The following commit(s) were added to refs/heads/branch-0.10 by this push:
     new 225b460  [ZEPPELIN-5395] Address tab nabbing vulnerability
225b460 is described below

commit 225b460132704b73a8085902211287eddfeeea94
Author: Aleksandr Iushmanov <iz...@amazon.com>
AuthorDate: Tue Sep 7 14:20:34 2021 +0100

    [ZEPPELIN-5395] Address tab nabbing vulnerability
    
    ### What is this PR for?
    Anchor links that launch new tabs using target="_blank" are vulnerable to tab nabbing
    see: https://owasp.org/www-community/attacks/Reverse_Tabnabbing
    
    ### What type of PR is it?
    Improvement
    
    ### Todos
    * Add rel="noopener noreferrer" to the anchor links (https://cheatsheetseries.owasp.org/cheatsheets/HTML5_Security_Cheat_Sheet.html#tabnabbing)
    
    ### What is the Jira issue?
    https://issues.apache.org/jira/browse/ZEPPELIN-5395
    
    ### How should this be tested?
    Child pages from opened links should not contain referrer info or links to the parent one
    
    ### Screenshots (if appropriate)
    
    ### Questions:
    * Does the licenses files need update?
    No
    * Is there breaking changes for older versions?
    Content of parent pages will no longer be accessed with back referencing from the child ones
    * Does this needs documentation?
    
    Author: Aleksandr Iushmanov <iz...@amazon.com>
    
    Closes #4212 from izeren-amzn/izeren-address-tab-napping-vulnerability and squashes the following commits:
    
    03bdc1cf6 [Aleksandr Iushmanov] [ZEPPELIN-5395] Remove extra rel tags, remove check isPlatformBrowser
    e7d936b57 [Aleksandr Iushmanov] [ZEPPELIN-5395] Address tab nabbing vulnerability for angular using directive
    52e055e6c [Aleksandr Iushmanov] [ZEPPELIN-5395] Fix too long line
    cd72175a7 [Aleksandr Iushmanov] [ZEPPELIN-5395] fix more anchors with tab napping vulnerability
    957596a3a [Aleksandr Iushmanov] [ZEPPELIN-5395] Fix tab nabbing vulnerability
    
    (cherry picked from commit 0796bf9d4ed4791b1fe87d867c6d2cce10525bc8)
    Signed-off-by: Philipp Dallig <ph...@gmail.com>
---
 cassandra/src/main/resources/scalate/helpMenu.ssp  | 18 +++++-----
 docs/_includes/themes/zeppelin/_navigation.html    |  6 ++--
 docs/interpreter/cassandra.md                      |  6 ++--
 docs/interpreter/jdbc.md                           | 38 ++++++++++----------
 docs/setup/operation/configuration.md              |  2 +-
 .../ui_templates/submarine-dashboard.jinja         |  6 ++--
 .../external-links/external-link.directive.ts      | 41 ++++++++++++++++++++++
 zeppelin-web-angular/src/app/share/share.module.ts |  5 +--
 zeppelin-web/src/app/credential/credential.html    |  1 +
 zeppelin-web/src/app/helium/helium.controller.js   |  4 +--
 zeppelin-web/src/app/helium/helium.html            |  4 ++-
 zeppelin-web/src/app/home/home.html                |  8 ++---
 .../src/app/interpreter/interpreter-create.html    |  2 +-
 zeppelin-web/src/app/interpreter/interpreter.html  |  4 +--
 .../src/app/notebook/notebook-actionBar.html       |  2 +-
 .../src/app/notebook/notebook.controller.js        |  3 +-
 .../app/notebook/paragraph/paragraph-control.html  |  6 ++--
 zeppelin-web/src/components/navbar/navbar.html     |  4 +--
 18 files changed, 103 insertions(+), 57 deletions(-)

diff --git a/cassandra/src/main/resources/scalate/helpMenu.ssp b/cassandra/src/main/resources/scalate/helpMenu.ssp
index 8ed2ae2..80fc994 100644
--- a/cassandra/src/main/resources/scalate/helpMenu.ssp
+++ b/cassandra/src/main/resources/scalate/helpMenu.ssp
@@ -219,7 +219,7 @@
                                     <tr>
                                         <td style="text-align:left"><strong>3.x</strong></td>
                                         <td style="text-align:left">
-                                            <a href="http://docs.datastax.com/en/cql/3.3/cql/cqlIntro.html" target="_blank">
+                                            <a href="http://docs.datastax.com/en/cql/3.3/cql/cqlIntro.html" target="_blank" rel="noopener noreferrer">
                                             http://docs.datastax.com/en/cql/3.3/cql/cqlIntro.html
                                             </a>
                                         </td>
@@ -227,7 +227,7 @@
                                         <tr>
                                             <td style="text-align:left"><strong>2.2</strong></td>
                                             <td style="text-align:left">
-                                                <a href="http://docs.datastax.com/en/cql/3.3/cql/cqlIntro.html" target="_blank">
+                                                <a href="http://docs.datastax.com/en/cql/3.3/cql/cqlIntro.html" target="_blank" rel="noopener noreferrer">
                                                     http://docs.datastax.com/en/cql/3.3/cql/cqlIntro.html
                                                 </a>
                                             </td>
@@ -235,7 +235,7 @@
                                         <tr>
                                             <td style="text-align:left"><strong>2.1</strong></td>
                                             <td style="text-align:left">
-                                                <a href="http://docs.datastax.com/en/cql/3.1/cql/cql_intro_c.html" target="_blank">
+                                                <a href="http://docs.datastax.com/en/cql/3.1/cql/cql_intro_c.html" target="_blank" rel="noopener noreferrer">
                                                     http://docs.datastax.com/en/cql/3.1/cql/cql_intro_c.html
                                                 </a>
                                             </td>
@@ -778,7 +778,7 @@ select id, double, float, text, date, time, timestamp from zep.test_format;</pre
                             <li><strong>null</strong> is parsed as-is</li>
                             <li><strong>boolean</strong> (true|false) are parsed as-is </li>
                             <li>collection values must follow the
-                                <a href="http://docs.datastax.com/en/cql/3.1/cql/cql_using/use_collections_c.html" target="_blank">standard CQL syntax</a>:
+                                <a href="http://docs.datastax.com/en/cql/3.1/cql/cql_using/use_collections_c.html" target="_blank" rel="noopener noreferrer">standard CQL syntax</a>:
                                 <ul>
                                     <li>list:  [‘list_item1’, ’list_item2’, ...]</li>
                                     <li>set: {‘set_item1’, ‘set_item2’, …}</li>
@@ -787,12 +787,12 @@ select id, double, float, text, date, time, timestamp from zep.test_format;</pre
                             </li>
                             <li>
                                 tuple values should be enclosed between parenthesis
-                                (see <a href="http://docs.datastax.com/en/cql/3.1/cql/cql_reference/tupleType.html" target="_blank">tuple CQL syntax</a>):
+                                (see <a href="http://docs.datastax.com/en/cql/3.1/cql/cql_reference/tupleType.html" target="_blank" rel="noopener noreferrer">tuple CQL syntax</a>):
                                 (‘text’, 123, true)
                             </li>
                             <li>
                                 udt values should be enclosed between brackets
-                                (see <a href="http://docs.datastax.com/en/cql/3.1/cql/cql_using/cqlUseUDT.html" target="_blank">udt CQL syntax</a>):
+                                (see <a href="http://docs.datastax.com/en/cql/3.1/cql/cql_using/cqlUseUDT.html" target="_blank" rel="noopener noreferrer">udt CQL syntax</a>):
                                 {stree_name: ‘Beverly Hills’,  number: 104, zip_code: 90020, state: ‘California’, …}
                             </li>
                         </ul>
@@ -834,7 +834,7 @@ select id, double, float, text, date, time, timestamp from zep.test_format;</pre
                   <div class="panel-body">
                     <p>
                         Instead of hard-coding your CQL queries, it is possible to use <strong>
-                        <a href="http://zeppelin.apache.org/docs/0.6.0-SNAPSHOT/manual/dynamicform.html" target="_blank">Zeppelin dynamic form</a>
+                        <a href="http://zeppelin.apache.org/docs/0.6.0-SNAPSHOT/manual/dynamicform.html" target="_blank" rel="noopener noreferrer">Zeppelin dynamic form</a>
                         </strong> syntax to inject simple value or multiple choices forms.
 
                         The legacy mustache syntax (  <strong>{{ }}</strong> ) to bind input text and select form is still supported but is deprecated and will be removed in future releases.
@@ -1050,7 +1050,7 @@ select id, double, float, text, date, time, timestamp from zep.test_format;</pre
                It is possible to execute many paragraphs in parallel. However, at the back-end side, we’re still using synchronous queries. <em>Asynchronous execution</em> is only possible when it is possible to return a <strong>Future</strong> value in the <strong>InterpreterResult</strong>. It may be an interesting proposal for the <strong>Zeppelin</strong> project.
                <br/><br/>
                Recently, <strong>Zeppelin</strong> allows you to choose the level of isolation for your interpreters (see
-               <strong><a href="http://zeppelin.apache.org/docs/0.6.0-SNAPSHOT/manual/interpreters.html" target="_blank">Interpreter Binding Mode</a></strong> ).
+               <strong><a href="http://zeppelin.apache.org/docs/0.6.0-SNAPSHOT/manual/interpreters.html" target="_blank" rel="noopener noreferrer">Interpreter Binding Mode</a></strong> ).
                <br/><br/>
                Long story short, you have 3 available bindings:
 
@@ -1137,7 +1137,7 @@ select id, double, float, text, date, time, timestamp from zep.test_format;</pre
         </div>        
         <div id="${contactsId}" class="panel-collapse collapse" role="tabpanel">
             <div class="panel-body">
-                If you encounter a bug for this interpreter, please create a <a href="https://issues.apache.org/jira/browse/ZEPPELIN" target="_blank"><strong>JIRA</strong></a> ticket.</a>
+                If you encounter a bug for this interpreter, please create a <a href="https://issues.apache.org/jira/browse/ZEPPELIN" target="_blank" rel="noopener noreferrer"><strong>JIRA</strong></a> ticket.</a>
             </div>
         </div>            
     </div>    
diff --git a/docs/_includes/themes/zeppelin/_navigation.html b/docs/_includes/themes/zeppelin/_navigation.html
index 3459856..0c2acf7 100644
--- a/docs/_includes/themes/zeppelin/_navigation.html
+++ b/docs/_includes/themes/zeppelin/_navigation.html
@@ -192,9 +192,9 @@
                 <li><a href="{{BASE_PATH}}/development/contribution/how_to_contribute_website.html">How to Contribute (website)</a></li>
                 <li role="separator" class="divider"></li>
                 <li class="title"><span>External Resources</span></li>
-                <li><a target="_blank" href="https://zeppelin.apache.org/community.html">Mailing List</a></li>
-                <li><a target="_blank" href="https://cwiki.apache.org/confluence/display/ZEPPELIN/Zeppelin+Home">Apache Zeppelin Wiki</a></li>
-                <li><a target="_blank" href="http://stackoverflow.com/questions/tagged/apache-zeppelin">Stackoverflow Questions about Zeppelin</a></li>
+                <li><a target="_blank" rel="noopener noreferrer" href="https://zeppelin.apache.org/community.html">Mailing List</a></li>
+                <li><a target="_blank" rel="noopener noreferrer" href="https://cwiki.apache.org/confluence/display/ZEPPELIN/Zeppelin+Home">Apache Zeppelin Wiki</a></li>
+                <li><a target="_blank" rel="noopener noreferrer" href="http://stackoverflow.com/questions/tagged/apache-zeppelin">Stackoverflow Questions about Zeppelin</a></li>
               </ul>
             </li>
             <li>
diff --git a/docs/interpreter/cassandra.md b/docs/interpreter/cassandra.md
index 0de7b51..a49ae7e 100644
--- a/docs/interpreter/cassandra.md
+++ b/docs/interpreter/cassandra.md
@@ -163,7 +163,7 @@ The complete list of all CQL statements and versions can be found below:
    <tr>
      <td><strong>3.x</strong></td>
      <td>
-        <a target="_blank"
+        <a target="_blank" rel="noopener noreferrer"
           href="https://docs.datastax.com/en/archived/cql/3.3/cql/cqlIntro.html">
           https://docs.datastax.com/en/archived/cql/3.3/cql/cqlIntro.html
         </a>
@@ -172,7 +172,7 @@ The complete list of all CQL statements and versions can be found below:
    <tr>
      <td><strong>2.2</strong></td>
      <td>
-        <a target="_blank"
+        <a target="_blank" rel="noopener noreferrer"
           href="https://docs.datastax.com/en/archived/cql/3.3/cql/cqlIntro.html">
           https://docs.datastax.com/en/archived/cql/3.3/cql/cqlIntro.html
         </a>
@@ -181,7 +181,7 @@ The complete list of all CQL statements and versions can be found below:
    <tr>
      <td><strong>2.1</strong></td>
      <td>
-        <a target="_blank"
+        <a target="_blank" rel="noopener noreferrer"
           href="http://docs.datastax.com/en/cql/3.1/cql/cql_intro_c.html">
           http://docs.datastax.com/en/cql/3.1/cql/cql_intro_c.html
         </a>
diff --git a/docs/interpreter/jdbc.md b/docs/interpreter/jdbc.md
index 081e64f..cb0a6db 100644
--- a/docs/interpreter/jdbc.md
+++ b/docs/interpreter/jdbc.md
@@ -37,43 +37,43 @@ By now, it has been tested with:
   </div>
   <div class="col-md-6">
     <li style="padding-bottom: 5px; list-style: circle">
-      <a href="http://www.postgresql.org/" target="_blank">Postgresql</a> -
-      <a href="https://jdbc.postgresql.org/" target="_blank">JDBC Driver</a>
+      <a href="http://www.postgresql.org/" target="_blank" rel="noopener noreferrer">Postgresql</a> -
+      <a href="https://jdbc.postgresql.org/" target="_blank" rel="noopener noreferrer">JDBC Driver</a>
     </li>
     <li style="padding-bottom: 5px; list-style: circle">
-      <a href="https://www.mysql.com/" target="_blank">Mysql</a> -
-      <a href="https://dev.mysql.com/downloads/connector/j/" target="_blank">JDBC Driver</a>
+      <a href="https://www.mysql.com/" target="_blank" rel="noopener noreferrer">Mysql</a> -
+      <a href="https://dev.mysql.com/downloads/connector/j/" target="_blank" rel="noopener noreferrer">JDBC Driver</a>
     </li>
     <li style="padding-bottom: 5px; list-style: circle">
-      <a href="https://mariadb.org/" target="_blank">MariaDB</a> -
-      <a href="https://mariadb.com/kb/en/mariadb/about-mariadb-connector-j/" target="_blank">JDBC Driver</a>
+      <a href="https://mariadb.org/" target="_blank" rel="noopener noreferrer">MariaDB</a> -
+      <a href="https://mariadb.com/kb/en/mariadb/about-mariadb-connector-j/" target="_blank" rel="noopener noreferrer">JDBC Driver</a>
     </li>
     <li style="padding-bottom: 5px; list-style: circle">
-      <a href="https://aws.amazon.com/documentation/redshift/" target="_blank">Redshift</a> -
-      <a href="https://docs.aws.amazon.com/redshift/latest/mgmt/configure-jdbc-connection.html" target="_blank">JDBC Driver</a>
+      <a href="https://aws.amazon.com/documentation/redshift/" target="_blank" rel="noopener noreferrer">Redshift</a> -
+      <a href="https://docs.aws.amazon.com/redshift/latest/mgmt/configure-jdbc-connection.html" target="_blank" rel="noopener noreferrer">JDBC Driver</a>
     </li>
     <li style="padding-bottom: 5px; list-style: circle">
-      <a href="https://hive.apache.org/" target="_blank">Apache Hive</a> - 
-      <a href="https://cwiki.apache.org/confluence/display/Hive/HiveServer2+Clients#HiveServer2Clients-JDBC" target="_blank">JDBC Driver</a>
+      <a href="https://hive.apache.org/" target="_blank" rel="noopener noreferrer">Apache Hive</a> - 
+      <a href="https://cwiki.apache.org/confluence/display/Hive/HiveServer2+Clients#HiveServer2Clients-JDBC" target="_blank" rel="noopener noreferrer">JDBC Driver</a>
     </li>
     <li style="padding-bottom: 5px; list-style: circle">
-      <a href="https://trino.io/" target="_blank">Presto/Trino</a> - 
-      <a href="https://trino.io/docs/current/installation/jdbc.html" target="_blank">JDBC Driver</a>
+      <a href="https://trino.io/" target="_blank" rel="noopener noreferrer">Presto/Trino</a> - 
+      <a href="https://trino.io/docs/current/installation/jdbc.html" target="_blank" rel="noopener noreferrer">JDBC Driver</a>
     </li>
     <li style="padding-bottom: 5px; list-style: circle">
-      <a href="https://impala.apache.org/" target="_blank">Impala</a> - 
-      <a href="https://impala.apache.org/docs/build/html/topics/impala_jdbc.html" target="_blank">JDBC Driver</a>
+      <a href="https://impala.apache.org/" target="_blank" rel="noopener noreferrer">Impala</a> - 
+      <a href="https://impala.apache.org/docs/build/html/topics/impala_jdbc.html" target="_blank" rel="noopener noreferrer">JDBC Driver</a>
     </li>
     <li style="padding-bottom: 5px; list-style: circle">
-      <a href="https://phoenix.apache.org/" target="_blank">Apache Phoenix</a> itself is a JDBC driver
+      <a href="https://phoenix.apache.org/" target="_blank" rel="noopener noreferrer">Apache Phoenix</a> itself is a JDBC driver
     </li>
     <li style="padding-bottom: 5px; list-style: circle">
-      <a href="https://drill.apache.org/" target="_blank">Apache Drill</a> - 
-      <a href="https://drill.apache.org/docs/using-the-jdbc-driver" target="_blank">JDBC Driver</a>
+      <a href="https://drill.apache.org/" target="_blank" rel="noopener noreferrer">Apache Drill</a> - 
+      <a href="https://drill.apache.org/docs/using-the-jdbc-driver" target="_blank" rel="noopener noreferrer">JDBC Driver</a>
     </li>
     <li style="padding-bottom: 5px; list-style: circle">
-      <a href="http://tajo.apache.org/" target="_blank">Apache Tajo</a> - 
-      <a href="https://tajo.apache.org/docs/current/jdbc_driver.html" target="_blank">JDBC Driver</a>
+      <a href="http://tajo.apache.org/" target="_blank" rel="noopener noreferrer">Apache Tajo</a> - 
+      <a href="https://tajo.apache.org/docs/current/jdbc_driver.html" target="_blank" rel="noopener noreferrer">JDBC Driver</a>
     </li>
   </div>
 </div>
diff --git a/docs/setup/operation/configuration.md b/docs/setup/operation/configuration.md
index 32d5015..9e12345 100644
--- a/docs/setup/operation/configuration.md
+++ b/docs/setup/operation/configuration.md
@@ -53,7 +53,7 @@ Sources descending by priority:
     <td>8080</td>
     <td>Zeppelin server port </br>
       <span style="font-style:italic; color: gray"> Note: Please make sure you're not using the same port with
-      <a href="https://zeppelin.apache.org/contribution/webapplication.html#dev-mode" target="_blank">Zeppelin web application development port</a> (default: 9000).</span></td>
+      <a href="https://zeppelin.apache.org/contribution/webapplication.html#dev-mode" target="_blank" rel="noopener noreferrer">Zeppelin web application development port</a> (default: 9000).</span></td>
   </tr>
   <tr>
     <td><h6 class="properties">ZEPPELIN_SSL_PORT</h6></td>
diff --git a/submarine/src/main/resources/ui_templates/submarine-dashboard.jinja b/submarine/src/main/resources/ui_templates/submarine-dashboard.jinja
index 54ba679..d998592 100644
--- a/submarine/src/main/resources/ui_templates/submarine-dashboard.jinja
+++ b/submarine/src/main/resources/ui_templates/submarine-dashboard.jinja
@@ -31,16 +31,16 @@
           tooltip-placement="top" uib-tooltip="Create Tensorboard">  Create Tensorboard
         </button>
         <a ng-if="TENSORBOARD_URL!=undefined" class="btn btn-default btn-xs" style="margin-left:20px;"
-          ng-href="{%raw%}{{TENSORBOARD_URL}}{%endraw%}" target="_blank" tooltip-placement="top" uib-tooltip="View training in Tensorboard">
+          ng-href="{%raw%}{{TENSORBOARD_URL}}{%endraw%}" target="_blank" rel="noopener noreferrer" tooltip-placement="top" uib-tooltip="View training in Tensorboard">
           <span class="icon-share-alt shortcut-icon" style="font-size:12px;"></span> Tensorboard
         </a>
         <a ng-if="YARN_TENSORBOARD_URL!=undefined" class="btn btn-default btn-xs" style="margin-left:4px;"
-          ng-href="{%raw%}{{YARN_TENSORBOARD_URL}}{%endraw%}" target="_blank" tooltip-placement="top" uib-tooltip="View tensorboard on YARN WEB">
+          ng-href="{%raw%}{{YARN_TENSORBOARD_URL}}{%endraw%}" target="_blank" rel="noopener noreferrer" tooltip-placement="top" uib-tooltip="View tensorboard on YARN WEB">
           <span class="icon-share-alt shortcut-icon" style="font-size:12px;"></span> Tensorboard on YARN
         </a>
 
         <a ng-if="YARN_APPLICATION_URL!=undefined" class="btn btn-default btn-xs" style="margin-left:4px;"
-          ng-href="{%raw%}{{YARN_APPLICATION_URL}}{%endraw%}" target="_blank" tooltip-placement="top" uib-tooltip="View application on YARN WEB">
+          ng-href="{%raw%}{{YARN_APPLICATION_URL}}{%endraw%}" target="_blank" rel="noopener noreferrer" tooltip-placement="top" uib-tooltip="View application on YARN WEB">
           <span class="icon-share-alt shortcut-icon" style="font-size:12px;"></span> Job on YARN
         </a>
         <button class="btn btn-default btn-xs" style="margin-left:4px;"
diff --git a/zeppelin-web-angular/src/app/share/external-links/external-link.directive.ts b/zeppelin-web-angular/src/app/share/external-links/external-link.directive.ts
new file mode 100644
index 0000000..3eade7c
--- /dev/null
+++ b/zeppelin-web-angular/src/app/share/external-links/external-link.directive.ts
@@ -0,0 +1,41 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { Directive, HostBinding, Input, ElementRef } from '@angular/core';
+
+@Directive({
+  selector: 'a[href]',
+})
+export class ExternalLinkDirective {
+  @HostBinding('attr.rel') relAttr = null;
+  @HostBinding('attr.target') targetAttr = null;
+  @Input() href: string;
+
+  constructor(private elementRef: ElementRef) {}
+
+  ngOnChanges() {
+    this.elementRef.nativeElement.href = this.href;
+
+    if (this.isLinkExternal()) {
+      // https://developers.google.com/web/tools/lighthouse/audits/noopener
+      this.relAttr = 'noopener noreferrer';
+      this.targetAttr = '_blank';
+    } else {
+      this.relAttr = null;
+      this.targetAttr = null;
+    }
+  }
+
+  private isLinkExternal() {
+    return !this.elementRef.nativeElement.hostname.includes(location.hostname);
+  }
+}
diff --git a/zeppelin-web-angular/src/app/share/share.module.ts b/zeppelin-web-angular/src/app/share/share.module.ts
index ce75d65..1070a7b 100644
--- a/zeppelin-web-angular/src/app/share/share.module.ts
+++ b/zeppelin-web-angular/src/app/share/share.module.ts
@@ -51,6 +51,7 @@ import { NoteTocComponent } from '@zeppelin/share/note-toc/note-toc.component';
 import { PageHeaderComponent } from '@zeppelin/share/page-header/page-header.component';
 import { HumanizeBytesPipe } from '@zeppelin/share/pipes';
 import { RunScriptsDirective } from '@zeppelin/share/run-scripts/run-scripts.directive';
+import { ExternalLinkDirective } from "@zeppelin/share/external-links/external-link.directive";
 import { SpinComponent } from '@zeppelin/share/spin/spin.component';
 import { Ng1MigrationComponent } from './ng1-migration/ng1-migration.component';
 import { ResizeHandleComponent } from './resize-handle';
@@ -74,9 +75,9 @@ const EXPORT_LIST = [
 const PIPES = [HumanizeBytesPipe];
 
 @NgModule({
-  declarations: [MODAL_LIST, EXPORT_LIST, PIPES, MathJaxDirective, RunScriptsDirective],
+  declarations: [MODAL_LIST, EXPORT_LIST, PIPES, MathJaxDirective, RunScriptsDirective, ExternalLinkDirective],
   entryComponents: [MODAL_LIST],
-  exports: [EXPORT_LIST, PIPES, MathJaxDirective, RunScriptsDirective, CodeEditorModule],
+  exports: [EXPORT_LIST, PIPES, MathJaxDirective, RunScriptsDirective, ExternalLinkDirective, CodeEditorModule],
   imports: [
     FormsModule,
     CommonModule,
diff --git a/zeppelin-web/src/app/credential/credential.html b/zeppelin-web/src/app/credential/credential.html
index c2dbc54..8d38880 100644
--- a/zeppelin-web/src/app/credential/credential.html
+++ b/zeppelin-web/src/app/credential/credential.html
@@ -21,6 +21,7 @@ limitations under the License.
         <div class="pull-right" style="margin-top:10px;">
           <a style="cursor:pointer;margin-right:10px;text-decoration:none;"
              target="_blank"
+             rel="noopener noreferrer"
              ng-href="{{getCredentialDocsLink()}}"
              tooltip-placement="bottom" uib-tooltip="Learn more">
             <i class="icon-question" ng-style="{color: showRepositoryInfo ? '#3071A9' : 'black' }"></i>
diff --git a/zeppelin-web/src/app/helium/helium.controller.js b/zeppelin-web/src/app/helium/helium.controller.js
index e409393..8de38a0 100644
--- a/zeppelin-web/src/app/helium/helium.controller.js
+++ b/zeppelin-web/src/app/helium/helium.controller.js
@@ -185,9 +185,9 @@ export default function HeliumCtrl($scope, $rootScope, $sce,
 
   const getHeliumTypeText = function(type) {
     if (type === HeliumType.VISUALIZATION) {
-      return `<a target="_blank" href="https://zeppelin.apache.org/docs/${$rootScope.zeppelinVersion}/development/helium/writing_visualization.html">${type}</a>`; // eslint-disable-line max-len
+      return `<a target="_blank" rel="noopener noreferrer" href="https://zeppelin.apache.org/docs/${$rootScope.zeppelinVersion}/development/helium/writing_visualization.html">${type}</a>`; // eslint-disable-line max-len
     } else if (type === HeliumType.SPELL) {
-      return `<a target="_blank" href="https://zeppelin.apache.org/docs/${$rootScope.zeppelinVersion}/development/helium/writing_spell.html">${type}</a>`; // eslint-disable-line max-len
+      return `<a target="_blank" rel="noopener noreferrer" href="https://zeppelin.apache.org/docs/${$rootScope.zeppelinVersion}/development/helium/writing_spell.html">${type}</a>`; // eslint-disable-line max-len
     } else {
       return type;
     }
diff --git a/zeppelin-web/src/app/helium/helium.html b/zeppelin-web/src/app/helium/helium.html
index 9d0628c..a28d8b8 100644
--- a/zeppelin-web/src/app/helium/helium.html
+++ b/zeppelin-web/src/app/helium/helium.html
@@ -21,6 +21,7 @@ limitations under the License.
         </h3>
         <div class="pull-right heliumLearnMore">
           <a target="_blank"
+             rel="noopener noreferrer"
              class="helium-repo-btn"
              ng-href="https://zeppelin.apache.org/helium_packages.html"
              tooltip-placement="bottom" uib-tooltip="Learn more">
@@ -89,13 +90,14 @@ limitations under the License.
                ng-bind-html=intpDefaultIcon></div>
           <div class="heliumPackageName">
             <span ng-if="hasNpmLink(pkgSearchResult)">
-              <a target="_blank" href="https://www.npmjs.com/package/{{pkgSearchResult.pkg.name}}">{{pkgSearchResult.pkg.name}}</a>
+              <a target="_blank" rel="noopener noreferrer" href="https://www.npmjs.com/package/{{pkgSearchResult.pkg.name}}">{{pkgSearchResult.pkg.name}}</a>
             </span>
             <span ng-if="!hasNpmLink(pkgSearchResult) && !hasMavenLink(pkgSearchResult)" ng-class="{'heliumLocalPackage': isLocalPackage(pkgSearchResult)}">
               {{pkgSearchResult.pkg.name}}
             </span>
             <span ng-if="hasMavenLink(pkgSearchResult)">
               <a target="_blank"
+                 rel="noopener noreferrer"
                  href="http://search.maven.org/#search%7Cga%7C1%7Ca%3A%22{{pkgSearchResult.pkg.artifact.split('@')[0]}}%22%20AND%20v%3A%22{{pkgSearchResult.pkg.artifact.split('@')[1]}}%22">
                  {{pkgSearchResult.pkg.name}}
               </a>
diff --git a/zeppelin-web/src/app/home/home.html b/zeppelin-web/src/app/home/home.html
index 0285754..b34d07e 100644
--- a/zeppelin-web/src/app/home/home.html
+++ b/zeppelin-web/src/app/home/home.html
@@ -57,18 +57,18 @@ limitations under the License.
         </div>
         <div class="col-md-6">
           <h4>Help</h4>
-          Get started with <a style="text-decoration: none;" target="_blank"
+          Get started with <a style="text-decoration: none;" target="_blank" rel="noopener noreferrer"
                               href="http://zeppelin.apache.org/docs/{{zeppelinVersion}}/index.html">Zeppelin documentation</a><br/>
 
           <h4>Community</h4>
           Please feel free to help us to improve Zeppelin, <br/>
           Any contribution are welcome!<br/><br/>
           <a style="text-decoration: none;" href="http://zeppelin.apache.org/community.html"
-             target="_blank"><i style="font-size: 15px;" class="fa fa-users"></i> Mailing list</a><br/>
+             target="_blank" rel="noopener noreferrer"><i style="font-size: 15px;" class="fa fa-users"></i> Mailing list</a><br/>
           <a style="text-decoration: none;" href="https://issues.apache.org/jira/browse/ZEPPELIN"
-             target="_blank"><i style="font-size: 15px;" class="fa fa-bug"></i> Issues tracking</a><br/>
+             target="_blank" rel="noopener noreferrer"><i style="font-size: 15px;" class="fa fa-bug"></i> Issues tracking</a><br/>
           <a style="text-decoration: none;" href="https://github.com/apache/zeppelin"
-             target="_blank"><i style="font-size: 20px;" class="fa fa-github"></i> Github</a>
+             target="_blank" rel="noopener noreferrer"><i style="font-size: 20px;" class="fa fa-github"></i> Github</a>
         </div>
       </div>
     </div>
diff --git a/zeppelin-web/src/app/interpreter/interpreter-create.html b/zeppelin-web/src/app/interpreter/interpreter-create.html
index 7ec878f..68b92a1 100644
--- a/zeppelin-web/src/app/interpreter/interpreter-create.html
+++ b/zeppelin-web/src/app/interpreter/interpreter-create.html
@@ -128,7 +128,7 @@ limitations under the License.
               <a class="fa fa-info-circle interpreter-binding-mode-info-link"
                  aria-hidden="true"
                  uib-tooltip="Can manage interpreter sessions differently by setting this option. Click this button to learn more"
-                 ng-href="{{getInterpreterBindingModeDocsLink()}}" target="_blank"></a>
+                 ng-href="{{getInterpreterBindingModeDocsLink()}}" target="_blank" rel="noopener noreferrer"></a>
             <span ng-if="getInterpreterRunningOption(setting.id) === 'Per User' && ticket.principal !== 'anonymous'">
               <span ng-if="getPerNoteOption(setting.id) === 'shared'">
                 <button type="button" class="btn btn-default btn-xs"
diff --git a/zeppelin-web/src/app/interpreter/interpreter.html b/zeppelin-web/src/app/interpreter/interpreter.html
index d644142..3123fb1 100644
--- a/zeppelin-web/src/app/interpreter/interpreter.html
+++ b/zeppelin-web/src/app/interpreter/interpreter.html
@@ -236,7 +236,7 @@ limitations under the License.
             <a class="fa fa-info-circle interpreter-binding-mode-info-link"
                aria-hidden="true"
                uib-tooltip="Can manage interpreter sessions differently by setting this option. Click this button to learn more"
-               ng-href="{{getInterpreterBindingModeDocsLink()}}" target="_blank"></a>
+               ng-href="{{getInterpreterBindingModeDocsLink()}}" target="_blank" rel="noopener noreferrer"></a>
             <span ng-if="getInterpreterRunningOption(setting.id) === 'Per User' && ticket.principal !== 'anonymous'">
               <span ng-if="getPerNoteOption(setting.id) === 'shared'">
                 <button type="button" class="btn btn-default btn-xs"
@@ -299,7 +299,7 @@ limitations under the License.
               <a class="fa fa-info-circle interpreter-binding-mode-info-link"
                  aria-hidden="true"
                  uib-tooltip="Can manage interpreter sessions differently by setting this option. Click this button to learn more"
-                 ng-href="{{getInterpreterBindingModeDocsLink()}}" target="_blank"></a>
+                 ng-href="{{getInterpreterBindingModeDocsLink()}}" target="_blank" rel="noopener noreferrer"></a>
               <button type="button" class="btn btn-default btn-xs"
                       ng-disabled="!valueform.$visible"
                       ng-click="setPerNoteOption(setting.id, 'shared')"
diff --git a/zeppelin-web/src/app/notebook/notebook-actionBar.html b/zeppelin-web/src/app/notebook/notebook-actionBar.html
index 4b31119..c553d8c 100644
--- a/zeppelin-web/src/app/notebook/notebook-actionBar.html
+++ b/zeppelin-web/src/app/notebook/notebook-actionBar.html
@@ -291,7 +291,7 @@ limitations under the License.
           <li>
             <div class="cron-preset-container">
               Run note with cron scheduler.
-              Either choose from preset or write your own <a href="https://www.quartz-scheduler.org/documentation/quartz-2.3.0/tutorials/tutorial-lesson-06.html" target="_blank">cron expression</a>.
+              Either choose from preset or write your own <a href="https://www.quartz-scheduler.org/documentation/quartz-2.3.0/tutorials/tutorial-lesson-06.html" target="_blank" rel="noopener noreferrer">cron expression</a>.
               <div>
                 <span>- Preset</span>
                 <a class="cron-preset" ng-repeat="cr in cronOption"
diff --git a/zeppelin-web/src/app/notebook/notebook.controller.js b/zeppelin-web/src/app/notebook/notebook.controller.js
index 49398c9..20e6d26 100644
--- a/zeppelin-web/src/app/notebook/notebook.controller.js
+++ b/zeppelin-web/src/app/notebook/notebook.controller.js
@@ -150,7 +150,8 @@ function NotebookCtrl($scope, $route, $routeParams, $location, $rootScope,
     let zeppelinVersion = $rootScope.zeppelinVersion;
     let url = 'https://zeppelin.apache.org/docs/' + zeppelinVersion + '/security/notebook_authorization.html';
     let content = 'Only authenticated user can set the permission.' +
-      '<a data-toggle="tooltip" data-placement="top" title="Learn more" target="_blank" href=' + url + '>' +
+      '<a data-toggle="tooltip" data-placement="top" title="Learn more" target="_blank" ' +
+      'rel="noopener noreferrer" href=' + url + '>' +
       '<i class="icon-question" />' +
       '</a>';
     BootstrapDialog.show({
diff --git a/zeppelin-web/src/app/notebook/paragraph/paragraph-control.html b/zeppelin-web/src/app/notebook/paragraph/paragraph-control.html
index 588e898..9ac5b07 100644
--- a/zeppelin-web/src/app/notebook/paragraph/paragraph-control.html
+++ b/zeppelin-web/src/app/notebook/paragraph/paragraph-control.html
@@ -15,7 +15,7 @@ limitations under the License.
 <div id="{{paragraph.id}}_control" class="control" ng-show="!asIframe">
   <span>
     <span ng-show="paragraph.runtimeInfos.jobUrl.values.length == 1">
-      <a href="{{paragraph.runtimeInfos.jobUrl.values[0].jobUrl}}" target="_blank" style="text-decoration: none;"
+      <a href="{{paragraph.runtimeInfos.jobUrl.values[0].jobUrl}}" target="_blank" rel="noopener noreferrer" style="text-decoration: none;"
          tooltip-placement="top" uib-tooltip="{{paragraph.runtimeInfos.jobUrl.tooltip}}" >
         <span class="fa fa-tasks"></span>
         {{paragraph.runtimeInfos.jobUrl.label}}
@@ -29,8 +29,8 @@ limitations under the License.
       </span>
       <ul class="dropdown-menu" role="menu" style="width:200px;z-index:1002">
         <li ng-class="{'option-disabled': !noteOperationsAllowed()}" ng-repeat="value in paragraph.runtimeInfos.jobUrl.values">
-          <a ng-if="value.jobLabel === undefined" href="{{value['jobUrl']}}" target="_blank"><span class="fa fa-external-link-square"></span> Jobs #{{$index}}</a>
-          <a ng-if="value.jobLabel !== undefined" href="{{value['jobUrl']}}" target="_blank"><span class="fa fa-external-link-square"></span> {{value['jobLabel']}} </a>
+          <a ng-if="value.jobLabel === undefined" href="{{value['jobUrl']}}" target="_blank" rel="noopener noreferrer"><span class="fa fa-external-link-square"></span> Jobs #{{$index}}</a>
+          <a ng-if="value.jobLabel !== undefined" href="{{value['jobUrl']}}" target="_blank" rel="noopener noreferrer"><span class="fa fa-external-link-square"></span> {{value['jobLabel']}} </a>
         </li>
       </ul>
     </span>
diff --git a/zeppelin-web/src/components/navbar/navbar.html b/zeppelin-web/src/components/navbar/navbar.html
index 8182585..b13d7eb 100644
--- a/zeppelin-web/src/components/navbar/navbar.html
+++ b/zeppelin-web/src/components/navbar/navbar.html
@@ -142,9 +142,9 @@ limitations under the License.
             <span class="modal-body-about-version"> {{zeppelinVersion}} </span>
             <br/>
             <br/>
-            <a href="http://zeppelin.apache.org/" target="_blank"><span id="i18n-15">Get involved!</span></a>
+            <a href="http://zeppelin.apache.org/" target="_blank" rel="noopener noreferrer"><span id="i18n-15">Get involved!</span></a>
             <br/>
-            <a href="http://www.apache.org/licenses/LICENSE-2.0" target="_blank"><span id="i18n-16">Licensed under the Apache License, Version 2.0</span></a>
+            <a href="http://www.apache.org/licenses/LICENSE-2.0" target="_blank" rel="noopener noreferrer"><span id="i18n-16">Licensed under the Apache License, Version 2.0</span></a>
         </div>
 
       </div>