Skip to content

Commit aba7790

Browse files
authored
Merge pull request #461 from magento-jackalopes/MAGETWO-56133-unsecure-functions
Fixed Issue: - MAGETWO-56133 Prevent new code from including unsecure functions
2 parents ad37944 + ec974f6 commit aba7790

File tree

3 files changed

+179
-0
lines changed

3 files changed

+179
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
<?php
2+
/**
3+
* Copyright © 2016 Magento. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
namespace Magento\Test\Legacy;
7+
8+
use Magento\Framework\App\Utility\Files;
9+
10+
/**
11+
* Tests to detect unsecure functions usage
12+
*/
13+
class UnsecureFunctionsUsageTest extends \PHPUnit_Framework_TestCase
14+
{
15+
/**
16+
* File extensions pattern to search for
17+
*
18+
* @var string
19+
*/
20+
private $fileExtensions = '/\.(php|phtml|js)$/';
21+
22+
/**
23+
* Php unsecure functions to detect
24+
*
25+
* @var array
26+
*/
27+
private $phpUnsecureFunctions = [
28+
'unserialize',
29+
'serialize',
30+
'eval',
31+
'md5',
32+
'srand',
33+
'mt_srand'
34+
];
35+
36+
/**
37+
* JS unsecure functions to detect
38+
*
39+
* @var array
40+
*/
41+
private $jsUnsecureFunctions = [];
42+
43+
/**
44+
* Detect unsecure functions usage for changed files in whitelist with the exception of blacklist
45+
*
46+
* @return void
47+
*/
48+
public function testUnsecureFunctionsUsage()
49+
{
50+
$invoker = new \Magento\Framework\App\Utility\AggregateInvoker($this);
51+
$invoker(
52+
function ($fileName) {
53+
$result = '';
54+
$errorMessage = 'The following functions are non secure and should be avoided: '
55+
. implode(', ', $this->phpUnsecureFunctions)
56+
. ' for PHP';
57+
if (!empty($this->jsUnsecureFunctions)) {
58+
$errorMessage .= ', and '
59+
. implode(', ', $this->jsUnsecureFunctions)
60+
. ' for JavaScript';
61+
}
62+
$errorMessage .= ".\n";
63+
$regexp = $this->getRegexpByFileExtension(pathinfo($fileName, PATHINFO_EXTENSION));
64+
if ($regexp) {
65+
$matches = preg_grep(
66+
$regexp,
67+
file($fileName, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES)
68+
);
69+
if (!empty($matches)) {
70+
foreach (array_keys($matches) as $line) {
71+
$result .= $fileName . ':' . ($line + 1) . "\n";
72+
}
73+
}
74+
$this->assertEmpty($result, $errorMessage . $result);
75+
}
76+
},
77+
$this->unsecureFunctionsUsageDataProvider()
78+
);
79+
}
80+
81+
/**
82+
* Data provider for test
83+
*
84+
* @return array
85+
*/
86+
public function unsecureFunctionsUsageDataProvider()
87+
{
88+
$fileExtensions = $this->fileExtensions;
89+
$directoriesToScan = Files::init()->readLists(__DIR__ . '/_files/security/whitelist.txt');
90+
$blackListFiles = include __DIR__ . '/_files/security/blacklist.php';
91+
92+
$filesToVerify = [];
93+
foreach (glob(__DIR__ . '/../_files/changed_files*') as $listFile) {
94+
$filesToVerify = array_merge(
95+
$filesToVerify,
96+
file($listFile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES)
97+
);
98+
}
99+
array_walk(
100+
$filesToVerify,
101+
function (&$file) {
102+
$file = [BP . '/' . $file];
103+
}
104+
);
105+
$filesToVerify = array_filter(
106+
$filesToVerify,
107+
function ($path) use ($directoriesToScan, $fileExtensions, $blackListFiles) {
108+
if (!file_exists($path[0])) {
109+
return false;
110+
}
111+
$path = realpath($path[0]);
112+
foreach ($directoriesToScan as $directory) {
113+
$directory = realpath($directory);
114+
if (strpos($path, $directory) === 0) {
115+
if (preg_match($fileExtensions, $path)) {
116+
foreach ($blackListFiles as $blackListFile) {
117+
if (preg_match($blackListFile, $path)) {
118+
return false;
119+
}
120+
}
121+
return true;
122+
}
123+
}
124+
}
125+
return false;
126+
}
127+
);
128+
return $filesToVerify;
129+
}
130+
131+
/**
132+
* Get regular expression by file extension
133+
*
134+
* @param string $fileExtension
135+
* @return string|bool
136+
*/
137+
private function getRegexpByFileExtension($fileExtension)
138+
{
139+
$regexp = false;
140+
if ($fileExtension == 'php') {
141+
$regexp = $this->prepareRegexp($this->phpUnsecureFunctions);
142+
} elseif ($fileExtension == 'js') {
143+
$regexp = $this->prepareRegexp($this->jsUnsecureFunctions);
144+
} elseif ($fileExtension == 'phtml') {
145+
$regexp = $this->prepareRegexp($this->phpUnsecureFunctions + $this->jsUnsecureFunctions);
146+
}
147+
return $regexp;
148+
}
149+
150+
/**
151+
* Prepare regular expression for unsecure function names
152+
*
153+
* @param array $functions
154+
* @return string
155+
*/
156+
private function prepareRegexp(array $functions)
157+
{
158+
if (empty($functions)) {
159+
return '';
160+
}
161+
$regexArray = [];
162+
foreach ($functions as $function) {
163+
$regexArray[] = '\b' . $function . '\b\(';
164+
}
165+
return '/' . implode('|', $regexArray) . '/i';
166+
}
167+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?php
2+
/**
3+
* Copyright © 2016 Magento. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
return [
7+
'/Test\/Unit/'
8+
];
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
module * /
2+
library * /
3+
setup
4+
pub

0 commit comments

Comments
 (0)