2
0
forked from Wavyzz/dolibarr

SEC: Add option MAIN_RESTRICTHTML_ONLY_VALID_HTML_TIDY

This commit is contained in:
Laurent Destailleur
2023-11-29 20:19:21 +01:00
parent 3a78357253
commit 43f9210ab4
4 changed files with 217 additions and 19 deletions

View File

@@ -176,6 +176,7 @@ class SecurityTest extends PHPUnit\Framework\TestCase
$this->assertEquals($tmplangs->defaultlang, 'malicioustextwithquote_MALICIOUSTEXTWITHQUOTE');
}
/**
* testSqlAndScriptInjectWithPHPUnit
*
@@ -379,9 +380,11 @@ class SecurityTest extends PHPUnit\Framework\TestCase
// Force default mode
$conf->global->MAIN_RESTRICTHTML_ONLY_VALID_HTML = 0;
$conf->global->MAIN_RESTRICTHTML_ONLY_VALID_HTML_TIDY = 0;
$conf->global->MAIN_RESTRICTHTML_REMOVE_ALSO_BAD_ATTRIBUTES = 0;
$_COOKIE["id"]=111;
$_POST["param0"]='A real string with <a href="rrr" title="aa&quot;bb">aaa</a> and " and \' and &amp; inside content';
$_GET["param1"]="222";
$_POST["param1"]="333";
$_GET["param2"]='a/b#e(pr)qq-rr\cc';
@@ -413,20 +416,27 @@ class SecurityTest extends PHPUnit\Framework\TestCase
$_POST["param19"]='<a href="j&Tab;a&Tab;v&Tab;asc&NewLine;ri&Tab;pt:&lpar;alert(document.cookie)&rpar;">XSS</a>';
//$_POST["param19"]='<a href="javascript:alert(document.cookie)">XSS</a>';
$result=GETPOST('id', 'int'); // Must return nothing
print __METHOD__." result=".$result."\n";
$this->assertEquals($result, '');
$this->assertEquals('', $result);
$result=GETPOST("param1", 'int');
print __METHOD__." result=".$result."\n";
$this->assertEquals($result, 222, 'Test on param1 with no 3rd param');
$this->assertEquals(222, $result, 'Test on param1 with no 3rd param');
$result=GETPOST("param1", 'int', 2);
print __METHOD__." result=".$result."\n";
$this->assertEquals($result, 333, 'Test on param1 with 3rd param = 2');
$this->assertEquals(333, $result, 'Test on param1 with 3rd param = 2');
// Test with alpha
$result=GETPOST("param0", 'alpha'); // a simple format, so " completely removed
$resultexpected = 'A real string with aaa and and \' and & inside content';
print __METHOD__." result=".$result."\n";
$this->assertEquals($resultexpected, $result, 'Test on param0');
$result=GETPOST("param2", 'alpha');
print __METHOD__." result=".$result."\n";
$this->assertEquals($result, $_GET["param2"], 'Test on param2');
@@ -472,7 +482,7 @@ class SecurityTest extends PHPUnit\Framework\TestCase
// Test with nohtml
$result=GETPOST("param6", 'nohtml');
print __METHOD__." result=".$result."\n";
print __METHOD__." result6=".$result."\n";
$this->assertEquals('">', $result);
// Test with alpha = alphanohtml. We must convert the html entities like &#110; and disable all entities
@@ -525,16 +535,23 @@ class SecurityTest extends PHPUnit\Framework\TestCase
print __METHOD__." result=".$result."\n";
$this->assertEquals('n n > < XSS', $result, 'Test that html entities are decoded with alpha');
// Test with alphawithlgt
$result=GETPOST("param11", 'alphawithlgt');
print __METHOD__." result=".$result."\n";
$this->assertEquals(trim($_POST["param11"]), $result, 'Test an email string with alphawithlgt');
// Test with restricthtml: we must remove html open/close tag and content but not htmlentities (we can decode html entities for ascii chars like &#110;)
$result=GETPOST("param0", 'restricthtml');
$resultexpected = 'A real string with <a href="rrr" title="aa&quot;bb">aaa</a> and " and \' and &amp; inside content';
print __METHOD__." result=".$result."\n";
$this->assertEquals($resultexpected, $result, 'Test on param0');
$result=GETPOST("param6", 'restricthtml');
print __METHOD__." result param6=".$result."\n";
print __METHOD__." result for param6=".$result." - before=".$_POST["param6"]."\n";
$this->assertEquals('&quot;&gt;', $result);
$result=GETPOST("param7", 'restricthtml');
@@ -570,19 +587,83 @@ class SecurityTest extends PHPUnit\Framework\TestCase
$this->assertEquals('<a href="&lpar;alert(document.cookie)&rpar;">XSS</a>', $result, 'Test 19');
// Test with restricthtml + MAIN_RESTRICTHTML_ONLY_VALID_HTML to test disabling of bad atrributes
$conf->global->MAIN_RESTRICTHTML_ONLY_VALID_HTML = 1;
// Test with restricthtml + MAIN_RESTRICTHTML_ONLY_VALID_HTML only to test disabling of bad atrributes
$conf->global->MAIN_RESTRICTHTML_ONLY_VALID_HTML = 1;
$conf->global->MAIN_RESTRICTHTML_ONLY_VALID_HTML_TIDY = 0;
//$_POST["param0"] = 'A real string with <a href="rrr" title="aabb">aaa</a> and " inside content';
$result=GETPOST("param0", 'restricthtml');
$resultexpected = 'A real string with <a href="rrr" title=\'aa"bb\'>aaa</a> and " and \' and &amp; inside content';
print __METHOD__." result for param0=".$result."\n";
$this->assertEquals($resultexpected, $result, 'Test on param0');
$result=GETPOST("param15", 'restricthtml'); // param15 = <img onerror<=alert(document.domain)> src=>0xbeefed that is a dangerous string
print __METHOD__." result=".$result."\n";
// $this->assertEquals('InvalidHTMLStringCantBeCleaned', $result, 'Test 15b'); // With some PHP and libxml version, we got this result when parsing invalid HTML, but ...
print __METHOD__." result for param15=".$result."\n";
//$this->assertEquals('InvalidHTMLStringCantBeCleaned', $result, 'Test 15b'); // With some PHP and libxml version, we got this result when parsing invalid HTML, but ...
//$this->assertEquals('<img onerror> src=&gt;0xbeefed', $result, 'Test 15b'); // ... on other PHP and libxml versions, we got a HTML that has been cleaned
$result=GETPOST("param6", 'restricthtml'); // param6 = "&gt;
print __METHOD__." result for param6=".$result." - before=".$_POST["param6"]."\n";
$this->assertEquals('"&gt;', $result);
$result=GETPOST("param7", 'restricthtml'); // param7 = "c:\this is a path~1\aaa&#110; &#x&#x31;&#x31;&#x30;;" abc<bad>def</bad>
print __METHOD__." result param7 = ".$result."\n";
$this->assertEquals('"c:\this is a path~1\aaan 110;" abcdef', $result);
// Test with restricthtml + MAIN_RESTRICTHTML_ONLY_VALID_HTML_TIDY only to test disabling of bad atrributes
if (extension_loaded('tidy') && class_exists("tidy")) {
$conf->global->MAIN_RESTRICTHTML_ONLY_VALID_HTML = 0;
$conf->global->MAIN_RESTRICTHTML_ONLY_VALID_HTML_TIDY = 1;
$result=GETPOST("param0", 'restricthtml');
$resultexpected = 'A real string with <a href="rrr" title="aa&quot;bb">aaa</a> and " and \' and & inside content';
print __METHOD__." result for param0=".$result."\n";
$this->assertEquals($resultexpected, $result, 'Test on param0');
$result=GETPOST("param15", 'restricthtml'); // param15 = <img onerror<=alert(document.domain)> src=>0xbeefed that is a dangerous string
print __METHOD__." result=".$result."\n";
$result=GETPOST("param6", 'restricthtml');
print __METHOD__." result for param6=".$result." - before=".$_POST["param6"]."\n";
$this->assertEquals('"&gt;', $result);
$result=GETPOST("param7", 'restricthtml');
print __METHOD__." result param7 = ".$result."\n";
$this->assertEquals('"c:\this is a path~1\aaan &amp;#x110;" abcdef', $result);
}
// Test with restricthtml + MAIN_RESTRICTHTML_ONLY_VALID_HTML + MAIN_RESTRICTHTML_ONLY_VALID_HTML_TIDY to test disabling of bad atrributes
if (extension_loaded('tidy') && class_exists("tidy")) {
$conf->global->MAIN_RESTRICTHTML_ONLY_VALID_HTML = 1;
$conf->global->MAIN_RESTRICTHTML_ONLY_VALID_HTML_TIDY = 1;
$result=GETPOST("param0", 'restricthtml');
$resultexpected = 'A real string with <a href="rrr" title=\'aa"bb\'>aaa</a> and " and \' and & inside content';
print __METHOD__." result for param0=".$result."\n";
$this->assertEquals($resultexpected, $result, 'Test on param0');
$result=GETPOST("param15", 'restricthtml'); // param15 = <img onerror<=alert(document.domain)> src=>0xbeefed that is a dangerous string
print __METHOD__." result=".$result."\n";
$result=GETPOST("param6", 'restricthtml');
print __METHOD__." result for param6=".$result." - before=".$_POST["param6"]."\n";
$this->assertEquals('"&gt;', $result);
$result=GETPOST("param7", 'restricthtml');
print __METHOD__." result param7 = ".$result."\n";
$this->assertEquals('"c:\this is a path~1\aaan 110;" abcdef', $result);
}
unset($conf->global->MAIN_RESTRICTHTML_ONLY_VALID_HTML);
// Test with restricthtml + MAIN_RESTRICTHTML_REMOVE_ALSO_BAD_ATTRIBUTES to test disabling of bad atrributes
unset($conf->global->MAIN_RESTRICTHTML_ONLY_VALID_HTML);
unset($conf->global->MAIN_RESTRICTHTML_ONLY_VALID_HTML_TIDY);
$conf->global->MAIN_RESTRICTHTML_REMOVE_ALSO_BAD_ATTRIBUTES = 1;
$result=GETPOST("param15", 'restricthtml');
@@ -664,7 +745,7 @@ class SecurityTest extends PHPUnit\Framework\TestCase
/**
* testEncodeDecode
*
* @return number
* @return int
*/
public function testEncodeDecode()
{
@@ -686,7 +767,7 @@ class SecurityTest extends PHPUnit\Framework\TestCase
/**
* testDolStringOnlyTheseHtmlTags
*
* @return number
* @return int
*/
public function testDolHTMLEntityDecode()
{
@@ -704,7 +785,7 @@ class SecurityTest extends PHPUnit\Framework\TestCase
/**
* testDolStringOnlyTheseHtmlTags
*
* @return number
* @return int
*/
public function testDolStringOnlyTheseHtmlTags()
{
@@ -734,7 +815,7 @@ class SecurityTest extends PHPUnit\Framework\TestCase
/**
* testDolStringOnlyTheseHtmlAttributes
*
* @return number
* @return int
*/
public function testDolStringOnlyTheseHtmlAttributes()
{
@@ -753,7 +834,7 @@ class SecurityTest extends PHPUnit\Framework\TestCase
/**
* testGetRandomPassword
*
* @return number
* @return int
*/
public function testGetRandomPassword()
{
@@ -804,7 +885,7 @@ class SecurityTest extends PHPUnit\Framework\TestCase
/**
* testGetRandomPassword
*
* @return number
* @return int
*/
public function testGetURLContent()
{
@@ -1058,6 +1139,77 @@ class SecurityTest extends PHPUnit\Framework\TestCase
}
/**
* testDolPrintHTML.
* This method include calls to dol_htmlwithnojs()
*
* @return int
*/
public function testDolPrintHTML()
{
global $conf;
// Set options for cleaning data
$conf->global->MAIN_RESTRICTHTML_ONLY_VALID_HTML = 1;
// Enabled option MAIN_RESTRICTHTML_ONLY_VALID_HTML_TIDY if possible
if (extension_loaded('tidy') && class_exists("tidy")) {
$conf->global->MAIN_RESTRICTHTML_ONLY_VALID_HTML_TIDY = 1;
}
$conf->global->MAIN_RESTRICTHTML_REMOVE_ALSO_BAD_ATTRIBUTES = 1;
// For a string that is already HTML (contains HTML tags) with special tags but badly formated
$stringtotest = "&quot;&gt;";
$stringfixed = "&quot;&gt;";
//$result = dol_htmlentitiesbr($stringtotest);
//$result = dol_string_onlythesehtmltags(dol_htmlentitiesbr($stringtotest), 1, 1, 1, 0);
//$result = dol_htmlwithnojs(dol_string_onlythesehtmltags(dol_htmlentitiesbr($stringtotest), 1, 1, 1, 0));
//$result = dol_escape_htmltag(dol_htmlwithnojs(dol_string_onlythesehtmltags(dol_htmlentitiesbr($stringtotest), 1, 1, 1, 0)), 1, 1, 'common', 0, 1);
$result = dolPrintHTML($stringtotest);
print __METHOD__." result=".$result."\n";
$this->assertEquals($stringfixed, $result, 'Error'); // Expected '' because should failed because login 'auto' does not exists
// For a string that is already HTML (contains HTML tags) with special tags but badly formated
$stringtotest = "testA\n<h1>hhhh</h1><z>ddd</z><header>aaa</header><footer>bbb</footer>";
if (getDolGlobalString("MAIN_RESTRICTHTML_ONLY_VALID_HTML_TIDY")) {
$stringfixed = "testA\n<h1>hhhh</h1>\nddd\n<header>aaa</header>\n<footer>bbb</footer>";
} else {
$stringfixed = "testA\n<h1>hhhh</h1>ddd<header>aaa</header><footer>bbb</footer>";
}
//$result = dol_htmlentitiesbr($stringtotest);
//$result = dol_string_onlythesehtmltags(dol_htmlentitiesbr($stringtotest), 1, 1, 1, 0);
//$result = dol_htmlwithnojs(dol_string_onlythesehtmltags(dol_htmlentitiesbr($stringtotest), 1, 1, 1, 0));
//$result = dol_escape_htmltag(dol_htmlwithnojs(dol_string_onlythesehtmltags(dol_htmlentitiesbr($stringtotest), 1, 1, 1, 0)), 1, 1, 'common', 0, 1);
$result = dolPrintHTML($stringtotest);
print __METHOD__." result=".$result."\n";
$this->assertEquals($stringfixed, $result, 'Error'); // Expected '' because should failed because login 'auto' does not exists
// For a string that is already HTML (contains HTML tags) but badly formated
$stringtotest = "testB\n<h1>hhh</h1>\n<td>td alone</td><h1>iii</h1>";
if (getDolGlobalString("MAIN_RESTRICTHTML_ONLY_VALID_HTML_TIDY")) {
$stringfixed = "testB\n<h1>hhh</h1>\n<h1>iii</h1>\n<table>\n<tr>\n<td>td alone</td>\n</tr>\n</table>";
} else {
$stringfixed = "testB\n<h1>hhh</h1>\n<td>td alone</td><h1>iii</h1>";
}
$result = dolPrintHTML($stringtotest);
print __METHOD__." result=".$result."\n";
$this->assertEquals($stringfixed, $result, 'Error'); // Expected '' because should failed because login 'auto' does not exists
// For a string with no HTML tags
$stringtotest = "testC\ntest";
$stringfixed = "testC<br>\ntest";
$result = dolPrintHTML($stringtotest);
print __METHOD__." result=".$result."\n";
$this->assertEquals($stringfixed, $result, 'Error'); // Expected '' because should failed because login 'auto' does not exists
return 0;
}
/**
* testCheckLoginPassEntity
*