Large scale data breaches and critical security vulnerabilities have companies thinking about security more than ever. Many developers are familiar with the OWASP top 10 (https://owasp.org/www-project-top-ten/) and there are already many resources on generic mitigation for these vulnerabilities. Instead in this series, I cover security issues and mitigations specific to AEM.
XSS and AntiSamy
As a quick review, Cross Site Scripting (XSS) can occur if user-entered inputs are not filtered before displaying back to the user. Remember that user-entered content can include sources that usually users do not edit like URL parameters, local storage, and cookies. Many applications will also need to filter user content from HTML and JS emails before sending.
When using HTL tags in AEM, the default rendering context and all other contexts other than ‘unsafe’ will utilize a set of OWASP rules called AntiSamy. Sometimes this ruleset may filter more than expected, and some developers resort to using the context=’unsafe’ attribute which renders the raw text from the Sling Model property.
A common use case that the default AntiSamy library interferes with is telephone (tel:) hrefs in links. For instance:
<a href=”${model.url @ context='html'”> ${model.urlText @ context=’html’} </a>
Will not allow model.url = tel://555-555-555 to be output correctly to the page. A developer might just resort to:
<a href=”${model.url @ context='unsafe'”> ${model.urlText @ context='html'} </a>
or worse:
${model.rteText @ context='unsafe'}
Solution Design
Thankfully, we have a few options other than using context=’unsafe’.
- Design your components to utilize feature flags for hardcoded attributes or special characters separately output from the user or author input.
- You can overlay the default ruleset located at /libs/cq/xssprotection/config.xml. Be careful not to allow any more attributes or special characters than you need, or ones commonly used by exploits to run JavaScript.
- Utilize a custom backend service or static utility that rewrites entered characters to desired substitute other than empty.
My preference is #1 so I’ll provide an example. With these considerations, your implementation may look more like the following:
<a data-sly-test=”${!model.isPhoneLink}” href=”${model.url @ context='html'”> ${model.urlText @ context=’html’} </a> <a data-sly-test=”${model.isPhoneLink && model.isValidPhone}” href=”tel:// ${model.url @ context=’html’}${ model.phoneExt ? ',' : ''}${properties.phoneExt @ context='html'} x-cq-linkchecker="skip"> ${model.url @ context='html'}${model.extentionText || ‘’ @ context='html'}${properties.phoneExt @ context='html'} </a> <a data-sly-test=”${model.isPhoneLink && !model.isValidPhone}”> ${model.invalidPhoneMsg} </a>
Do you have any context = ‘unsafe’ usages in your codebase? It’s worth checking to see if it’s exploitable. But it’s only the start of the XSS vulnerability review process.
To see the implementation in action, watch this in video format.
For more information on how Perficient can help you achieve your AEM Security goals and implement your dream digital experiences, we’d love to hear from you.
Contact Perficient to start your journey.