Skip to content

Commit a6da8e3

Browse files
committed
Change argument order of Processor. Add firewall dataset test.
1 parent 980c879 commit a6da8e3

6 files changed

Lines changed: 163 additions & 23 deletions

File tree

src/Processor.php

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,13 @@ class Processor
2929
*/
3030
private $whitelistRules = array();
3131

32+
/**
33+
* Firewall datasets which can be interacted with by the firewall rules.
34+
*
35+
* @var array
36+
*/
37+
private $dataset = array();
38+
3239
/**
3340
* The options of the engine.
3441
*
@@ -73,24 +80,26 @@ class Processor
7380
/**
7481
* Creates a new processor instance.
7582
*
83+
* @param ExtensionInterface $extension
7684
* @param array $firewallRules
7785
* @param array $firewallRulesLegacy
7886
* @param array $whitelistRules
7987
* @param array $options
80-
* @param ExtensionInterface $extension
8188
*/
8289
public function __construct(
83-
$firewallRules,
84-
$firewallRulesLegacy,
85-
$whitelistRules,
86-
$options,
87-
ExtensionInterface $extension
90+
ExtensionInterface $extension,
91+
$firewallRules = array(),
92+
$firewallRulesLegacy = array(),
93+
$whitelistRules = array(),
94+
$options = array(),
95+
$datasets = array()
8896
) {
97+
$this->extension = $extension;
8998
$this->firewallRules = $firewallRules;
9099
$this->firewallRulesLegacy = $firewallRulesLegacy;
91100
$this->whitelistRules = $whitelistRules;
92101
$this->options = array_merge($this->options, $options);
93-
$this->extension = $extension;
102+
$this->dataset = $datasets;
94103

95104
$this->secret = isset($options['secret']) ? $options['secret'] : 'secret';
96105
$this->request = new Request($this->options);
@@ -150,6 +159,8 @@ public function launch($mustExit = true)
150159
\Laravel\SerializableClosure\SerializableClosure::setSecretKey($this->secret);
151160
}
152161

162+
// Store the datasets in a shorter variable for easy access.
163+
$dataset = $this->dataset;
153164
foreach ($this->firewallRules as $rule) {
154165
// Get the firewall rule and extract it.
155166
$vpatch = base64_decode($rule->rule);

tests/FirewallDatasetTest.php

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
use PHPUnit\Framework\TestCase;
6+
use Patchstack\Processor;
7+
use Patchstack\Extensions\Test\Extension;
8+
9+
final class FirewallDatasetTest extends TestCase
10+
{
11+
/**
12+
* @var Processor
13+
*/
14+
protected $processor;
15+
16+
/**
17+
* @var array
18+
*/
19+
protected $rules;
20+
21+
/**
22+
* @var array
23+
*/
24+
protected $datasets;
25+
26+
/**
27+
* Setup the test for testing the header location redirect.
28+
*
29+
* @return void
30+
*/
31+
protected function setUp(): void
32+
{
33+
$this->datasets = json_decode(file_get_contents(dirname(__FILE__) . '/data/Datasets.json'), true);
34+
}
35+
36+
/**
37+
* Setup the firewall processor.
38+
*
39+
* @param array $rules
40+
* @return void
41+
*/
42+
private function setUpFirewallProcessor(array $rules)
43+
{
44+
$this->processor = new Processor(
45+
new Extension(),
46+
$rules,
47+
[],
48+
[],
49+
[],
50+
$this->datasets
51+
);
52+
}
53+
54+
/**
55+
* Alters the payload between tests.
56+
* For most firewall rules there's no difference if testing against GET or POST.
57+
* Therefore, both can be used for testing payloads.
58+
*
59+
* @return void
60+
*/
61+
private function alterPayload(array $payload = [])
62+
{
63+
$_POST = [];
64+
$_GET = [];
65+
66+
$_POST = isset($payload['POST']) ? $payload['POST'] : [];
67+
$_GET = isset($payload['GET']) ? $payload['GET'] : [];
68+
}
69+
70+
/**
71+
* Test specific firewall rules.
72+
*
73+
* @return void
74+
*/
75+
public function testRules()
76+
{
77+
// Since the Opis/Closure package does not support PHP 8.1+, we have to use Laravel's ported version for 8.1+.
78+
require dirname(__FILE__) . '/../vendor/autoload.php';
79+
if (PHP_VERSION_ID < 80100) {
80+
\Opis\Closure\SerializableClosure::setSecretKey('secret');
81+
class_alias('\Opis\Closure\SerializableClosure', 'SerializeClosure');
82+
} else {
83+
\Laravel\SerializableClosure\SerializableClosure::setSecretKey('secret');
84+
class_alias('\Laravel\SerializableClosure\SerializableClosure', 'SerializeClosure');
85+
}
86+
87+
// For easier access we store the datasets inside of $datasets as it will function
88+
// like this in the firewall rule processor as well.
89+
$datasets = $this->datasets;
90+
91+
// Create the firewall rule.
92+
$function = function () use ($datasets) {
93+
return in_array($_SERVER['REMOTE_ADDR'], $datasets['ps_ips']);
94+
};
95+
$wrapper = new SerializeClosure($function);
96+
$rule = (object) [
97+
'id' => 1,
98+
'title' => 'Determine if IP is in blacklist',
99+
'rule' => base64_encode(serialize($wrapper)),
100+
'cat' => 'TEST',
101+
'type' => 'BLOCK'
102+
];
103+
104+
// Test the rule.
105+
$_SERVER['REMOTE_ADDR'] = '1.1.1.1';
106+
$this->setUpFirewallProcessor([$rule]);
107+
$this->assertFalse($this->processor->launch(false));
108+
$_SERVER['REMOTE_ADDR'] = '';
109+
110+
// Create the firewall rule.
111+
$function = function () use ($datasets) {
112+
return preg_match($datasets['ps_sqli'], $_GET['id']) === 1;
113+
};
114+
$wrapper = new SerializeClosure($function);
115+
$rule = (object) [
116+
'id' => 1,
117+
'title' => 'Determine if union all select regex is a hit in the id GET parameter',
118+
'rule' => base64_encode(serialize($wrapper)),
119+
'cat' => 'TEST',
120+
'type' => 'BLOCK'
121+
];
122+
123+
// Test the rule.
124+
$this->setUpFirewallProcessor([$rule]);
125+
$this->alterPayload(
126+
['GET' => [
127+
'id' => '1 UNION ALL SELECT 1,2,3,4,5,@@version-- '
128+
]]
129+
);
130+
$this->assertFalse($this->processor->launch(false));
131+
$this->alterPayload();
132+
}
133+
}

tests/FirewallLegacyTest.php

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,9 @@ protected function setUp(): void
3737
private function setUpFirewallProcessor(array $rules)
3838
{
3939
$this->processor = new Processor(
40+
new Extension(),
4041
[],
41-
$rules,
42-
[],
43-
[],
44-
new Extension()
42+
$rules
4543
);
4644
}
4745

tests/FirewallRuleCreationTest.php

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,8 @@ protected function setUp(): void
3737
private function setUpFirewallProcessor(array $rules)
3838
{
3939
$this->processor = new Processor(
40-
$rules,
41-
[],
42-
[],
43-
[],
44-
new Extension()
40+
new Extension(),
41+
$rules
4542
);
4643
}
4744

@@ -72,10 +69,8 @@ public function testFirewallRuleCreation()
7269
require dirname(__FILE__) . '/../vendor/autoload.php';
7370
if (PHP_VERSION_ID < 80100) {
7471
\Opis\Closure\SerializableClosure::setSecretKey('secret');
75-
class_alias('\Opis\Closure\SerializableClosure', 'SerializeClosure');
7672
} else {
7773
\Laravel\SerializableClosure\SerializableClosure::setSecretKey('secret');
78-
class_alias('\Laravel\SerializableClosure\SerializableClosure', 'SerializeClosure');
7974
}
8075

8176
// Create the firewall rule.
@@ -126,5 +121,6 @@ class_alias('\Laravel\SerializableClosure\SerializableClosure', 'SerializeClosur
126121
]]
127122
);
128123
$this->assertFalse($this->processor->launch(false));
124+
$this->alterPayload();
129125
}
130126
}

tests/FirewallTest.php

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,8 @@ protected function setUp(): void
3737
private function setUpFirewallProcessor(array $rules)
3838
{
3939
$this->processor = new Processor(
40-
$rules,
41-
[],
42-
[],
43-
[],
44-
new Extension()
40+
new Extension(),
41+
$rules
4542
);
4643
}
4744

@@ -97,5 +94,6 @@ public function testRules()
9794
]]
9895
);
9996
$this->assertFalse($this->processor->launch(false));
97+
$this->alterPayload();
10098
}
10199
}

tests/data/Datasets.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"ps_ips":["1.1.1.1","2.2.2.2","3.3.3.3"],
3+
"ps_sqli":"/(union all select)/msi"
4+
}

0 commit comments

Comments
 (0)