You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by gc...@apache.org on 2011/11/29 21:42:51 UTC

svn commit: r1208059 - in /myfaces/trinidad/trunk: src/site/xdoc/devguide/ trinidad-examples/trinidad-demo/src/main/webapp/WEB-INF/ trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/context/ trinidad-impl/src/main/java/org/apache/myfaces/...

Author: gcrawford
Date: Tue Nov 29 20:42:49 2011
New Revision: 1208059

URL: http://svn.apache.org/viewvc?rev=1208059&view=rev
Log:
TRINIDAD-2169 add framebusting support to handle clickjacking attacks

Added:
    myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/util/FrameBustingUtils.java
Modified:
    myfaces/trinidad/trunk/src/site/xdoc/devguide/configuration.xml
    myfaces/trinidad/trunk/trinidad-examples/trinidad-demo/src/main/webapp/WEB-INF/web.xml
    myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/context/TrinidadPhaseListener.java
    myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/renderkit/core/xhtml/BodyRenderer.java
    myfaces/trinidad/trunk/trinidad-impl/src/main/javascript/META-INF/adf/jsLibs/Page.js

Modified: myfaces/trinidad/trunk/src/site/xdoc/devguide/configuration.xml
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/src/site/xdoc/devguide/configuration.xml?rev=1208059&r1=1208058&r2=1208059&view=diff
==============================================================================
--- myfaces/trinidad/trunk/src/site/xdoc/devguide/configuration.xml (original)
+++ myfaces/trinidad/trunk/src/site/xdoc/devguide/configuration.xml Tue Nov 29 20:42:49 2011
@@ -351,6 +351,32 @@ Some Apache Trinidad configuration optio
 <code>&lt;context-param&gt;</code> elements in your
 <code>WEB-INF/web.xml</code>file.
 </p>
+
+<subsection name="org.apache.myfaces.trinidad.security.FRAME_BUSTING">
+
+<p>
+The parameter "org.apache.myfaces.trinidad.security.FRAME_BUSTING" controls the framebusting feature. 
+Framebusting stops content from running inside frames (meaning a frame or iframe tag).
+</p>
+<p>
+This context parameter is ignored when org.apache.myfaces.trinidad.util.ExternalContextUtils.isPortlet is true,
+and will behave as if the context parameter is set to 'never'.
+</p>
+<p>
+Possible values are:
+<ul>
+<li>differentOrigin - only bust frames if the an ancestor window origin and the
+                      frame origin are different. If the ancestor windows and frame have
+                      the same origin then allow the content to run in a frame. This is the default.
+</li>
+<li>always - always bust frames, meaning don't allow a page to be embedded in frames
+</li>
+<li>never - never bust frames, meaning always allow a page to be embedded in frames
+</li>
+</ul>
+</p>
+</subsection>
+
 <subsection name="org.apache.myfaces.trinidad.CACHE_VIEW_ROOT">
 <p>
 Enables or disables UIViewRoot caching;  defaults to true.

Modified: myfaces/trinidad/trunk/trinidad-examples/trinidad-demo/src/main/webapp/WEB-INF/web.xml
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad-examples/trinidad-demo/src/main/webapp/WEB-INF/web.xml?rev=1208059&r1=1208058&r2=1208059&view=diff
==============================================================================
--- myfaces/trinidad/trunk/trinidad-examples/trinidad-demo/src/main/webapp/WEB-INF/web.xml (original)
+++ myfaces/trinidad/trunk/trinidad-examples/trinidad-demo/src/main/webapp/WEB-INF/web.xml Tue Nov 29 20:42:49 2011
@@ -34,6 +34,32 @@
     <param-value>.jspx</param-value>
   </context-param>
 
+   
+
+  <context-param> 
+    <!--description>
+      The parameter "org.apache.myfaces.trinidad.security.FRAME_BUSTING" controls 
+      the framebusting feature. Framebusting stops content from running inside 
+      frames (meaning a frame or iframe tag).
+
+      This context parameter is ignored when 
+      org.apache.myfaces.trinidad.util.ExternalContextUtils.isPortlet is true, 
+      and will behave as if the context parameter is set to 'never'.
+
+      Possible values are:
+
+          differentOrigin - only bust frames if the an ancestor window origin 
+                   and the frame origin are different. If the ancestor windows 
+                   and frame have the same origin then allow the content to run 
+                   in a frame. This is the default.
+          always - always bust frames, meaning don't allow a page to be embedded in frames
+          never - never bust frames, meaning always allow a page to be embedded in frames
+
+    </description-->
+    <param-name>org.apache.myfaces.trinidad.security.FRAME_BUSTING</param-name>
+    <param-value>differentOrigin</param-value>
+  </context-param> 
+
   <!-- Set to true for using the lightweight dialog feature -->
   <context-param>
     <param-name>org.apache.myfaces.trinidad.ENABLE_LIGHTWEIGHT_DIALOGS</param-name>

Modified: myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/context/TrinidadPhaseListener.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/context/TrinidadPhaseListener.java?rev=1208059&r1=1208058&r2=1208059&view=diff
==============================================================================
--- myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/context/TrinidadPhaseListener.java (original)
+++ myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/context/TrinidadPhaseListener.java Tue Nov 29 20:42:49 2011
@@ -26,6 +26,7 @@ import javax.faces.event.PhaseListener;
 
 import org.apache.myfaces.trinidadinternal.config.xmlHttp.XmlHttpConfigurator;
 import org.apache.myfaces.trinidadinternal.renderkit.core.CoreRenderKit;
+import org.apache.myfaces.trinidadinternal.util.FrameBustingUtils;
 
 /**
  * Performs some trinidad logic and provides some hooks.
@@ -68,11 +69,14 @@ public class TrinidadPhaseListener imple
   @SuppressWarnings("unchecked")
   public void beforePhase(PhaseEvent event)
   {
+    
+    PhaseId phaseId = event.getPhaseId();
+    
     // Ensure that the implicit object gets created.  In general,
     // "restore view" would be sufficient, but someone can call
     // renderResponse() before even calling Lifecycle.execute(),
     // in which case RESTORE_VIEW doesn't actually run.
-    if (event.getPhaseId() == PhaseId.RESTORE_VIEW)
+    if (phaseId == PhaseId.RESTORE_VIEW)
     {
       FacesContext context = event.getFacesContext();
       ExternalContext ec = context.getExternalContext();
@@ -82,11 +86,35 @@ public class TrinidadPhaseListener imple
     // If we've reached "apply request values", this is definitely a
     // postback (the ViewHandler should have reached the same conclusion too,
     // but make sure)
-    else if (event.getPhaseId() == PhaseId.APPLY_REQUEST_VALUES)
+    else if (phaseId == PhaseId.APPLY_REQUEST_VALUES)
     {
       FacesContext context = event.getFacesContext();
       markPostback(context);
     }
+    else if (phaseId == PhaseId.RENDER_RESPONSE)
+    {    
+      // add response headers for framebusting if needed
+
+      FacesContext context = event.getFacesContext();
+      String frameBusting = FrameBustingUtils.getFrameBustingValue(context);        
+  
+      if (! FrameBustingUtils.FRAME_BUSTING_NEVER.equalsIgnoreCase(frameBusting))
+      {
+        // TODO: Mozilla has introduced CSP
+        //     https://wiki.mozilla.org/Security/CSP/Specification
+        // which we may want to support at some point
+        
+        // the X-Frame-Options header doesn't work on all browsers, but we're adding it anyway
+        if (FrameBustingUtils.FRAME_BUSTING_ALWAYS.equalsIgnoreCase(frameBusting))
+        {
+          context.getExternalContext().addResponseHeader("X-Frame-Options", "deny");
+        }
+        else
+        {
+          context.getExternalContext().addResponseHeader("X-Frame-Options", "sameorigin");
+        }
+      }
+    }    
   }
 
 

Modified: myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/renderkit/core/xhtml/BodyRenderer.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/renderkit/core/xhtml/BodyRenderer.java?rev=1208059&r1=1208058&r2=1208059&view=diff
==============================================================================
--- myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/renderkit/core/xhtml/BodyRenderer.java (original)
+++ myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/renderkit/core/xhtml/BodyRenderer.java Tue Nov 29 20:42:49 2011
@@ -35,6 +35,7 @@ import org.apache.myfaces.trinidad.conte
 import org.apache.myfaces.trinidad.render.ExtendedRenderKitService;
 import org.apache.myfaces.trinidad.skin.Skin;
 import org.apache.myfaces.trinidad.util.Service;
+import org.apache.myfaces.trinidadinternal.util.FrameBustingUtils;
 
 
 /**
@@ -141,8 +142,12 @@ public class BodyRenderer extends PanelP
 
     if (supportsScripting(rc))
     {
+      // this sets display:none on body and removes it with javascript. If no javascript is supported,
+      // no need to render the script. (it breaks emailable page mode because display:none is never cleared) 
+      _renderFrameBustingScript(context, rc); 
+      
       _renderNoScript(context, rc);
-      _storeInitialFocus(rc, component, bean);
+      _storeInitialFocus(rc, component, bean);  
     }
 
     if (!isPartialPass)
@@ -584,6 +589,47 @@ public class BodyRenderer extends PanelP
     return "(" + versionInfo + apiSpecTitle  + " - " + apiVersion  + "/"
                              + implSpecTitle + " - " + implVersion + ")";
   }
+  
+  private void _renderFrameBustingScript(
+    FacesContext     context,
+    RenderingContext rc
+  ) throws IOException
+  {    
+    // get the framebusting param set in web.xml
+    String frameBusting = FrameBustingUtils.getFrameBustingValue(context);
+    
+    if (! FrameBustingUtils.FRAME_BUSTING_NEVER.equalsIgnoreCase(frameBusting))
+    {
+      ResponseWriter out = context.getResponseWriter();
+
+      // Add a style to hide the body tag, if the framebusting code runs and decides it does not
+      // need to bust frames then it will remove the style dom node, which will make the content
+      // visible.
+      //
+      // We are using a style element instead of setting a style/class directly on the
+      // body tag because if we ever added a splash screen it would not show.
+      // We are setting an id on the style so that it can be removed on the client,
+      // which will make the content visible.
+      //
+      // We had previously tried to use javascript to add display:block to the
+      // style attribute of the body tag, but the style attribute of the body tag can get removed,
+      // for example when you do ppr nav or you ppr the document. Therefore we are now
+      // removing the style element on the client.
+      //
+      out.startElement("style", null);
+      // an id cannot start with an underscore
+      out.writeAttribute("id", "trinFrameBustStyle", null);
+      out.writeText("body {display:none}", null);
+      out.endElement("style");
+
+      out.startElement("script", null);
+      XhtmlRenderer.renderScriptTypeAttribute(context, rc);
+      out.writeText("TrPage.__frameBusting(\"", null);
+      out.writeText(frameBusting, null);
+      out.writeText("\");", null);
+      out.endElement("script");
+    }
+  }  
 
   private PropertyKey _firstClickPassedKey;
   private PropertyKey _initialFocusIdKey;

Added: myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/util/FrameBustingUtils.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/util/FrameBustingUtils.java?rev=1208059&view=auto
==============================================================================
--- myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/util/FrameBustingUtils.java (added)
+++ myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/util/FrameBustingUtils.java Tue Nov 29 20:42:49 2011
@@ -0,0 +1,88 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you 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.
+ */
+
+package org.apache.myfaces.trinidadinternal.util;
+
+
+import javax.faces.context.FacesContext;
+
+import org.apache.myfaces.trinidad.util.ExternalContextUtils;
+
+import org.apache.myfaces.trinidad.context.RequestContext;
+
+/**
+ * @author Gabrielle Crawford
+ */
+public class FrameBustingUtils
+{
+
+  // This parameter controls the framebusting feature. framebusting stops content from
+  //       running inside frames (meaning a frame or iframe tag).
+  //
+  //       This context parameter is ignored when
+  //       org.apache.myfaces.trinidad.util.ExternalContextUtils.isPortlet is true,
+  //       and will behave as if the context parameter is set to 'never'.
+  //
+  //       Possible values are:
+  //         differentOrigin - only bust frames if the an ancestor window origin and the
+  //                     frame origin are different. If the ancestor windows and frame have
+  //                     the same origin then allow the content to run in a frame.
+  //                     This is the default.
+  //         always - always bust frames, meaning don't allow a page to be embedded in frames
+  //         never - never bust frames, meaning always allow a page to be embedded in frames
+  static private final String _FRAME_BUSTING_PARAM = "org.apache.myfaces.trinidad.security.FRAME_BUSTING";
+  static public final String FRAME_BUSTING_NEVER = "never";
+  static public final String FRAME_BUSTING_ALWAYS = "always";
+  static public final String FRAME_BUSTING_DIFFERENT_ORIGIN = "differentOrigin";
+  
+  public static String getFrameBustingValue(FacesContext context)
+  {    
+
+    // Act as if the value is never if
+    // 1. we're doing ppr, we should only need to bust frames on a full page render
+    // 2. if the web.xml value is never
+    // 3. if we're in a portal    
+    //     Portals have a concept of producers and consumers.
+    //     The main page is the consumer, and the portlets inside that page are the producers.
+    //     Producer content can only be accessed by trusted consumers.
+    //
+    //     The consumer page can set the context param as needed,
+    //     but the producers will not do framebusting.
+    //     In other words when ExternalContextUtils.isPortlet is true we will behave as if
+    //     the context param is set to 'never'.
+    
+    String frameBusting = context.getExternalContext().getInitParameter(_FRAME_BUSTING_PARAM);
+    
+    if ( FRAME_BUSTING_NEVER.equalsIgnoreCase(frameBusting) || 
+         RequestContext.getCurrentInstance().isPartialRequest(context) ||
+         ExternalContextUtils.isPortlet(context.getExternalContext()))
+    {
+      return FRAME_BUSTING_NEVER;    
+    }
+    else if (FRAME_BUSTING_ALWAYS.equalsIgnoreCase(frameBusting))
+    {
+      return FRAME_BUSTING_ALWAYS;
+    }
+    else
+    {
+      // default is different origin
+      return FRAME_BUSTING_DIFFERENT_ORIGIN;
+    }
+  }  
+}

Modified: myfaces/trinidad/trunk/trinidad-impl/src/main/javascript/META-INF/adf/jsLibs/Page.js
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad-impl/src/main/javascript/META-INF/adf/jsLibs/Page.js?rev=1208059&r1=1208058&r2=1208059&view=diff
==============================================================================
--- myfaces/trinidad/trunk/trinidad-impl/src/main/javascript/META-INF/adf/jsLibs/Page.js (original)
+++ myfaces/trinidad/trunk/trinidad-impl/src/main/javascript/META-INF/adf/jsLibs/Page.js Tue Nov 29 20:42:49 2011
@@ -1019,4 +1019,66 @@ TrPage.prototype._getDomToBeUpdated = fu
   }
 
   return oldElements;
-}
\ No newline at end of file
+}
+
+
+// static method called on server
+TrPage.__frameBusting = function(frameBusting)
+{
+
+  if ( !(self == top || frameBusting == "never"))
+  {
+    if (frameBusting == "always")
+    {
+      top.location.href = location.href;
+    }
+    else
+    {
+      var topNotProcessed = true;
+      var parentWindow = parent;
+
+      while (topNotProcessed)
+      {
+        try
+        {
+          // if we have a different origin parentWindow.location.href will throw an exception
+          // in firefox and IE
+          var parentWindowLocation = parentWindow.location.href;
+
+          // in safari and google chrome no exception is thrown for referring to
+          // parentWindow.location.href, instead the parent window location is undefined
+          if (parentWindowLocation == null)
+          {
+            top.location.href = location.href;
+            return;
+          }
+        }
+        catch(e)
+        {
+          // the content has different origin, redirect 
+          top.location.href = location.href;
+          return;
+        }
+
+        if (parentWindow == top)
+          topNotProcessed = false;
+
+        parentWindow = parentWindow.parent;
+      }
+    }
+  }
+
+  // we didn't end up framebusting, so show the content
+  //
+  // We had previously tried to use javascript to add display:block to the
+  // style attribute of the body tag, but the style attribute of the body tag can get removed,
+  // for example when you do ppr nav or you ppr the document. Therefore we are now
+  // removing the style element on the client.
+  var styleNode = document.getElementById("trinFrameBustStyle");
+
+  if (styleNode)
+  {
+    styleNode.parentNode.removeChild(styleNode);
+  }
+}
+