Safeguard your QCubed based app from XSS - HTMLPurifier integrated to QCubed!!
XSS is a big problem and we know QCubed has been a bit weak over there. I have integrated HTMLPurifier (the best known OSS PHP Library for HTML Purification) into QCubed. This thread concerns the same and aims to help you understand how to use the features it brings.
The ticket for the same is here: http://trac.qcu.be/projects/qcubed/ticket/766
Coming to what has been done, I proposed earlier about adding HTMLPurifier to QCubed and was suggested by Alex to use QCrossScripting class to help integrate HTMLPurifier into the framework. Since XSS (or QCrossScripting) occurs via text input boxes, the major changes have been made to QTextBoxBase.class.php. However, they need the small addition made to the enumerations file (_enumerations.inc.php) in the same directory of base_controls. The changes made to the enumerations file are two lines being added:
const Purify = 'HTMLPurifierXSSProtectionConfig';
const PurifyCustom = 'HTMLPurifierEmptyConfig';
to the QCrossScripting abstract class.
If you pay a little attention (and know a little about how this works), it would be clear that two new modes of protection / filtering are applied to textboxes via the two constants defined there.
Purify: When using this value (constant / enumeration), you would get a textbox protected from most known XSS attacks. You can still add more options to your need (more on that later).
Here is how you would use it:
[When using the 'Purify' option]:
<?php
$this->txtSometextBox = new QTextBox($this);
// Configure looks
$this->txtSometextBox->TextMode = 'MultiLine';
$this->txtSometextBox->Width = 600;
$this->txtSometextBox->Rows = 24;
// Use the QCrossScripting enumeration to provide XSS protection.
$this->txtSometextBox->CrossScripting = QCrossScripting::Purify;
// Control other options for your textbox provided by HTMLPurifier
$this->txtSometextBox->SetPurifierConfig('Core.Encoding', 'UTF-8');
$this->txtSometextBox->SetPurifierConfig('AutoFormat.AutoParagraph', true);
$this->txtSometextBox->SetPurifierConfig('HTML.Allowed', 'p,b,strong,i,em,u,i,code,img[src]');
?>That's all about it. The next time you try to get the data from the control on the page via a POSTback, the 'Text' property of the TextBox will have the value you would have wanted, cleaned by HTMLPurifier. You need not change anything. Just usual method to get the data:
<?php
$filteredText = $this->txtSometextBox->Text;
?>That's it!
Now, time for a little bit of internals on how it was done:
I already said that two new values / enums were added to the QCrossScripting class. Here is how they work:
- The user first creates the control and chooses the QCrossScripting protection he desires. If he does not want the HTMLPurifier features in there, the Library (HTMLPurifier) is not loaded. This is to save the hefty bloat that HTMLPurifier can be without actually needing it on pages.
- I have done it like this:
<?php
if($this->strCrossScripting == QCrossScripting::Purify)
{
// If we are purifying using HTMLPurify, we will need the autoloader be included.
require_once(__INCLUDES__ .'/external_libraries/htmlpurifier/library/HTMLPurifier.auto.php');
// do something
}
?>Inside the __set function. This makes sure that the library is loaded only if needed. NO unnecessary bloats. In case the developers want it to be autoloaded (I wouldn't recommend because I tried it and load times really went about 120ms up for small pages even without a textbox), they might make the necessary changes.
- Since QWriteBox inherits from QTextBox which in turn Inherits from QTextBoxBase, I think it serves well throughout.
- In case you want to use it on other controls (I don't see a need), you can either move this functionality to some class deeper (more 'base') or implement separately on desired control.
- I did not change anything in the FCK editor because I do not use it anyway and I think there are many who don't
- Added this function to the QTextBoxBase class:
<?php
public function SetPurifierConfig($Parameter, $Value) {
if($this->HTMLPurifierConfig != null)
{
$this->HTMLPurifierConfig->set($Parameter, $Value);
}
}
?>to make sure that you could still configure HTMLPurifier featured options in the QCubed style. See examples above on how to use it. NOTE that you should not do that before setting the QCrossScripting Property of the textBox (it would have no effect).
- Note that I have used the path:
__INCLUDES__ . '/external_libraries/htmlpurifier/library/HTMLPurifier.auto.php'
for the HTMLPurifier's autoloader file. To the developers, I would request that it should be kept like this, in the 'external_libraries' directory because HTMLPurifier is indeed an 'External Library' and would help brave people play around with the code in HTML Purifier. Adding another line in configuration.inc.php to depict the path would not be bad either :)
- The HTMLPurifier version I used is 4.3.0.
I hope I was not too bad. Please test it and let let me know if something is not right by replying to this very thread.
[EDIT]: PurifyCustom as an option has been removed upon discussion in the ticket.
Regards,
Vaibhav

This is amazing work, Vaibhav - thanks so much for doing this. You're really helping move this community forward.
For everyone interested - we're all working together with Vaibhav to include this amazing component into the core distribution of QCubed 2.1. Details in this ticket: http://trac.qcu.be/projects/qcubed/ticket/766
Thanks a lot for the praise. It makes me happy :) Really, to give back to community from which I have gained something is invaluable.
Thanks again :)
Regards,
Vaibhav
Yes, thank you from my side as well.
Great thinking and great work!