Skip to content

Commit eb9cd26

Browse files
committed
Add more sniffs
1 parent f49a329 commit eb9cd26

File tree

9 files changed

+276
-0
lines changed

9 files changed

+276
-0
lines changed
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace NthRoot\PhpSecuritySniffs\Security\Sniffs\BrokenAccessControl;
6+
7+
use NthRoot\PhpSecuritySniffs\Security\Sniffs\UserInputDetector;
8+
use PHP_CodeSniffer\Files\File;
9+
use PHP_CodeSniffer\Sniffs\Sniff;
10+
11+
use function in_array;
12+
13+
use const T_OPEN_PARENTHESIS;
14+
use const T_STRING;
15+
16+
final class PathTraversalSniff implements Sniff
17+
{
18+
const array DANGEROUS_FUNCTIONS = ['fopen', 'file_get_contents'];
19+
20+
protected UserInputDetector $userInputDetector;
21+
22+
public function __construct()
23+
{
24+
$this->userInputDetector = new UserInputDetector();
25+
}
26+
27+
public function register(): array
28+
{
29+
return [T_STRING];
30+
}
31+
32+
public function process(File $phpcsFile, $stackPtr): void
33+
{
34+
$tokens = $phpcsFile->getTokens();
35+
36+
if (!in_array($tokens[$stackPtr]['content'], self::DANGEROUS_FUNCTIONS, true)) {
37+
return;
38+
}
39+
40+
$start = $phpcsFile->findNext(T_OPEN_PARENTHESIS, $stackPtr, null, false, null, true);
41+
42+
if ($this->userInputDetector->containsUserInput($phpcsFile, $start)) {
43+
$phpcsFile->addError(
44+
sprintf(
45+
"Passing user input to %s() can lead to path traversal attacks (CWE-22)",
46+
$tokens[$stackPtr]['content']
47+
),
48+
$stackPtr,
49+
'FoundWithUserInput'
50+
);
51+
52+
return;
53+
}
54+
55+
if ($this->userInputDetector->containsVariableInput($phpcsFile, $start)) {
56+
$phpcsFile->addWarning(
57+
sprintf(
58+
"Passing variable data to %s() can lead to path traversal attacks (CWE-22) if it contains user input",
59+
$tokens[$stackPtr]['content']
60+
),
61+
$stackPtr,
62+
'FoundWithVariableInput'
63+
);
64+
}
65+
}
66+
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace NthRoot\PhpSecuritySniffs\Security\Sniffs\Injection;
6+
7+
use NthRoot\PhpSecuritySniffs\Security\Sniffs\UserInputDetector;
8+
use PHP_CodeSniffer\Files\File;
9+
use PHP_CodeSniffer\Sniffs\Sniff;
10+
11+
use function in_array;
12+
13+
use const T_OBJECT_OPERATOR;
14+
use const T_OPEN_PARENTHESIS;
15+
use const T_STRING;
16+
use const T_VARIABLE;
17+
18+
final class SqlInjectionSniff implements Sniff
19+
{
20+
private const array FUNCTIONS = [
21+
'mysqli_query',
22+
'mysqli_real_query',
23+
'mysqli_multi_query',
24+
];
25+
26+
private const array METHODS = [
27+
'query',
28+
'prepare',
29+
];
30+
31+
private UserInputDetector $userInputDetector;
32+
33+
public function __construct()
34+
{
35+
$this->userInputDetector = new UserInputDetector();
36+
}
37+
38+
public function register(): array
39+
{
40+
return [T_STRING];
41+
}
42+
43+
public function process(File $phpcsFile, $stackPtr): void
44+
{
45+
$tokens = $phpcsFile->getTokens();
46+
47+
$function = $tokens[$stackPtr]['content'];
48+
49+
if ($objectOperator = $phpcsFile->findPrevious(T_OBJECT_OPERATOR, $stackPtr - 1, null, false, null, true)) {
50+
$object = $phpcsFile->findPrevious([T_STRING, T_VARIABLE], $objectOperator - 1, null, false, null, true);
51+
$object = $tokens[$object]['content'];
52+
}
53+
54+
if ($objectOperator === false && !in_array($function, self::FUNCTIONS, true)) {
55+
return;
56+
}
57+
58+
if ($objectOperator !== false && !in_array($function, self::METHODS, true)) {
59+
return;
60+
}
61+
62+
$openParenthesis = $phpcsFile->findNext(T_OPEN_PARENTHESIS, $stackPtr, null, false, null, true);
63+
64+
if ($this->userInputDetector->containsUserInput($phpcsFile, $openParenthesis)) {
65+
$phpcsFile->addError(
66+
sprintf(
67+
'Passing user input to %s() can lead to SQL injection (CWE-89)',
68+
isset($object) ? $object . '->' . $function : $function
69+
),
70+
$stackPtr,
71+
'FoundWithUserInput'
72+
);
73+
}
74+
}
75+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace NthRoot\PhpSecuritySniffs\Security\Sniffs\SensitiveInformationExposure;
6+
7+
use PHP_CodeSniffer\Files\File;
8+
use PHP_CodeSniffer\Sniffs\Sniff;
9+
10+
use function in_array;
11+
use function sprintf;
12+
13+
use const T_STRING;
14+
15+
final class DebuggingFunctionSniff implements Sniff
16+
{
17+
private const array DEBUGGING_FUNCTIONS = ['var_dump', 'dump', 'dd', 'print_r'];
18+
19+
public function register(): array
20+
{
21+
return [T_STRING];
22+
}
23+
24+
public function process(File $phpcsFile, $stackPtr): void
25+
{
26+
$tokens = $phpcsFile->getTokens();
27+
28+
if (!in_array($tokens[$stackPtr]['content'], self::DEBUGGING_FUNCTIONS, true)) {
29+
return;
30+
}
31+
32+
$phpcsFile->addWarning(
33+
sprintf(
34+
'Leaving debugging functions such as %s() in the code might lead to sensitive data exposure (CWE-489)',
35+
$tokens[$stackPtr]['content']
36+
),
37+
$stackPtr,
38+
'Found'
39+
);
40+
}
41+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<?php
2+
3+
$file = $_GET['file'];
4+
5+
$contents = file_get_contents($file);
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace NthRoot\PhpSecuritySniffs\Security\Tests\BrokenAccessControl;
6+
7+
use NthRoot\PhpSecuritySniffs\Security\Tests\SecuritySniffTestCase;
8+
9+
final class PathTraversalUnitTest extends SecuritySniffTestCase
10+
{
11+
protected function getErrorList(): array
12+
{
13+
return [
14+
5 => 1,
15+
];
16+
}
17+
18+
protected function getWarningList(): array
19+
{
20+
return [];
21+
}
22+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?php
2+
3+
$id = $_GET['id'];
4+
5+
$query = 'SELECT * FROM users WHERE id = ' . $id;
6+
7+
mysqli_query($query);
8+
9+
$pdo = new PDO('');
10+
11+
$statement = $pdo->prepare($query);
12+
$statement = $pdo->query($query);
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace NthRoot\PhpSecuritySniffs\Security\Tests\Injection;
6+
7+
use NthRoot\PhpSecuritySniffs\Security\Tests\SecuritySniffTestCase;
8+
9+
final class SqlInjectionUnitTest extends SecuritySniffTestCase
10+
{
11+
protected function getErrorList(): array
12+
{
13+
return [
14+
7 => 1,
15+
11 => 1,
16+
12 => 1,
17+
];
18+
}
19+
20+
protected function getWarningList(): array
21+
{
22+
return [];
23+
}
24+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<?php
2+
3+
print_r('foo');
4+
var_dump($user);
5+
dump($user);
6+
dd($user);
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace NthRoot\PhpSecuritySniffs\Security\Tests\SensitiveInformationExposure;
6+
7+
use NthRoot\PhpSecuritySniffs\Security\Tests\SecuritySniffTestCase;
8+
9+
final class DebuggingFunctionUnitTest extends SecuritySniffTestCase
10+
{
11+
protected function getErrorList(): array
12+
{
13+
return [];
14+
}
15+
16+
protected function getWarningList(): array
17+
{
18+
return [
19+
3 => 1,
20+
4 => 1,
21+
5 => 1,
22+
6 => 1,
23+
];
24+
}
25+
}

0 commit comments

Comments
 (0)