Script Tag Stripping Workaround in Joomla PDF Print E-mail
Tuesday, 27 July 2010 23:03

If you ever tried inserting javascript into a Joomla article you may find it is a very difficult task; so, I went a head and made a plug-in to make this fast and easy. The reason why joomla makes it so difficult is because cross site scripting (XSS) vulnerabilities are very devious and can compromise the entire application. In this very short article I will explain how I created the plug-in and when and how you should use it.



Process

My inspiration for writing this new plug-in was my need to embed javascript in one of my articles on this website, the article demonstrates a little bug in Firefox. I quickly discovered that joomla strips <script> tags pretty much no matter what you do in the settings. After hours of searching the web and others with having similar problems, I found one plug-in enabled me to insert javascript in my article. But it was too clumsy and tried to do too much for my purposes. So even-though I have never written a plug-in for joomla before, I decided it was a simple task that I can do myself.

I began my quest by reading a few excellent tutorials (listed below) to get an idea of how it all works. Next I looked at a few other plug-ins that did somewhat of a similar job. All I needed was to find a way to replace {*script*} tags with <script>. CodeCitation is a syntax highlighter  that replaces {*code*} tags with some other HTML tags to do some of its work. This was just perfect, all I needed to do now was to strip it down to the bare bones and let it do what I want.

I copied some of the code used by CodeCitation and did a lot of modifications. It now looks nothing like the original. As a bonus I also managed to discover a bug in it (Open Source in all its glory :)). I called this new plug-in Scripty and gave it some very basic options. The idea was to keep it simple and fast here is what I came up with:

scripty.php



// no direct access
defined( '_JEXEC' ) or die( 'Restricted access' );


jimport( 'joomla.plugin.plugin' );


/**
 * Scripty plug-in provides a workaround for the problem of script tags being filtered. It was
 * designed for advanced users, if you do not know what you are doing security can be compromised!
 */
class plgContentScripty extends JPlugin
{
	const _tag = "scripty";
	
	/**
	 * Constructor
	 *
	 * For php4 compatibility we must not use the __constructor as a constructor for plugins
	 * because func_get_args ( void ) returns a copy of all passed arguments NOT references.
	 * This causes problems with cross-referencing necessary for the observer design pattern.
	 *
	 * @access	protected
	 * @param	object	$subject The object to observe
	 * @param 	array   $config  An array that holds the plugin configuration
	 * @since	1.0
	 */
	function plgContentScripty(&$subject, $config)
	{
		parent::__construct( $subject, $config );


		// Do some extra initialisation in this constructor if required
	}
	
	/**
	 * onPrepareContent event handler. It replaces all entries of {scripty}tag with the
	 * script HTML tag.
	 * @param $row
	 * @param $params
	 * @param $page
	 * @return boolean Returns true if successful
	 */
	function onPrepareContent(&$row, &$params, $page = 0) 
	{
	  	$tag = self::_tag;
	  	$alternativetag = $this->params->def('alternativetag', '');
	  	
	  	if ($alternativetag != '')
	  	{
	  		$tag = '(' . $tag . '|' . $alternativetag . ')'; 		
	  	}
	  	else
	  	{
	  		$tag = '(' . $tag . ')';
	  	}
	    
	  	$regex = "#{" . $tag . "(?:\s|&nbsp;)*(.*?)}([\s\S]*?){/\\1}#s";
	    // register the regular expression to invoke our replacer in case Joomla finds the matches
	    $row->text = preg_replace_callback($regex, array($this,'replacer'), $row->text);
	    
	    return true;
	}


  /**
   * Provides a replacement text for the given match. This provides a call back function for the
   * regular expression matcher. It wrap the text in &lt;script&gt;&lt;/script&gt; as needed
   * @param array $matches The match that was found
   * @return string The replacement string 
   */
  private function replacer(&$matches) 
  {
    $args = $matches[2];
    $text = $matches[3];
    $src = '';
    
    if($this->params->def('include', '') === '1' && $args !== '')
    {
    	$key_value = explode("=", $args);
    	
    	if(trim($key_value[0]) === 'src')
    	{
    		$src = trim($key_value[1]);
    	}
    }
    
    if($src === '')
    {
    	$prolog = '<script type="text/javascript">';
    }
    else
    {
    	$prolog = '<script type="text/javascript" src="' . $src . '">';
    }
    
    $epilog = '</script>';


    $text = $prolog . $text . $epilog;


    return $text;
  }
}


 

scripty.xml



<?xml version="1.0" encoding="utf-8"?>
<install version="1.5.2" type="plugin" group="content" method="upgrade">
	<name>Content - Scripty</name>
	<author>Michael Yagudaev</author>
	<creationDate>July 2010</creationDate>
	<copyright>Copyright (C) 2010 yagudaev.com. All rights reserved.</copyright>
	<license>GNU General Public License</license>
	<authorEmail>michaelyagudaev [at] gmail.com</authorEmail>
	<authorUrl>http://www.yagudaev.com/</authorUrl>
	<version>0.1</version>
	<description>Scripty is a small plug-in that provides a workaround to the problem 
		of filtered script tags (&lt;script&gt;). To use it simply place the scripty opening
		and closing tags where you would normally place the script tags in your html.
	</description>
	<files>
		<filename plugin="scripty">scripty.php</filename>
	</files>
	<params>
  		<param name="include" type="radio" default="0" label="Allow includes" description="Allows the user to include a script">
  			<option value="0">No</option>
			<option value="1">Yes</option>
		</param>
		<param name="alternativetag" type="text" default="" label="Alternative tag to trigger the plugin usage." description="If you would like to use something other than {scripty}. For example: script" />
	</params>
</install>


Download it here.

How to Use it

To use the plug-in simply install it like any other joomla plug-in and place the {*scripty*} and {*/scripty*} around it.

(Remove the * it was only added in order to prevent Joomla from parsing it as a plug-in entry, since I do have this plug-in running now)

Here are a few usage examples:

 
{*scripty*} 
	alert("hello javascript on joomla!"); 
{*/script*} 
 
{*scripty src="/js/my_awesome_script.js"*} 
	no javascript 
{*/scripty*} 


When to Use it

You should only use this plug-in after you have exhausted all other options of adding the same content -- Joomla usually has much better ways of adding custom behaviour if this is what you are looking for.

If you truly want to associate an article with a script, such as when you are demonstrating something you may use this. But, beware as JavaScript is based on a global namespace which means your script may not work the right way if some other code on the page is using the same identifier names. There are 2 ways to deal with this, one is to use closure in javascript as Douglas Crockford recommends in his book JavaScript: The Good Parts to mitigate some of the problems caused by having global variables. The second is to simply use a new html page on your machine, upload it using FTP and attach and link to it from your article, this page will not be managed by Joomla and will guarantee your code works without problems.


References


  1. http://developer.joomla.org/tutorials/184-how-to-create-a-joomla-plugin.html
  2. http://docs.joomla.org/How_to_create_a_content_plugin




Add this page to your favorite Social Bookmarking websites
 
Last Updated on Monday, 18 April 2011 14:13
 
More articles :

» Deleting Multiple Database Tables – The Easy Way

In this short article I will describe how I went about deleting multiple database tables quickly without using the DROP DATABASE dbName statement. Feel free to skip right to the solution if you like.Background StoryAs part of changing one of our...

» Getting Reliable z-index Cross-Browser

Turns out it is not as easy as one might think to get thecorrect z-index of an element using a javascript call like $(element).css(‘z-index’). The problem is how browser vendors apply the z-indexto an element. But, no worries I have created a...

» Multiple Popup Windows Workaround

Pop-up window management poses a challenge in itself, but with an elusive Firefox bug effecting this process, it may seem impossible to do it well. I will present you with an account of my struggle with this issue and the simple solution I found for...

» Snow in JavaScript

Winter is finally over, but we can still make nice digital snow to cool us down during hot summer days. We will start by considering the path snow flakes take before they hit the ground, then we will find out how to implement it...

» Resolving PHP Relative Paths Problems

In this tutorial I will talk about the problem of using relative paths with the four following function: include(), include_once(), require() and require_once().

Comments  

 
0 #4 2011-09-12 01:14
Nice tutorial. Very helpfull.
Quote
 
 
0 #3 2011-09-08 05:15
looks like it could be useful - thank you.
Quote
 
 
0 #2 Administrator 2011-04-18 14:21
Hi Kemal,

Thanks for your comment. I have added a few examples to the article. Ironically enough there is no way to specify I want to use the {scripty} expression literally and not as a plug-in in Joomla.

Cheers,
Michael Yagudaev
Quote
 
 
+1 #1 2011-04-18 06:59
Please add a couple of real world examples to this nice article. I was forced to reverse engineer the regular expression to use it. My own example:
{scripty src=http://example.com/js/script.js} javascript not active {/scripty}
Quote
 

Add comment


Security code
Refresh