blob: edb42891b9ec6ef2d4b714fb23e4a768620a374e [file] [log] [blame]
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<meta name="Date-Revision-yyyymmdd" content="20140918"/>
<meta http-equiv="Content-Language" content="en"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>Security</title>
<link href="//fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,600,700,400italic,600italic,700italic" rel="stylesheet" type="text/css">
<link href="//netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.css" rel="stylesheet">
<link href="/css/main.css" rel="stylesheet">
<link href="/css/custom.css" rel="stylesheet">
<link href="/css/syntax.css" rel="stylesheet">
<script src="//code.jquery.com/jquery-1.11.0.min.js"></script>
<script type="text/javascript" src="/bootstrap/js/bootstrap.js"></script>
<script type="text/javascript" src="/js/community.js"></script>
<!-- Matomo -->
<script>
var _paq = window._paq = window._paq || [];
/* tracker methods like "setCustomDimension" should be called before "trackPageView" */
/* We explicitly disable cookie tracking to avoid privacy issues */
_paq.push(['disableCookies']);
_paq.push(['trackPageView']);
_paq.push(['enableLinkTracking']);
(function() {
var u="//analytics.apache.org/";
_paq.push(['setTrackerUrl', u+'matomo.php']);
_paq.push(['setSiteId', '41']);
var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];
g.async=true; g.src=u+'matomo.js'; s.parentNode.insertBefore(g,s);
})();
</script>
<!-- End Matomo Code -->
</head>
<body>
<a href="https://github.com/apache/struts" class="github-ribbon">
<img decoding="async" loading="lazy" style="position: absolute; right: 0; border: 0;" width="149" height="149" src="https://github.blog/wp-content/uploads/2008/12/forkme_right_red_aa0000.png?resize=149%2C149" class="attachment-full size-full" alt="Fork me on GitHub" data-recalc-dims="1">
</a>
<header>
<nav>
<div role="navigation" class="navbar navbar-default navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<button type="button" data-toggle="collapse" data-target="#struts-menu" class="navbar-toggle">
Menu
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a href="/index.html" class="navbar-brand logo"><img src="/img/struts-logo.svg"></a>
</div>
<div id="struts-menu" class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li class="dropdown">
<a data-toggle="dropdown" href="#" class="dropdown-toggle">
Home<b class="caret"></b>
</a>
<ul class="dropdown-menu">
<li><a href="/index.html">Welcome</a></li>
<li><a href="/download.cgi">Download</a></li>
<li><a href="/releases.html">Releases</a></li>
<li><a href="/announce-2023.html">Announcements</a></li>
<li><a href="http://www.apache.org/licenses/">License</a></li>
<li><a href="https://www.apache.org/foundation/thanks.html">Thanks!</a></li>
<li><a href="https://www.apache.org/foundation/sponsorship.html">Sponsorship</a></li>
<li><a href="https://privacy.apache.org/policies/privacy-policy-public.html">Privacy Policy</a></li>
</ul>
</li>
<li class="dropdown">
<a data-toggle="dropdown" href="#" class="dropdown-toggle">
Support<b class="caret"></b>
</a>
<ul class="dropdown-menu">
<li><a href="/mail.html">User Mailing List</a></li>
<li><a href="https://issues.apache.org/jira/browse/WW">Issue Tracker</a></li>
<li><a href="/security.html">Reporting Security Issues</a></li>
<li><a href="/commercial-support.html">Commercial Support</a></li>
<li class="divider"></li>
<li><a href="https://cwiki.apache.org/confluence/display/WW/Migration+Guide">Version Notes</a></li>
<li><a href="https://cwiki.apache.org/confluence/display/WW/Security+Bulletins">Security Bulletins</a></li>
<li class="divider"></li>
<li><a href="/maven/project-info.html">Maven Project Info</a></li>
<li><a href="/maven/struts2-core/dependencies.html">Struts Core Dependencies</a></li>
<li><a href="/maven/struts2-plugins/modules.html">Plugin Dependencies</a></li>
</ul>
</li>
<li class="dropdown">
<a data-toggle="dropdown" href="#" class="dropdown-toggle">
Documentation<b class="caret"></b>
</a>
<ul class="dropdown-menu">
<li><a href="/birdseye.html">Birds Eye</a></li>
<li><a href="/primer.html">Key Technologies</a></li>
<li><a href="/kickstart.html">Kickstart FAQ</a></li>
<li><a href="https://cwiki.apache.org/confluence/display/WW/Home">Wiki</a></li>
<li class="divider"></li>
<li><a href="/getting-started/">Getting Started</a></li>
<li><a href="/security/">Security Guide</a></li>
<li><a href="/core-developers/">Core Developers Guide</a></li>
<li><a href="/tag-developers/">Tag Developers Guide</a></li>
<li><a href="/maven-archetypes/">Maven Archetypes</a></li>
<li><a href="/plugins/">Plugins</a></li>
<li><a href="/maven/struts2-core/apidocs/index.html">Struts Core API</a></li>
<li><a href="/tag-developers/tag-reference.html">Tag reference</a></li>
<li><a href="https://cwiki.apache.org/confluence/display/WW/FAQs">FAQs</a></li>
<li><a href="http://cwiki.apache.org/S2PLUGINS/home.html">Plugin registry</a></li>
</ul>
</li>
<li class="dropdown">
<a data-toggle="dropdown" href="#" class="dropdown-toggle">
Contributing<b class="caret"></b>
</a>
<ul class="dropdown-menu">
<li><a href="/youatstruts.html">You at Struts</a></li>
<li><a href="/helping.html">How to Help FAQ</a></li>
<li><a href="/dev-mail.html">Development Lists</a></li>
<li class="divider"></li>
<li><a href="/submitting-patches.html">Submitting patches</a></li>
<li><a href="/builds.html">Source Code and Builds</a></li>
<li><a href="/coding-standards.html">Coding standards</a></li>
<li><a href="/contributors/">Contributors Guide</a></li>
<li class="divider"></li>
<li><a href="/release-guidelines.html">Release Guidelines</a></li>
<li><a href="/bylaws.html">PMC Charter</a></li>
<li><a href="/volunteers.html">Volunteers</a></li>
<li><a href="https://gitbox.apache.org/repos/asf?p=struts.git">Source Repository</a></li>
<li><a href="/updating-website.html">Updating the website</a></li>
</ul>
</li>
<li class="apache"><a href="http://www.apache.org/"><img src="/img/apache.png"></a></li>
</ul>
</div>
</div>
</div>
</nav>
</header>
<article class="container">
<section class="col-md-12">
<a class="edit-on-gh" href="https://github.com/apache/struts-site/edit/master/source/security/index.md" title="Edit this page on GitHub">Edit on GitHub</a>
<h1 class="no_toc" id="security">Security</h1>
<ul id="markdown-toc">
<li><a href="#security-tips" id="markdown-toc-security-tips">Security tips</a> <ul>
<li><a href="#restrict-access-to-the-config-browser-plugin" id="markdown-toc-restrict-access-to-the-config-browser-plugin">Restrict access to the Config Browser Plugin</a></li>
<li><a href="#dont-mix-different-access-levels-in-the-same-namespace" id="markdown-toc-dont-mix-different-access-levels-in-the-same-namespace">Don’t mix different access levels in the same namespace</a></li>
<li><a href="#never-expose-jsp-files-directly" id="markdown-toc-never-expose-jsp-files-directly">Never expose JSP files directly</a></li>
<li><a href="#disable-devmode" id="markdown-toc-disable-devmode">Disable devMode</a></li>
<li><a href="#reduce-logging-level" id="markdown-toc-reduce-logging-level">Reduce logging level</a></li>
<li><a href="#use-utf-8-encoding" id="markdown-toc-use-utf-8-encoding">Use UTF-8 encoding</a></li>
<li><a href="#defining-and-annotating-your-action-parameters" id="markdown-toc-defining-and-annotating-your-action-parameters">Defining and annotating your Action parameters</a></li>
<li><a href="#do-not-define-setters-when-not-needed" id="markdown-toc-do-not-define-setters-when-not-needed">Do not define setters when not needed</a></li>
<li><a href="#do-not-use-incoming-values-as-an-input-for-localisation-logic" id="markdown-toc-do-not-use-incoming-values-as-an-input-for-localisation-logic">Do not use incoming values as an input for localisation logic</a></li>
<li><a href="#do-not-use-incoming-untrusted-user-input-in-forced-expression-evaluation" id="markdown-toc-do-not-use-incoming-untrusted-user-input-in-forced-expression-evaluation">Do not use incoming, untrusted user input in forced expression evaluation</a></li>
<li><a href="#use-struts-tags-instead-of-raw-el-expressions" id="markdown-toc-use-struts-tags-instead-of-raw-el-expressions">Use Struts tags instead of raw EL expressions</a></li>
<li><a href="#define-custom-error-pages" id="markdown-toc-define-custom-error-pages">Define custom error pages</a></li>
<li><a href="#ambiguous-action-methods" id="markdown-toc-ambiguous-action-methods">Ambiguous Action Methods</a></li>
<li><a href="#accepted--excluded-patterns" id="markdown-toc-accepted--excluded-patterns">Accepted / Excluded Patterns</a></li>
<li><a href="#strict-method-invocation" id="markdown-toc-strict-method-invocation">Strict Method Invocation</a></li>
<li><a href="#resource-isolation-using-fetch-metadata" id="markdown-toc-resource-isolation-using-fetch-metadata">Resource Isolation Using Fetch Metadata</a></li>
<li><a href="#cross-origin-isolation-with-coop-and-coep" id="markdown-toc-cross-origin-isolation-with-coop-and-coep">Cross Origin Isolation with COOP and COEP</a></li>
</ul>
</li>
<li><a href="#proactively-protecting-against-ognl-expression-injections-attacks" id="markdown-toc-proactively-protecting-against-ognl-expression-injections-attacks">Proactively protecting against OGNL Expression Injections attacks</a> <ul>
<li><a href="#run-ognl-expressions-inside-sandbox" id="markdown-toc-run-ognl-expressions-inside-sandbox">Run OGNL expressions inside sandbox</a></li>
<li><a href="#restricting-access-to-the-struts-context-actioncontext" id="markdown-toc-restricting-access-to-the-struts-context-actioncontext">Restricting access to the Struts Context (ActionContext)</a></li>
<li><a href="#apply-a-maximum-allowed-length-on-ognl-expressions" id="markdown-toc-apply-a-maximum-allowed-length-on-ognl-expressions">Apply a maximum allowed length on OGNL expressions</a></li>
<li><a href="#ognl-member-access" id="markdown-toc-ognl-member-access">OGNL Member Access</a></li>
<li><a href="#struts-ognl-guard" id="markdown-toc-struts-ognl-guard">Struts OGNL Guard</a></li>
</ul>
</li>
</ul>
<h2 id="security-tips">Security tips</h2>
<p>The Apache Struts 2 doesn’t provide any security mechanism - it is just a pure web framework. Below are few tips
you should consider during application development with the Apache Struts 2.</p>
<h3 id="restrict-access-to-the-config-browser-plugin">Restrict access to the Config Browser Plugin</h3>
<p><a href="../plugins/config-browser/">Config Browser Plugin</a> exposes internal configuration and should be used only during
development phase. If you must use it on production site, we strictly recommend restricting access to it - you can use<br />
Basic Authentication or any other security mechanism (e.g. <a href="https://shiro.apache.org/">Apache Shiro</a>)</p>
<h3 id="dont-mix-different-access-levels-in-the-same-namespace">Don’t mix different access levels in the same namespace</h3>
<p>Very often access to different resources is controlled based on URL patterns, see snippet below. Because of that
you cannot mix actions with different security levels in the same namespace. Always group actions in one namespace
by security level.</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;security-constraint&gt;</span>
<span class="nt">&lt;web-resource-collection&gt;</span>
<span class="nt">&lt;web-resource-name&gt;</span>admin<span class="nt">&lt;/web-resource-name&gt;</span>
<span class="nt">&lt;url-pattern&gt;</span>/secure/*<span class="nt">&lt;/url-pattern&gt;</span>
<span class="nt">&lt;/web-resource-collection&gt;</span>
<span class="nt">&lt;auth-constraint&gt;</span>
<span class="nt">&lt;role-name&gt;</span>admin<span class="nt">&lt;/role-name&gt;</span>
<span class="nt">&lt;/auth-constraint&gt;</span>
<span class="nt">&lt;/security-constraint&gt;</span>
</code></pre></div></div>
<h3 id="never-expose-jsp-files-directly">Never expose JSP files directly</h3>
<p>You must always hide JSP file behind an action, you cannot allow for direct access to the JSP files as this can leads
to unpredictable security vulnerabilities. You can achieve this by putting all your JSP files under the <code class="language-plaintext highlighter-rouge">WEB-INF</code> folder</p>
<ul>
<li>most of the JEE containers restrict access to files placed under the <code class="language-plaintext highlighter-rouge">WEB-INF</code> folder. Second option is to add security
constraint to the <code class="language-plaintext highlighter-rouge">web.xml</code> file:</li>
</ul>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">&lt;!-- Restricts access to pure JSP files - access available only via Struts action --&gt;</span>
<span class="nt">&lt;security-constraint&gt;</span>
<span class="nt">&lt;display-name&gt;</span>No direct JSP access<span class="nt">&lt;/display-name&gt;</span>
<span class="nt">&lt;web-resource-collection&gt;</span>
<span class="nt">&lt;web-resource-name&gt;</span>No-JSP<span class="nt">&lt;/web-resource-name&gt;</span>
<span class="nt">&lt;url-pattern&gt;</span>*.jsp<span class="nt">&lt;/url-pattern&gt;</span>
<span class="nt">&lt;/web-resource-collection&gt;</span>
<span class="nt">&lt;auth-constraint&gt;</span>
<span class="nt">&lt;role-name&gt;</span>no-users<span class="nt">&lt;/role-name&gt;</span>
<span class="nt">&lt;/auth-constraint&gt;</span>
<span class="nt">&lt;/security-constraint&gt;</span>
<span class="nt">&lt;security-role&gt;</span>
<span class="nt">&lt;description&gt;</span>Don't assign users to this role<span class="nt">&lt;/description&gt;</span>
<span class="nt">&lt;role-name&gt;</span>no-users<span class="nt">&lt;/role-name&gt;</span>
<span class="nt">&lt;/security-role&gt;</span>
</code></pre></div></div>
<p>The best approach is to used the both solutions.</p>
<h3 id="disable-devmode">Disable devMode</h3>
<p>The <code class="language-plaintext highlighter-rouge">devMode</code> is a very useful option during development time, allowing for deep introspection and debugging into you app.</p>
<p>However, in production it exposes your application to be presenting too many informations on application’s internals
or to evaluating risky parameter expressions. Please <strong>always disable</strong> <code class="language-plaintext highlighter-rouge">devMode</code> before deploying your application
to a production environment. While it is disabled by default, your
<code class="language-plaintext highlighter-rouge">struts.xml</code> might include a line setting it to <code class="language-plaintext highlighter-rouge">true</code>. The best way is to ensure the following setting is applied
to our <code class="language-plaintext highlighter-rouge">struts.xml</code> for production deployment:</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;constant</span> <span class="na">name =</span><span class="s">"struts.devMode"</span> <span class="na">value=</span><span class="s">"false"</span> <span class="nt">/&gt;</span>
</code></pre></div></div>
<h3 id="reduce-logging-level">Reduce logging level</h3>
<p>It’s a good practice to reduce logging level from <strong>DEBUG</strong> to <strong>INFO</strong> or less. Framework’s classes can produce
a lot of logging entries which will pollute the log file. You can even set logging level to <strong>WARN</strong> for classes that
belongs to the framework, see example Log4j2 configuration:</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">&lt;?xml version="1.0" encoding="UTF-8"?&gt;</span>
<span class="nt">&lt;Configuration&gt;</span>
<span class="nt">&lt;Appenders&gt;</span>
<span class="nt">&lt;Console</span> <span class="na">name=</span><span class="s">"STDOUT"</span> <span class="na">target=</span><span class="s">"SYSTEM_OUT"</span><span class="nt">&gt;</span>
<span class="nt">&lt;PatternLayout</span> <span class="na">pattern=</span><span class="s">"%d %-5p [%t] %C{2} (%F:%L) - %m%n"</span><span class="nt">/&gt;</span>
<span class="nt">&lt;/Console&gt;</span>
<span class="nt">&lt;/Appenders&gt;</span>
<span class="nt">&lt;Loggers&gt;</span>
<span class="nt">&lt;Logger</span> <span class="na">name=</span><span class="s">"com.opensymphony.xwork2"</span> <span class="na">level=</span><span class="s">"warn"</span><span class="nt">/&gt;</span>
<span class="nt">&lt;Logger</span> <span class="na">name=</span><span class="s">"org.apache.struts2"</span> <span class="na">level=</span><span class="s">"warn"</span><span class="nt">/&gt;</span>
<span class="nt">&lt;Root</span> <span class="na">level=</span><span class="s">"info"</span><span class="nt">&gt;</span>
<span class="nt">&lt;AppenderRef</span> <span class="na">ref=</span><span class="s">"STDOUT"</span><span class="nt">/&gt;</span>
<span class="nt">&lt;/Root&gt;</span>
<span class="nt">&lt;/Loggers&gt;</span>
<span class="nt">&lt;/Configuration&gt;</span>
</code></pre></div></div>
<h3 id="use-utf-8-encoding">Use UTF-8 encoding</h3>
<p>Always use <code class="language-plaintext highlighter-rouge">UTF-8</code> encoding when building an application with the Apache Struts 2, when using JSPs please add the following
header to each JSP file</p>
<div class="language-jsp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;%@ page </span><span class="na">contentType=</span><span class="s">"text/html; charset=UTF-8"</span> <span class="nt">%&gt;</span>
</code></pre></div></div>
<h3 id="defining-and-annotating-your-action-parameters">Defining and annotating your Action parameters</h3>
<blockquote>
<p>Note: Since 6.4 using <code class="language-plaintext highlighter-rouge">struts.parameters.requireAnnotations=true</code>. Or by default from 7.0.</p>
</blockquote>
<p>Request parameters, such as those submitted by a form, can be stored on your Struts Action class by defining getters and
setters for them. For example, if you have a form with a field called <code class="language-plaintext highlighter-rouge">name</code>, you can store the value of that field by
defining a <code class="language-plaintext highlighter-rouge">public void setName(String name)</code> method on your Action class, and then importantly, annotating this method
with <code class="language-plaintext highlighter-rouge">@StrutsParameter</code>. The presence of this annotation indicates that the method is intended for parameter injection
and is safe to be invoked by any user who can view the Action.</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">private</span> <span class="nc">String</span> <span class="n">name</span><span class="o">;</span>
<span class="nd">@StrutsParameter</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">setName</span><span class="o">(</span><span class="nc">String</span> <span class="n">name</span><span class="o">)</span> <span class="o">{</span>
<span class="k">this</span><span class="o">.</span><span class="na">name</span> <span class="o">=</span> <span class="n">name</span><span class="o">;</span>
<span class="o">}</span>
</code></pre></div></div>
<p>If you wish to populate a DTO (Data Transfer Object) instead of setting the parameters directly on the Action class, you
can define a getter for the DTO on your Action class instead. For example, define a method <code class="language-plaintext highlighter-rouge">public MyDto getFormData()</code>
which is also annotated by <code class="language-plaintext highlighter-rouge">@StrutsParameter(depth = 1)</code>. Then, a parameter with name <code class="language-plaintext highlighter-rouge">formData.fullName</code> will be mapped
to the setter <code class="language-plaintext highlighter-rouge">setFullName</code> on that DTO. Note that the <code class="language-plaintext highlighter-rouge">@StrutsParameter</code> annotation has a <code class="language-plaintext highlighter-rouge">depth</code> field which dictates
the depth to which parameter injection is permitted. The default value is 0, which only allows setting parameters
directly on the Action class as in the first example. A <code class="language-plaintext highlighter-rouge">depth</code> of 1 indicates that the immediate public properties of
an object returned by the getter are permitted to be set. If you have further nested objects, you can increase
the <code class="language-plaintext highlighter-rouge">depth</code> accordingly. Do not set this <code class="language-plaintext highlighter-rouge">depth</code> field to a value greater than the minimum required for your use case.</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">private</span> <span class="nc">MyDto</span> <span class="n">formData</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">MyDto</span><span class="o">();</span>
<span class="nd">@StrutsParameter</span><span class="o">(</span><span class="n">depth</span> <span class="o">=</span> <span class="mi">1</span><span class="o">)</span>
<span class="kd">public</span> <span class="nc">MyDto</span> <span class="nf">getFormData</span><span class="o">()</span> <span class="o">{</span>
<span class="k">return</span> <span class="n">formData</span><span class="o">;</span>
<span class="o">}</span>
<span class="kd">public</span> <span class="kd">static</span> <span class="kd">class</span> <span class="nc">MyDto</span> <span class="o">{</span>
<span class="kd">private</span> <span class="nc">String</span> <span class="n">fullName</span><span class="o">;</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">setFullName</span><span class="o">(</span><span class="nc">String</span> <span class="n">fullName</span><span class="o">)</span> <span class="o">{</span>
<span class="k">this</span><span class="o">.</span><span class="na">fullName</span> <span class="o">=</span> <span class="n">fullName</span><span class="o">;</span>
<span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>
<p>It is critical that any method you annotate with <code class="language-plaintext highlighter-rouge">@StrutsParameter</code> is safe for any user who can view that corresponding
action to invoke (including any public methods on objects returned by that method and so forth). Any getters you
annotate should only ever return a DTO or a collection/hierarchy of DTOs. Do NOT mix business logic or service
references with your parameter injection methods and DTOs. Additionally, any database DTOs should be entirely separate
from request parameter/form DTOs.</p>
<p>Do NOT, under any circumstance, annotate a method that returns one of the following unsafe objects:</p>
<ul>
<li>live Hibernate persistent objects</li>
<li>container or Spring-managed beans, or any other live components/services</li>
<li>objects (or objects that contain references to objects) that contain setter methods that are used for anything other
than setting form parameter values</li>
</ul>
<p>If you are finding updating your application with this new annotation time-consuming, you can temporarily combine the
above option with <code class="language-plaintext highlighter-rouge">struts.parameters.requireAnnotations.transitionMode=true</code>. When this mode is enabled, only ‘nested’
parameters, i.e. DTOs or Collections represented by public getters on Action classes, will require annotations. This
means public setters will still be exposed for parameter injection. Notably,
the <a href="#allowlist-capability">auto-allowlisting capability</a>, which is also supported by these annotations, is not degraded
in any way, so it proves a useful transitioning option for applications that wish to enable the OGNL allowlist as soon
as possible.</p>
<h3 id="do-not-define-setters-when-not-needed">Do not define setters when not needed</h3>
<blockquote>
<p>Note: Only relevant if you are not using <code class="language-plaintext highlighter-rouge">struts.parameters.requireAnnotations=true</code> as per the previous section.</p>
</blockquote>
<p>You should carefully design your actions without exposing anything via setters and getters, this can lead to potential
security vulnerabilities. Any action’s setter can be used to set incoming untrusted user’s value which can contain
suspicious expression. Some Struts <code class="language-plaintext highlighter-rouge">Result</code>s automatically populate params based on values in
<code class="language-plaintext highlighter-rouge">ValueStack</code> (action in most cases is the root) which means incoming value will be evaluated as an expression during
this process.</p>
<h3 id="do-not-use-incoming-values-as-an-input-for-localisation-logic">Do not use incoming values as an input for localisation logic</h3>
<p>All <code class="language-plaintext highlighter-rouge">TextProvider</code>’s <code class="language-plaintext highlighter-rouge">getText(...)</code> methods (e.g. in<code class="language-plaintext highlighter-rouge">ActionSupport</code>) perform evaluation of parameters included in a message
to properly localize the text. This means using incoming request parameters with <code class="language-plaintext highlighter-rouge">getText(...)</code> methods is potentially
dangerous and should be avoided. See example below, assuming that an action implements getter and setter for property
<code class="language-plaintext highlighter-rouge">message</code>, the below code allows inject an OGNL expression:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="nc">String</span> <span class="nf">execute</span><span class="o">()</span> <span class="kd">throws</span> <span class="nc">Exception</span> <span class="o">{</span>
<span class="n">message</span> <span class="o">=</span> <span class="n">getText</span><span class="o">(</span><span class="n">getMessage</span><span class="o">());</span>
<span class="k">return</span> <span class="no">SUCCESS</span><span class="o">;</span>
<span class="o">}</span>
</code></pre></div></div>
<p><strong>Never use value of incoming request parameter as part of your localization logic.</strong></p>
<h3 id="do-not-use-incoming-untrusted-user-input-in-forced-expression-evaluation">Do not use incoming, untrusted user input in forced expression evaluation</h3>
<p>You can use a forced expression evalaution in many tags’ attributes by using <code class="language-plaintext highlighter-rouge">%{...}</code> syntax. This is a very powerful option
but used with wrong data can lead to the Remote Code Execution. Never use forced expression evalaution if you didn’t verify
the input or it can be passed in by a user.</p>
<p><strong>Never use value of incoming request parameter as input for forced expression evalaution.</strong></p>
<h3 id="use-struts-tags-instead-of-raw-el-expressions">Use Struts tags instead of raw EL expressions</h3>
<p>JSP EL doesn’t perform any kind of escaping, you must perform this using a dedicated function, see <a href="https://stackoverflow.com/a/6135001/1805267">this example</a>.
Never use a raw <code class="language-plaintext highlighter-rouge">${}</code> EL expression on incoming values as this can lead to injecting a malicious code into the page.</p>
<p>The safest option is to use Struts Tags instead.</p>
<h3 id="define-custom-error-pages">Define custom error pages</h3>
<p>As mentioned in <a href="https://cwiki.apache.org/confluence/display/WW/S2-006">S2-006</a> it’s a good practicse to define your own
error pages. This avoids exposing users to XSS attacks as Struts does not escape action’s names in automatically
generated error pages.</p>
<p>You can either disable <a href="../core-developers/action-configuration#dynamic-method-invocation">DMI</a></p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;constant</span> <span class="na">name=</span><span class="s">"struts.enable.DynamicMethodInvocation"</span> <span class="na">value=</span><span class="s">"false"</span> <span class="nt">/&gt;</span>
</code></pre></div></div>
<p>or define an error page</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;global-results&gt;</span>
<span class="nt">&lt;result</span> <span class="na">name=</span><span class="s">"error"</span><span class="nt">&gt;</span>/error_page.jsp<span class="nt">&lt;/result&gt;</span>
<span class="nt">&lt;/global-results&gt;</span>
<span class="nt">&lt;global-exception-mappings&gt;</span>
<span class="nt">&lt;exception-mapping</span> <span class="na">exception=</span><span class="s">"java.lang.Exception"</span> <span class="na">result=</span><span class="s">"error"</span><span class="nt">/&gt;</span>
<span class="nt">&lt;/global-exception-mappings&gt;</span>
</code></pre></div></div>
<h3 id="ambiguous-action-methods">Ambiguous Action Methods</h3>
<p>This can impact actions which have large inheritance hierarchy and use the same method’s name throughout the hierarchy,
this was reported as an issue <a href="https://issues.apache.org/jira/browse/WW-4405">WW-4405</a>. See the example below:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">class</span> <span class="nc">RealAction</span> <span class="kd">extends</span> <span class="nc">BaseAction</span> <span class="o">{</span>
<span class="nd">@Action</span><span class="o">(</span><span class="s">"save"</span><span class="o">)</span>
<span class="kd">public</span> <span class="nc">String</span> <span class="nf">save</span><span class="o">()</span> <span class="kd">throws</span> <span class="nc">Exception</span> <span class="o">{</span>
<span class="kd">super</span><span class="o">.</span><span class="na">save</span><span class="o">();</span>
<span class="k">return</span> <span class="no">SUCCESS</span><span class="o">;</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">BaseAction</span> <span class="kd">extends</span> <span class="nc">AbstractAction</span> <span class="o">{</span>
<span class="kd">public</span> <span class="nc">String</span> <span class="nf">save</span><span class="o">()</span> <span class="kd">throws</span> <span class="nc">Exception</span> <span class="o">{</span>
<span class="n">save</span><span class="o">(</span><span class="nc">Double</span><span class="o">.</span><span class="na">MAX_VALUE</span><span class="o">);</span>
<span class="k">return</span> <span class="no">SUCCESS</span><span class="o">;</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="kd">public</span> <span class="kd">abstract</span> <span class="kd">class</span> <span class="nc">AbstractAction</span> <span class="kd">extends</span> <span class="nc">ActionSupport</span> <span class="o">{</span>
<span class="kd">protected</span> <span class="kt">void</span> <span class="nf">save</span><span class="o">(</span><span class="nc">Double</span> <span class="n">val</span><span class="o">)</span> <span class="o">{</span>
<span class="c1">// some logic</span>
<span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>
<p>In such case OGNL cannot properly map which method to call when request is coming. This is do the OGNL limitation.
To solve the problem don’t use the same method’s names through the hierarchy, you can simply change the action’s method
from <code class="language-plaintext highlighter-rouge">save()</code> to <code class="language-plaintext highlighter-rouge">saveAction()</code> and leaving annotation as is to allow call this action via <code class="language-plaintext highlighter-rouge">/save.action</code> request.</p>
<h3 id="accepted--excluded-patterns">Accepted / Excluded Patterns</h3>
<p>As from version 2.3.20 the framework provides two new interfaces which are used to accept / exclude param names
and values - <a href="../maven/struts2-core/apidocs/com/opensymphony/xwork2/security/AcceptedPatternsChecker">AcceptedPatternsChecker</a>
and <a href="../maven/struts2-core/apidocs/com/opensymphony/xwork2/security/ExcludedPatternsChecker">ExcludedPatternsChecker</a>
with default implementations. These two interfaces are used by the <a href="../core-developers/parameters-interceptor">Parameters Interceptor</a>
and <a href="../core-developers/cookie-interceptor">Cookie Interceptor</a> to check if param can be accepted or must be excluded.
If you were using <code class="language-plaintext highlighter-rouge">excludeParams</code> previously please compare patterns used by you with these provided by the framework in default implementation.</p>
<h3 id="strict-method-invocation">Strict Method Invocation</h3>
<p>This mechanism was introduced in version 2.5. It allows control what methods can be accessed with the bang “!” operator
via <a href="../core-developers/action-configuration.html#dynamic-method-invocation">Dynamic Method Invocation</a>. Please read
more in the Strict Method Invocation section of <a href="../core-developers/action-configuration">Action Configuration</a>.</p>
<h3 id="resource-isolation-using-fetch-metadata">Resource Isolation Using Fetch Metadata</h3>
<blockquote>
<p>Note: since Struts 6.0.0</p>
</blockquote>
<p>Fetch Metadata is a mitigation against common cross-origin attacks such as Cross-Site Request Forgery (CSRF). It is
a web platform security feature designed to help servers defend themselves against cross-origin attacks based
on the preferred resource isolation policy. The browser provides information about the context of an HTTP request
in a set of <code class="language-plaintext highlighter-rouge">Sec-Fetch-*</code> headers. This allows the server processing the request to make decisions on whether the request
should be accepted or rejected based on the available resource isolation policies.</p>
<p>A Resource Isolation Policy prevents the resources on a server from being requested by external websites. This policy
can be enabled for all endpoints of the application or the endpoints that are meant to be loaded in a cross-site context
can be exempted from applying the policy. Read more about Fetch Metadata and resource isolation <a href="https://web.dev/fetch-metadata/">here</a>.</p>
<p>This mechanism is implemented in Struts using the <a href="../core-developers/fetch-metadata-interceptor">FetchMetadata Interceptor</a>.
Refer to the documentation for <a href="../core-developers/fetch-metadata-interceptor">FetchMetadata Interceptor</a>
instructions on how to enable Fetch Metadata.</p>
<h3 id="cross-origin-isolation-with-coop-and-coep">Cross Origin Isolation with COOP and COEP</h3>
<blockquote>
<p>Note: since Struts 6.0.0</p>
</blockquote>
<p><a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Opener-Policy">Cross-Origin Opener Policy</a> is
a security mitigation that lets developers isolate their resources against side-channel attacks and information leaks.
The COOP response header allows a document to request a new browsing context group to better isolate itself from other
untrustworthy origins.</p>
<p><a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Embedder-Policy">Cross-Origin Embedder Policy</a>
prevents a document from loading any cross-origin resources which don’t explicitly grant the document permission to be loaded.</p>
<p>COOP and COEP are independent mechanisms that can be enabled, tested and deployed separately. While enabling one doesn’t
require developers to enable the other, when set together COOP and COEP allows developers to use powerful features (such
as <code class="language-plaintext highlighter-rouge">SharedArrayBuffer</code>, <code class="language-plaintext highlighter-rouge">performance.measureMemory()</code> and the JS Self-Profiling API) securely, without worrying about
side channel attacks like <a href="https://meltdownattack.com/">Spectre</a>.
Further reading on <a href="https://docs.google.com/document/d/1zDlfvfTJ_9e8Jdc8ehuV4zMEu9ySMCiTGMS9y0GU92k/edit#bookmark=id.uo6kivyh0ge2">COOP/COEP</a>
and <a href="https://web.dev/why-coop-coep/">why you need cross-origin isolation</a>.</p>
<p>The recommended configuration for the policies are:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Cross-Origin-Embedder-Policy: require-corp;
Cross-Origin-Opener-Policy: same-origin;
</code></pre></div></div>
<p>COOP and COEP are implemented in Struts using <a href="../core-developers/coop-interceptor">CoopInterceptor</a>
and <a href="../core-developers/coep-interceptor">CoepInterceptor</a>.</p>
<h2 id="proactively-protecting-against-ognl-expression-injections-attacks">Proactively protecting against OGNL Expression Injections attacks</h2>
<p>The framework has a history of critical security bugs, many tied to its use of OGNL technology; Due to its ability to
create or change executable code, OGNL is capable of introducing critical security flaws to any framework that uses it.
Multiple Struts 2 versions have been vulnerable to OGNL security flaws. Consequently, we’ve equipped OGNL and the
framework with a number of additional security capabilities, some of which need to be manually enabled.</p>
<blockquote>
<p><strong>NOTE</strong>: These might break your current app functionality. Before using in production environment, you’re recommended
to comprehensively test your app UI and functionalities with these enabled.</p>
</blockquote>
<h3 id="run-ognl-expressions-inside-sandbox">Run OGNL expressions inside sandbox</h3>
<p>You can do this simply via adding <code class="language-plaintext highlighter-rouge">-Dognl.security.manager</code> to JVM arguments. OGNL thereupon utilizes Java Security
Manager to run OGNL expressions (which includes your actions either!) inside a sandbox with no permission. It is worth
noting that it affects only OGNL expression execution and thereafter OGNL reverts Java Security Manager to its previous
state.</p>
<p>Note: This feature does not work with JDK 21 and above.</p>
<h3 id="restricting-access-to-the-struts-context-actioncontext">Restricting access to the Struts Context (ActionContext)</h3>
<p>The Struts ActionContext is a core construct of the Struts framework. It is shared and manipulated throughout the
codebase. From the ActionContext, it is possible to access application parameters, the OgnlValueStack, the current
request/response/session, the servlet context, the Guice container, and a number of other objects either directly or
indirectly via the directly exposed objects. The Struts ActionContext enables powerful features and functionality, but
it also presents a major security risk if not properly secured.</p>
<p>The Struts ActionContext is accessible to OGNL expressions. In the case of an OGNL expression exploit, usually achieved
through some form of server-side template injection or parameter injection, the ActionContext is a prime gadget for
escalation of the vulnerability, often to remote code execution (RCE). Whilst known harmful capabilities of the
ActionContext items are blocked by the OGNL Member Access policy exclusion list (see below), this is not always
effective due to the myriad of changing objects available on the ActionContext. The new allowlist capability (also see
below) offers much stronger protection. However, for the strongest level of protection, we recommend disabling access
to the ActionContext from OGNL expressions entirely.</p>
<p>Note that before disabling access to the ActionContext from OGNL expressions, you should ensure that your application
does not rely on this capability. OGNL expressions may access the context directly using the <code class="language-plaintext highlighter-rouge">#</code> operator, or indirectly
using the OgnlValueStack’s fallback to context lookup capability. As of Struts 6.4.0, the Set, Iterator and Action
Struts components require ActionContext access from OGNL expressions.</p>
<p>To disable access to the ActionContext from OGNL expressions, set the following constants in your <code class="language-plaintext highlighter-rouge">struts.xml</code> or
<code class="language-plaintext highlighter-rouge">struts.properties</code> file. The option <code class="language-plaintext highlighter-rouge">struts.ognl.excludedNodeTypes</code> is an <a href="#Struts-OGNL-Guard">OGNL Guard</a> setting
which completely forbids the context accessing syntax node. The <code class="language-plaintext highlighter-rouge">struts.ognl.valueStackFallbackToContext</code> option
disables ValueStack behaviour which allows the context to be accessed indirectly via a fallback behaviour triggered when
an OGNL expression does not evaluate to a valid value.</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;constant</span> <span class="na">name=</span><span class="s">"struts.ognl.valueStackFallbackToContext"</span> <span class="na">value=</span><span class="s">"false"</span><span class="nt">/&gt;</span>
<span class="nt">&lt;constant</span> <span class="na">name=</span><span class="s">"struts.ognl.excludedNodeTypes"</span> <span class="na">value=</span><span class="s">"
ognl.ASTThisVarRef,
ognl.ASTVarRef
"</span><span class="nt">/&gt;</span>
</code></pre></div></div>
<h3 id="apply-a-maximum-allowed-length-on-ognl-expressions">Apply a maximum allowed length on OGNL expressions</h3>
<p>You can enable this via Struts configuration key <code class="language-plaintext highlighter-rouge">struts.ognl.expressionMaxLength</code> (defaults to 256). OGNL thereupon doesn’t evaluate any
expression longer than specified value. You would choose a value large enough to permit ALL valid OGNL expressions used
within the application. Values larger than the 200-400 range have diminishing security value (at which point it is
really only a “style guard” for long OGNL expressions in an application).</p>
<h3 id="ognl-member-access">OGNL Member Access</h3>
<p>Struts 2 implements an OGNL internal security mechanism which blocks access to particular classes and Java packages -
it’s an OGNL-wide mechanism which means it affects any aspect of the framework i.e. incoming parameters, expressions
used in JSPs, etc. Matching is done based on both the target and member class of all components of an OGNL expression.</p>
<p>There are 4 options that can be used to configure excluded packages and classes:</p>
<ul>
<li><code class="language-plaintext highlighter-rouge">struts.excludedClasses</code>: comma-separated list of excluded classes.</li>
<li><code class="language-plaintext highlighter-rouge">struts.excludedPackageNames</code>: comma-separated list of excluded packages, matched using string comparison via
<code class="language-plaintext highlighter-rouge">startWith</code>. Note that classes in subpackages are also excluded.</li>
<li><code class="language-plaintext highlighter-rouge">struts.excludedPackageNamePatterns</code> - comma-separated list of RegEx patterns used to exclude packages. Note that this
option is more flexible than <code class="language-plaintext highlighter-rouge">struts.excludedPackageNames</code> but will have a greater impact on performance and page
latency.</li>
<li><code class="language-plaintext highlighter-rouge">struts.excludedPackageExemptClasses</code> - comma-separated list of classes to exempt from any of the excluded packages or
package name patterns. An exact exemption must exist for each exclusion match (target or member or both).</li>
</ul>
<p>The defaults are defined <a href="https://github.com/apache/struts/blob/master/core/src/main/resources/struts-excluded-classes.xml">here</a>.</p>
<p>Any expression or target which does not pass this criteria will be blocked, and you will see a warning in the logs:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[WARNING] Target class [class example.MyBean] or declaring class of member type [public example.MyBean()] are excluded!
</code></pre></div></div>
<p>In that case <code class="language-plaintext highlighter-rouge">new MyBean()</code> was used to create a new instance of class (inside JSP) - it’s blocked because the <code class="language-plaintext highlighter-rouge">target</code>
of such expression is <code class="language-plaintext highlighter-rouge">java.lang.Class</code> which is excluded.</p>
<p>It is possible to redefine the above constants in <code class="language-plaintext highlighter-rouge">struts.xml</code>, but avoid reducing the list, instead extending the list
with other known dangerous classes or packages in your application.</p>
<h4 id="additional-options">Additional Options</h4>
<p>We additionally recommend enabling the following options (enabled by default in 7.0).</p>
<ul>
<li><code class="language-plaintext highlighter-rouge">struts.ognl.allowStaticFieldAccess=false</code> - static methods are always blocked, but static fields can also optionally be blocked</li>
<li><code class="language-plaintext highlighter-rouge">struts.disallowProxyMemberAccess=true</code> - disallow proxied objects from being used in OGNL expressions as they may present a security risk</li>
<li><code class="language-plaintext highlighter-rouge">struts.disallowDefaultPackageAccess=true</code> - disallow access to classes in the default package which should not be used in production</li>
<li><code class="language-plaintext highlighter-rouge">struts.ognl.disallowCustomOgnlMap=true</code> - disallow construction of custom OGNL maps which can be used to bypass the SecurityMemberAccess policy</li>
</ul>
<h4 id="allowlist-capability">Allowlist Capability</h4>
<blockquote>
<p>Note: Since Struts 6.4. Or by default from 7.0.</p>
</blockquote>
<p>For the most stringent OGNL protection, we recommend enabling the allowlist capability with <code class="language-plaintext highlighter-rouge">struts.allowlist.enable</code>.</p>
<p>Now, in addition to enforcing the exclusion list, classes involved in OGNL expression must also belong to a list of
allowlisted classes and packages. By default, all required Struts classes are allowlisted as well as any classes that
are defined in your <code class="language-plaintext highlighter-rouge">struts.xml</code> package configurations.</p>
<p>We highly recommend enabling the <a href="#defining-and-annotating-your-action-parameters">parameter annotation</a> capability to
ensure any necessary parameter injection types are allowlisted, in addition to its other benefits.</p>
<p>You can add additional classes and packages to the allowlist with:</p>
<ul>
<li><code class="language-plaintext highlighter-rouge">struts.allowlist.classes</code>: comma-separated list of allowlisted classes.</li>
<li><code class="language-plaintext highlighter-rouge">struts.allowlist.packages</code>: comma-separated list of allowlisted packages, matched using string comparison via
<code class="language-plaintext highlighter-rouge">startsWith</code>. Note that classes in subpackages are also allowlisted.</li>
</ul>
<p>Depending on the functionality of your application, you may not need to manually allowlist any classes. Please monitor
your application logs for any warnings about blocked classes and add them to the allowlist as necessary.</p>
<h4 id="extensibility">Extensibility</h4>
<blockquote>
<p>Note: since Struts 6.4.</p>
</blockquote>
<p>The OGNL Member Access mechanism is extensible, allowing you to define your own rules for blocking access to OGNL
expression evaluations. To do so, you may use the <code class="language-plaintext highlighter-rouge">struts.securityMemberAccess</code> extension point. Please be vigilant when
overriding methods as not to reduce protections offered by the default implementation.</p>
<h3 id="struts-ognl-guard">Struts OGNL Guard</h3>
<blockquote>
<p>Note: since Struts 6.4.</p>
</blockquote>
<p>The Struts OGNL Guard allows applications to completely disable certain OGNL expression features/capabilities. This
feature is disabled by default but can be enabled and configured with <code class="language-plaintext highlighter-rouge">struts.ognl.excludedNodeTypes</code>.</p>
<p>It is recommended to disable any OGNL feature you are not leveraging in your application.</p>
<p>For example, if you do not need to use the addition operation in any OGNL expressions, you can add <code class="language-plaintext highlighter-rouge">ognl.ASTAdd</code> to your
excluded node types. This will mitigate against a host of String concatenation attacks.</p>
<p>For applications using a minimal number of Struts features, you may find the following list a good starting point.
Please be aware that this list WILL break certain Struts features.</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;constant</span> <span class="na">name=</span><span class="s">"struts.ognl.excludedNodeTypes"</span>
<span class="na">value=</span><span class="s">"
ognl.ASTAdd,
ognl.ASTAssign,
ognl.ASTBitAnd,
ognl.ASTBitNegate,
ognl.ASTBitOr,
ognl.ASTCtor,
ognl.ASTDivide,
ognl.ASTEval,
ognl.ASTIn,
ognl.ASTInstanceof,
ognl.ASTKeyValue,
ognl.ASTList,
ognl.ASTMap,
ognl.ASTMultiply,
ognl.ASTNegate,
ognl.ASTNotIn,
ognl.ASTProject,
ognl.ASTRootVarRef,
ognl.ASTSelect,
ognl.ASTSelectFirst,
ognl.ASTSelectLast,
ognl.ASTSequence,
ognl.ASTShiftLeft,
ognl.ASTShiftRight,
ognl.ASTStaticField,
ognl.ASTStaticMethod,
ognl.ASTThisVarRef,
ognl.ASTUnsignedShiftRight,
ognl.ASTVarRef,
ognl.ASTXor
"</span><span class="nt">/&gt;</span>
</code></pre></div></div>
<h4 id="extensibility-1">Extensibility</h4>
<p>The Struts OGNL Guard mechanism is extensible, allowing you to define your own rules for blocking access to both raw
OGNL expressions and compiled syntax trees. To do so, you may use the <code class="language-plaintext highlighter-rouge">struts.ognlGuard</code> extension point. You may choose
to override the default implementation or implement the <code class="language-plaintext highlighter-rouge">OgnlGuard</code> interface directly.</p>
</section>
</article>
<footer class="container">
<div class="col-md-12">
Copyright &copy; 2000-2022 <a href="https://www.apache.org/">The Apache Software Foundation</a>.
Apache Struts, Struts, Apache, the Apache feather logo, and the Apache Struts project logos are
trademarks of The Apache Software Foundation. All Rights Reserved.
</div>
<div class="col-md-12">Logo and website design donated by <a href="https://softwaremill.com/">SoftwareMill</a>.</div>
</footer>
<script>!function (d, s, id) {
var js, fjs = d.getElementsByTagName(s)[0];
if (!d.getElementById(id)) {
js = d.createElement(s);
js.id = id;
js.src = "//platform.twitter.com/widgets.js";
fjs.parentNode.insertBefore(js, fjs);
}
}(document, "script", "twitter-wjs");</script>
<script src="https://apis.google.com/js/platform.js" async="async" defer="defer"></script>
<div id="fb-root"></div>
<script>(function (d, s, id) {
var js, fjs = d.getElementsByTagName(s)[0];
if (d.getElementById(id)) return;
js = d.createElement(s);
js.id = id;
js.src = "//connect.facebook.net/en_GB/all.js#xfbml=1";
fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));</script>
</body>
</html>