diff --git a/php-checks/src/main/java/org/sonar/php/checks/EmptyDatabasePasswordCheck.java b/php-checks/src/main/java/org/sonar/php/checks/EmptyDatabasePasswordCheck.java index c6f27fa3ce..2306281ed8 100644 --- a/php-checks/src/main/java/org/sonar/php/checks/EmptyDatabasePasswordCheck.java +++ b/php-checks/src/main/java/org/sonar/php/checks/EmptyDatabasePasswordCheck.java @@ -21,14 +21,15 @@ import java.util.ArrayList; import java.util.List; +import java.util.Optional; import java.util.regex.Pattern; import org.sonar.check.Rule; import org.sonar.php.checks.utils.CheckUtils; import org.sonar.php.tree.visitors.AssignmentExpressionVisitor; import org.sonar.plugins.php.api.symbols.Symbol; import org.sonar.plugins.php.api.tree.CompilationUnitTree; -import org.sonar.plugins.php.api.tree.SeparatedList; import org.sonar.plugins.php.api.tree.Tree.Kind; +import org.sonar.plugins.php.api.tree.declaration.CallArgumentTree; import org.sonar.plugins.php.api.tree.expression.ArrayInitializerTree; import org.sonar.plugins.php.api.tree.expression.ArrayPairTree; import org.sonar.plugins.php.api.tree.expression.BinaryExpressionTree; @@ -58,9 +59,9 @@ public void visitCompilationUnit(CompilationUnitTree tree) { public void visitFunctionCall(FunctionCallTree functionCall) { String functionName = CheckUtils.getLowerCaseFunctionName(functionCall); if ("mysqli".equals(functionName) || "mysqli_connect".equals(functionName) || "PDO".equalsIgnoreCase(functionName)) { - checkPasswordArgument(functionCall, 2); + checkPasswordArgument(functionCall, "passwd", 2); } else if ("oci_connect".equals(functionName)) { - checkPasswordArgument(functionCall, 1); + checkPasswordArgument(functionCall, "password", 1); } else if ("sqlsrv_connect".equals(functionName)) { checkSqlServer(functionCall); } else if ("pg_connect".equals(functionName)) { @@ -69,10 +70,10 @@ public void visitFunctionCall(FunctionCallTree functionCall) { super.visitFunctionCall(functionCall); } - private void checkPasswordArgument(FunctionCallTree functionCall, int argumentIndex) { - SeparatedList arguments = functionCall.arguments(); - if (arguments.size() > argumentIndex) { - ExpressionTree passwordArgument = arguments.get(argumentIndex); + private void checkPasswordArgument(FunctionCallTree functionCall, String argumentName, int argumentIndex) { + Optional argument = CheckUtils.argument(functionCall, argumentName, argumentIndex); + if (argument.isPresent()) { + ExpressionTree passwordArgument = argument.get().value(); if (hasEmptyValue(passwordArgument)) { context().newIssue(this, passwordArgument, MESSAGE); } @@ -101,10 +102,9 @@ private boolean hasEmptyValue(ExpressionTree expression) { } private void checkSqlServer(FunctionCallTree functionCall) { - SeparatedList arguments = functionCall.arguments(); - int argumentIndex = 1; - if (arguments.size() > argumentIndex) { - ExpressionTree connectionInfo = arguments.get(argumentIndex); + Optional argument = CheckUtils.argument(functionCall, "connectionInfo", 1); + if (argument.isPresent()) { + ExpressionTree connectionInfo = argument.get().value(); ExpressionTree password = sqlServerPassword(connectionInfo); if (password != null && hasEmptyValue(password)) { context().newIssue(this, password, MESSAGE); @@ -130,11 +130,11 @@ private ExpressionTree sqlServerPassword(ExpressionTree connectionInfo) { } private void checkPostgresql(FunctionCallTree functionCall) { - SeparatedList arguments = functionCall.arguments(); - if (arguments.isEmpty()) { + Optional connectionStringArgument = CheckUtils.argument(functionCall, "connection_string", 0); + if (!connectionStringArgument.isPresent()) { return; } - ExpressionTree connectionString = arguments.get(0); + ExpressionTree connectionString = connectionStringArgument.get().value(); Symbol connectionStringSymbol = context().symbolTable().getSymbol(connectionString); connectionString = assignmentExpressionVisitor .getUniqueAssignedValue(connectionStringSymbol) diff --git a/php-checks/src/main/java/org/sonar/php/checks/EncryptionModeAndPaddingCheck.java b/php-checks/src/main/java/org/sonar/php/checks/EncryptionModeAndPaddingCheck.java index 0ef3d1bdf2..85ae348480 100644 --- a/php-checks/src/main/java/org/sonar/php/checks/EncryptionModeAndPaddingCheck.java +++ b/php-checks/src/main/java/org/sonar/php/checks/EncryptionModeAndPaddingCheck.java @@ -64,10 +64,10 @@ private static Set opensslPublicEncryptNoncompliantValues() { public void visitFunctionCall(FunctionCallTree tree) { // by default OPENSSL_PKCS1_PADDING is used as padding mode argument if (!checkArgumentAbsence(tree, OPENSSL_PUBLIC_ENCRYPT, 3)) { - checkArgument(tree, OPENSSL_PUBLIC_ENCRYPT, new ArgumentVerifier(3, OPENSSL_PUBLIC_ENCRYPT_COMPLIANT_VALUE, false)); + checkArgument(tree, OPENSSL_PUBLIC_ENCRYPT, new ArgumentVerifier(3, "padding", OPENSSL_PUBLIC_ENCRYPT_COMPLIANT_VALUE, false)); } - checkArgument(tree, OPENSSL_ENCRYPT, new ArgumentVerifier(1, OPENSSL_ENCRYPT_NONCOMPLIANT_VALUES, true)); - checkArgument(tree, MCRYPT_ENCRYPT, new ArgumentVerifier(3, MCRYPT_ENCRYPT_NONCOMPLIANT_VALUE, true)); + checkArgument(tree, OPENSSL_ENCRYPT, new ArgumentVerifier(1, "method", OPENSSL_ENCRYPT_NONCOMPLIANT_VALUES, true)); + checkArgument(tree, MCRYPT_ENCRYPT, new ArgumentVerifier(3, "mode", MCRYPT_ENCRYPT_NONCOMPLIANT_VALUE, true)); super.visitFunctionCall(tree); } diff --git a/php-checks/src/main/java/org/sonar/php/checks/HashFunctionCheck.java b/php-checks/src/main/java/org/sonar/php/checks/HashFunctionCheck.java index 639af9c98b..22cb9ea8a3 100644 --- a/php-checks/src/main/java/org/sonar/php/checks/HashFunctionCheck.java +++ b/php-checks/src/main/java/org/sonar/php/checks/HashFunctionCheck.java @@ -29,6 +29,7 @@ import org.sonar.plugins.php.api.symbols.Symbol; import org.sonar.plugins.php.api.tree.CompilationUnitTree; import org.sonar.plugins.php.api.tree.Tree; +import org.sonar.plugins.php.api.tree.declaration.CallArgumentTree; import org.sonar.plugins.php.api.tree.expression.ArrayAccessTree; import org.sonar.plugins.php.api.tree.expression.ArrayInitializerBracketTree; import org.sonar.plugins.php.api.tree.expression.ArrayPairTree; @@ -54,18 +55,22 @@ public class HashFunctionCheck extends PHPVisitorCheck { @Override public void visitFunctionCall(FunctionCallTree tree) { String functionName = CheckUtils.getLowerCaseFunctionName(tree); - if ("hash_pbkdf2".equals(functionName) && tree.arguments().size() >= 3) { - ExpressionTree saltArgument = tree.arguments().get(2); - if (isPredictable(saltArgument)) { - context().newIssue(this, saltArgument, MESSAGE); + if ("hash_pbkdf2".equals(functionName)) { + Optional saltArgument = CheckUtils.argument(tree, "salt", 2); + if (saltArgument.isPresent()) { + ExpressionTree saltArgumentValue = saltArgument.get().value(); + if (isPredictable(saltArgumentValue)) { + context().newIssue(this, saltArgumentValue, MESSAGE); + } } } else if ("crypt".equals(functionName)) { - if (tree.arguments().size() < 2) { + Optional saltArgument = CheckUtils.argument(tree, "salt", 1); + if (!saltArgument.isPresent()) { context().newIssue(this, tree, MESSAGE_MISSING_SALT); } else { - ExpressionTree saltArgument = tree.arguments().get(1); - if (isPredictable(saltArgument)) { - context().newIssue(this, saltArgument, MESSAGE); + ExpressionTree saltArgumentValue = saltArgument.get().value(); + if (isPredictable(saltArgumentValue)) { + context().newIssue(this, saltArgumentValue, MESSAGE); } } } else if ("password_hash".equals(functionName)) { diff --git a/php-checks/src/main/java/org/sonar/php/checks/NoPaddingRsaCheck.java b/php-checks/src/main/java/org/sonar/php/checks/NoPaddingRsaCheck.java index 1f5e665a19..8eec676aef 100644 --- a/php-checks/src/main/java/org/sonar/php/checks/NoPaddingRsaCheck.java +++ b/php-checks/src/main/java/org/sonar/php/checks/NoPaddingRsaCheck.java @@ -20,9 +20,12 @@ package org.sonar.php.checks; import com.google.common.collect.ImmutableSet; +import java.util.Optional; import org.sonar.check.Rule; +import org.sonar.php.checks.utils.CheckUtils; import org.sonar.php.checks.utils.FunctionUsageCheck; import org.sonar.plugins.php.api.tree.Tree.Kind; +import org.sonar.plugins.php.api.tree.declaration.CallArgumentTree; import org.sonar.plugins.php.api.tree.declaration.NamespaceNameTree; import org.sonar.plugins.php.api.tree.expression.ExpressionTree; import org.sonar.plugins.php.api.tree.expression.FunctionCallTree; @@ -43,8 +46,9 @@ protected ImmutableSet functionNames() { @Override protected void createIssue(FunctionCallTree tree) { - if (tree.arguments().size() > PADDING_ARGUMENT_INDEX) { - ExpressionTree padding = tree.arguments().get(PADDING_ARGUMENT_INDEX); + Optional paddingArgument = CheckUtils.argument(tree, "padding", PADDING_ARGUMENT_INDEX); + if (paddingArgument.isPresent()) { + ExpressionTree padding = paddingArgument.get().value(); if (padding.is(Kind.NAMESPACE_NAME) && !((NamespaceNameTree) padding).fullName().equals(SECURE_PADDING)) { context().newIssue(this, padding, MESSAGE); } diff --git a/php-checks/src/main/java/org/sonar/php/checks/SSLCertificatesVerificationDisabledCheck.java b/php-checks/src/main/java/org/sonar/php/checks/SSLCertificatesVerificationDisabledCheck.java index a2038713d9..52340556be 100644 --- a/php-checks/src/main/java/org/sonar/php/checks/SSLCertificatesVerificationDisabledCheck.java +++ b/php-checks/src/main/java/org/sonar/php/checks/SSLCertificatesVerificationDisabledCheck.java @@ -38,7 +38,7 @@ public class SSLCertificatesVerificationDisabledCheck extends FunctionArgumentCh @Override public void visitFunctionCall(FunctionCallTree tree) { - checkArgument(tree, CURL_SETOPT, new ArgumentMatcher(1, CURLOPT_SSL_VERIFYPEER), new ArgumentVerifier(2, VERIFY_PEER_COMPLIANT_VALUES)); + checkArgument(tree, CURL_SETOPT, new ArgumentMatcher(1, "option", CURLOPT_SSL_VERIFYPEER), new ArgumentVerifier(2, "value", VERIFY_PEER_COMPLIANT_VALUES)); super.visitFunctionCall(tree); } diff --git a/php-checks/src/main/java/org/sonar/php/checks/SSLHostVerificationDisabledCheck.java b/php-checks/src/main/java/org/sonar/php/checks/SSLHostVerificationDisabledCheck.java index 85ffd92685..ceb9479f0f 100644 --- a/php-checks/src/main/java/org/sonar/php/checks/SSLHostVerificationDisabledCheck.java +++ b/php-checks/src/main/java/org/sonar/php/checks/SSLHostVerificationDisabledCheck.java @@ -37,7 +37,7 @@ public class SSLHostVerificationDisabledCheck extends FunctionArgumentCheck { @Override public void visitFunctionCall(FunctionCallTree tree) { - checkArgument(tree, CURL_SETOPT, new ArgumentMatcher(1, CURLOPT_SSL_VERIFYHOST), new ArgumentVerifier(2, VERIFY_HOST_COMPLIANT_VALUES, false)); + checkArgument(tree, CURL_SETOPT, new ArgumentMatcher(1, "option", CURLOPT_SSL_VERIFYHOST), new ArgumentVerifier(2, "value", VERIFY_HOST_COMPLIANT_VALUES, false)); super.visitFunctionCall(tree); } diff --git a/php-checks/src/main/java/org/sonar/php/checks/SessionCookiePersistenceCheck.java b/php-checks/src/main/java/org/sonar/php/checks/SessionCookiePersistenceCheck.java index bc69cadb53..97345de021 100644 --- a/php-checks/src/main/java/org/sonar/php/checks/SessionCookiePersistenceCheck.java +++ b/php-checks/src/main/java/org/sonar/php/checks/SessionCookiePersistenceCheck.java @@ -22,15 +22,17 @@ import com.google.common.collect.ImmutableSet; import java.util.ArrayList; import java.util.List; +import java.util.Optional; import org.sonar.check.Rule; +import org.sonar.php.checks.utils.CheckUtils; import org.sonar.php.checks.utils.FunctionUsageCheck; import org.sonar.php.ini.BasePhpIniIssue; import org.sonar.php.ini.PhpIniCheck; import org.sonar.php.ini.PhpIniIssue; import org.sonar.php.ini.tree.Directive; import org.sonar.php.ini.tree.PhpIniFile; -import org.sonar.plugins.php.api.tree.SeparatedList; import org.sonar.plugins.php.api.tree.Tree.Kind; +import org.sonar.plugins.php.api.tree.declaration.CallArgumentTree; import org.sonar.plugins.php.api.tree.expression.ExpressionTree; import org.sonar.plugins.php.api.tree.expression.FunctionCallTree; import org.sonar.plugins.php.api.tree.expression.LiteralTree; @@ -39,7 +41,7 @@ public class SessionCookiePersistenceCheck extends FunctionUsageCheck implements PhpIniCheck { private static final String PHP_INI_MESSAGE = "Configure \"session.cookie_lifetime\" to 0."; - private static final String PHP_CODE_MESSAGE = "Pass \"0\" as first argument."; + private static final String PHP_CODE_MESSAGE = "Set \"lifetime\" parameter to \"0\"."; @Override public List analyze(PhpIniFile phpIniFile) { @@ -60,13 +62,13 @@ protected ImmutableSet functionNames() { @Override protected void createIssue(FunctionCallTree functionCall) { - SeparatedList arguments = functionCall.arguments(); - if (!arguments.isEmpty()) { - ExpressionTree firstArgument = arguments.get(0); - if (firstArgument.is(Kind.NUMERIC_LITERAL)) { - LiteralTree literal = (LiteralTree) firstArgument; + Optional lifetimeArgument = CheckUtils.argument(functionCall, "lifetime", 0); + if (lifetimeArgument.isPresent()) { + ExpressionTree lifetimeArgumentValue = lifetimeArgument.get().value(); + if (lifetimeArgumentValue.is(Kind.NUMERIC_LITERAL)) { + LiteralTree literal = (LiteralTree) lifetimeArgumentValue; if (!"0".equals(literal.value())) { - context().newIssue(this, firstArgument, PHP_CODE_MESSAGE); + context().newIssue(this, lifetimeArgumentValue, PHP_CODE_MESSAGE); } } } diff --git a/php-checks/src/main/java/org/sonar/php/checks/WeakSSLProtocolCheck.java b/php-checks/src/main/java/org/sonar/php/checks/WeakSSLProtocolCheck.java index ceb7e3f7c7..91d934c743 100644 --- a/php-checks/src/main/java/org/sonar/php/checks/WeakSSLProtocolCheck.java +++ b/php-checks/src/main/java/org/sonar/php/checks/WeakSSLProtocolCheck.java @@ -32,6 +32,7 @@ import org.sonar.plugins.php.api.symbols.Symbol; import org.sonar.plugins.php.api.tree.CompilationUnitTree; import org.sonar.plugins.php.api.tree.Tree; +import org.sonar.plugins.php.api.tree.declaration.CallArgumentTree; import org.sonar.plugins.php.api.tree.declaration.NamespaceNameTree; import org.sonar.plugins.php.api.tree.expression.ArrayInitializerTree; import org.sonar.plugins.php.api.tree.expression.BinaryExpressionTree; @@ -94,16 +95,22 @@ public void visitCompilationUnit(CompilationUnitTree tree) { public void visitFunctionCall(FunctionCallTree tree) { String functionName = CheckUtils.getLowerCaseFunctionName(tree); List arguments = tree.arguments(); - if (STREAM_CONTEXT_CREATE.equals(functionName) && !arguments.isEmpty()) { - checkStreamSSLConfig(arguments.get(0)); + if (STREAM_CONTEXT_CREATE.equals(functionName)) { + CheckUtils.argument(tree, "options", 0).ifPresent( + options -> checkStreamSSLConfig(options.value())); } - if (STREAM_SOCKET_ENABLE_CRYPTO.equals(functionName) && arguments.size() > 2) { - checkStreamWeakProtocol(getAssignedValue(arguments.get(2)), STREAM_SOCKET_ENABLE_CRYPTO); + if (STREAM_SOCKET_ENABLE_CRYPTO.equals(functionName)) { + CheckUtils.argument(tree, "crypto_type", 2).ifPresent( + cryptoType -> checkStreamWeakProtocol(getAssignedValue(cryptoType.value()), STREAM_SOCKET_ENABLE_CRYPTO)); } - if (CURL_SETOPT.equals(functionName) && arguments.size() > 2) { - ExpressionTree optionArgument = arguments.get(1); - if (optionArgument.is(Tree.Kind.NAMESPACE_NAME) && "CURLOPT_SSLVERSION".equals(((NamespaceNameTree) optionArgument).name().text())) { - checkCURLWeakProtocol(getAssignedValue(arguments.get(2))); + if (CURL_SETOPT.equals(functionName)) { + Optional optionArgument = CheckUtils.argument(tree, "option", 1); + Optional valueArgument = CheckUtils.argument(tree, "value", 2); + if (optionArgument.isPresent() && valueArgument.isPresent()) { + ExpressionTree optionArgumentValue = optionArgument.get().value(); + if (optionArgumentValue.is(Tree.Kind.NAMESPACE_NAME) && "CURLOPT_SSLVERSION".equals(((NamespaceNameTree) optionArgumentValue).name().text())) { + checkCURLWeakProtocol(getAssignedValue(valueArgument.get().value())); + } } } super.visitFunctionCall(tree); diff --git a/php-checks/src/main/java/org/sonar/php/checks/security/LDAPAuthenticatedConnectionCheck.java b/php-checks/src/main/java/org/sonar/php/checks/security/LDAPAuthenticatedConnectionCheck.java index 028be6cf6a..96ebe73ed9 100644 --- a/php-checks/src/main/java/org/sonar/php/checks/security/LDAPAuthenticatedConnectionCheck.java +++ b/php-checks/src/main/java/org/sonar/php/checks/security/LDAPAuthenticatedConnectionCheck.java @@ -20,6 +20,7 @@ package org.sonar.php.checks.security; import com.google.common.collect.ImmutableSet; +import java.util.Optional; import org.sonar.check.Rule; import org.sonar.php.checks.utils.CheckUtils; import org.sonar.php.checks.utils.FunctionUsageCheck; @@ -27,6 +28,7 @@ import org.sonar.plugins.php.api.symbols.Symbol; import org.sonar.plugins.php.api.tree.CompilationUnitTree; import org.sonar.plugins.php.api.tree.Tree; +import org.sonar.plugins.php.api.tree.declaration.CallArgumentTree; import org.sonar.plugins.php.api.tree.expression.ExpressionTree; import org.sonar.plugins.php.api.tree.expression.FunctionCallTree; @@ -34,8 +36,6 @@ public class LDAPAuthenticatedConnectionCheck extends FunctionUsageCheck { private static final String MESSAGE = "Provide username and password to authenticate the connection."; - private static final int USERNAME_ARG_INDEX = 1; - private static final int PASSWORD_ARG_INDEX = 2; private AssignmentExpressionVisitor assignmentExpressionVisitor; @Override @@ -52,15 +52,16 @@ public void visitCompilationUnit(CompilationUnitTree tree) { @Override protected void createIssue(FunctionCallTree tree) { - if (argumentIsNullOrEmptyString(tree, USERNAME_ARG_INDEX) || argumentIsNullOrEmptyString(tree, PASSWORD_ARG_INDEX)) { + if (argumentIsNullOrEmptyString(tree, "bind_rdn", 1) || argumentIsNullOrEmptyString(tree, "bind_password", 2)) { context().newIssue(this, tree, MESSAGE); } } - private boolean argumentIsNullOrEmptyString(FunctionCallTree tree, int argumentIndex) { - if (tree.arguments().size() > argumentIndex) { - ExpressionTree valueArgument = getAssignedValue(tree.arguments().get(argumentIndex)); - return CheckUtils.isNullOrEmptyString(valueArgument); + private boolean argumentIsNullOrEmptyString(FunctionCallTree tree, String argumentName, int argumentIndex) { + Optional argument = CheckUtils.argument(tree, argumentName, argumentIndex); + if (argument.isPresent()) { + ExpressionTree argumentValue = getAssignedValue(argument.get().value()); + return CheckUtils.isNullOrEmptyString(argumentValue); } return true; } diff --git a/php-checks/src/main/java/org/sonar/php/checks/security/RobustCipherAlgorithmCheck.java b/php-checks/src/main/java/org/sonar/php/checks/security/RobustCipherAlgorithmCheck.java index f1c8df8d58..b4d246ad31 100644 --- a/php-checks/src/main/java/org/sonar/php/checks/security/RobustCipherAlgorithmCheck.java +++ b/php-checks/src/main/java/org/sonar/php/checks/security/RobustCipherAlgorithmCheck.java @@ -31,7 +31,7 @@ public class RobustCipherAlgorithmCheck extends FunctionArgumentCheck { @Override public void visitFunctionCall(FunctionCallTree tree) { - checkArgument(tree, "mcrypt_encrypt", new ArgumentVerifier(0, ImmutableSet.of( + checkArgument(tree, "mcrypt_encrypt", new ArgumentVerifier(0, "cipher", ImmutableSet.of( "mcrypt_des", "mcrypt_des_compat", "mcrypt_tripledes", @@ -40,7 +40,7 @@ public void visitFunctionCall(FunctionCallTree tree) { "mcrypt_rc2", "mcrypt_rc4"))); - checkArgument(tree, "openssl_encrypt", new ArgumentVerifier(1, ImmutableSet.of( + checkArgument(tree, "openssl_encrypt", new ArgumentVerifier(1, "method", ImmutableSet.of( "bf-ecb", "des-ede3", "des-ofb", diff --git a/php-checks/src/main/java/org/sonar/php/checks/utils/FunctionArgumentCheck.java b/php-checks/src/main/java/org/sonar/php/checks/utils/FunctionArgumentCheck.java index 5a12db5ee2..922b9853fd 100644 --- a/php-checks/src/main/java/org/sonar/php/checks/utils/FunctionArgumentCheck.java +++ b/php-checks/src/main/java/org/sonar/php/checks/utils/FunctionArgumentCheck.java @@ -210,11 +210,21 @@ public ArgumentVerifier(int position, String value, boolean raiseIssueOnMatch) { this.raiseIssueOnMatch = raiseIssueOnMatch; } + public ArgumentVerifier(int position, String name, String value, boolean raiseIssueOnMatch) { + this(position, name, ImmutableSet.of(value)); + this.raiseIssueOnMatch = raiseIssueOnMatch; + } + public ArgumentVerifier(int position, Set values, boolean raiseIssueOnMatch) { super(position, values); this.raiseIssueOnMatch = raiseIssueOnMatch; } + public ArgumentVerifier(int position, String name, Set values, boolean raiseIssueOnMatch) { + super(position, name, values); + this.raiseIssueOnMatch = raiseIssueOnMatch; + } + @VisibleForTesting boolean isRaiseIssueOnMatch() { return raiseIssueOnMatch; diff --git a/php-checks/src/test/resources/checks/EmptyDatabasePasswordCheck.php b/php-checks/src/test/resources/checks/EmptyDatabasePasswordCheck.php index 4150f2ac30..511fae3e1c 100644 --- a/php-checks/src/test/resources/checks/EmptyDatabasePasswordCheck.php +++ b/php-checks/src/test/resources/checks/EmptyDatabasePasswordCheck.php @@ -22,12 +22,16 @@ function mysql() { $conn = new mysqli($servername, $username, $secretPassword . 'somethingElse'); $conn = new mysqli($servername, $username, $empty); // Noncompliant // ^^^^^^ + $conn = new mysqli($servername, username: ''); + $conn = new mysqli($servername, passwd: ''); // Noncompliant + $conn = new mysqli($servername, passwd: $secretPassword); $conn = new mysqli($servername, $username, $maybeEmpty); $conn = new MyClass($servername, $username, ''); $conn = mysqli_connect($servername, $username); $conn = mysqli_connect($servername, $username, ''); // Noncompliant $conn = mysqli_connect($servername, $username, $pwd); + $conn = mysqli_connect($servername, passwd: ''); // Noncompliant } // PDO @@ -37,6 +41,8 @@ function pdo() { $conn = new PDO("mysql:host=$servername;dbname=myDB", $username, ''); // Noncompliant $conn = new PDO("mysql:host=$servername;dbname=myDB", $username, $pwd); $conn = new PDO("mysql:host=$servername;dbname=myDB", $username, 'secret'); + $conn = new PDO("mysql:host=$servername;dbname=myDB", passwd: '', username: $username); // Noncompliant + $conn = new PDO("mysql:host=$servername;dbname=myDB", passwd: 'secret', username: $username); } // Oracle @@ -46,6 +52,8 @@ function oracle() { $conn = oci_connect($username, '', $servername); // Noncompliant $conn = oci_connect($username, $pwd, $servername); $conn = oci_connect($username, 'secret', $servername); + $conn = oci_connect(password:'', username: $username); // Noncompliant + $conn = oci_connect(password:'secret', username: $username); } // MS SQL Server @@ -59,6 +67,8 @@ function sqlServer() { $conn = sqlsrv_connect($sqlsrvName, array("Database"=>"myDB", "UID"=>$username, "PWD"=>'secret')); $conn = sqlsrv_connect($sqlsrvName, ["Database"=>"myDB", "UID"=>$username, "PWD"=>'']); // Noncompliant $conn = sqlsrv_connect($sqlsrvName, ["Database"=>"myDB", "UID"=>$username, "PWD"=>'secret']); + $conn = sqlsrv_connect(connectionInfo: ["Database"=>"myDB", "UID"=>$username, "PWD"=>''], serverName:$sqlsrvName); // Noncompliant + $conn = sqlsrv_connect(connectionInfo: ["Database"=>"myDB", "UID"=>$username, "PWD"=>'secret'], serverName:$sqlsrvName); $sqlsrvConnInfo1 = array("Database"=>"myDB", "UID"=>$username, "PWD"=>$password); $conn = sqlsrv_connect($sqlsrvName, $sqlsrvConnInfo1); @@ -89,6 +99,8 @@ function postgresql() { $conn = pg_connect("host=localhost port=5432 dbname=test user=" . $username . " password=" . 'secret'); $conn = pg_connect("host=localhost port=5432 dbname=test user=" . $username . " password="); // Noncompliant $conn = pg_connect("host=localhost port=5432 dbname=test user=" . $username . " password='' port=" . $port); // Noncompliant + $conn = pg_connect(connect_type: 1, connection_string: "host=localhost port=5432 dbname=test user=john password="); // Noncompliant + $conn = pg_connect(connection_type: "host=localhost port=5432 dbname=test user=john password="); $str1 = "host=localhost port=5432 dbname=test user=john password=secret"; $conn = pg_connect($str1); diff --git a/php-checks/src/test/resources/checks/EncryptionModeAndPaddingCheck.php b/php-checks/src/test/resources/checks/EncryptionModeAndPaddingCheck.php index 405034f218..19a1b526a9 100644 --- a/php-checks/src/test/resources/checks/EncryptionModeAndPaddingCheck.php +++ b/php-checks/src/test/resources/checks/EncryptionModeAndPaddingCheck.php @@ -8,19 +8,24 @@ // by default OPENSSL_PKCS1_PADDING is used openssl_public_encrypt($data, $crypted, $key); // Noncompliant //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + openssl_public_encrypt($data, $crypted, padding:$key, key: OPENSSL_SSLV23_PADDING); + openssl_public_encrypt($data, $crypted, padding:OPENSSL_SSLV23_PADDING, key:$key); // Noncompliant - openssl_encrypt($plaintext, "BF-ECB", $key, $options=OPENSSL_RAW_DATA, $iv); // Noncompliant {{Use secure mode and padding scheme.}} - openssl_encrypt($plaintext, "RC2-ECB", $key, $options=OPENSSL_RAW_DATA, $iv); // Noncompliant - openssl_encrypt($plaintext, "bf-ecb", $key, $options=OPENSSL_RAW_DATA, $iv); // Noncompliant - openssl_encrypt($plaintext, "des-ecb", $key, $options=OPENSSL_RAW_DATA, $iv); // Noncompliant - openssl_encrypt($plaintext, "rc2-ecb", $key, $options=OPENSSL_RAW_DATA, $iv); // Noncompliant - openssl_encrypt($plaintext, "aes-256-gcm", $key, $options=OPENSSL_RAW_DATA, $iv); // Compliant + openssl_encrypt($plaintext, "BF-ECB", $key, OPENSSL_RAW_DATA, $iv); // Noncompliant {{Use secure mode and padding scheme.}} + openssl_encrypt($plaintext, "RC2-ECB", $key, OPENSSL_RAW_DATA, $iv); // Noncompliant + openssl_encrypt($plaintext, "bf-ecb", $key, OPENSSL_RAW_DATA, $iv); // Noncompliant + openssl_encrypt($plaintext, "des-ecb", $key, OPENSSL_RAW_DATA, $iv); // Noncompliant + openssl_encrypt($plaintext, "rc2-ecb", $key, OPENSSL_RAW_DATA, $iv); // Noncompliant + openssl_encrypt($plaintext, "aes-256-gcm", $key, OPENSSL_RAW_DATA, $iv); // Compliant + openssl_encrypt($plaintext, key:"rc2-ecb", method:"aes-256-gcm"); // Compliant + openssl_encrypt($plaintext, key:"rc2-ecb", method:"rc2-ecb"); // Noncompliant $mode = "ecb"; mcrypt_encrypt(MCRYPT_DES, $key, $plaintext, "ecb"); // Noncompliant {{Use secure mode and padding scheme.}} mcrypt_encrypt(MCRYPT_DES_COMPAT, $key, $plaintext, $mode); // Noncompliant mcrypt_encrypt(MCRYPT_RC4, $key, $plaintext, "ecb"); // Noncompliant mcrypt_encrypt(MCRYPT_RC4, $key, $plaintext, "cbc"); // Compliant + // mcrypt_encrypt was removed in PHP 7.2, so there's no need to test PHP named arguments on it foo($data, $crypted, $key, OPENSSL_NO_PADDING); openssl_public_encrypt($data, $crypted, $key, getPadding()); diff --git a/php-checks/src/test/resources/checks/HashFunctionCheck.php b/php-checks/src/test/resources/checks/HashFunctionCheck.php index 4b1c4d9752..439fac2b6e 100644 --- a/php-checks/src/test/resources/checks/HashFunctionCheck.php +++ b/php-checks/src/test/resources/checks/HashFunctionCheck.php @@ -16,6 +16,10 @@ $cryptoSalt = openssl_random_pseudo_bytes(16); $hash = hash_pbkdf2("sha256", $password, $cryptoSalt, $iterations, 20); +$hash = hash_pbkdf2("sha256", $password, iterations:'', salt:$cryptoSalt); +$hash = hash_pbkdf2("sha256", $password, iterations:$iterations, salt:$cryptoSalt); +$hash = hash_pbkdf2("sha256", $password, iterations:$iterations, salt:''); // Noncompliant +$hash = hash_pbkdf2("sha256", $password); $salt3 = $arr['email']; $hash = hash_pbkdf2("sha256", $password, $salt3, $iterations, 20); @@ -35,6 +39,9 @@ $hash = crypt($password, $cryptoSalt); +$hash = crypt(salt:$cryptoSalt, str:''); +$hash = crypt(salt:'', str:$cryptoSalt); // Noncompliant + $options = [ 'cost' => 11, 'salt' => mcrypt_create_iv(22, MCRYPT_DEV_URANDOM), // Noncompliant {{Use the salt that is generated by default.}} diff --git a/php-checks/src/test/resources/checks/NoPaddingRsaCheck.php b/php-checks/src/test/resources/checks/NoPaddingRsaCheck.php index a89b4fc9f9..5ad1381ee7 100644 --- a/php-checks/src/test/resources/checks/NoPaddingRsaCheck.php +++ b/php-checks/src/test/resources/checks/NoPaddingRsaCheck.php @@ -7,6 +7,8 @@ function f() { openssl_public_encrypt($data, $crypted, $key, OPENSSL_PKCS1_PADDING); // Noncompliant openssl_public_encrypt($data, $crypted, $key, OPENSSL_SSLV23_PADDING); // Noncompliant openssl_public_encrypt($data, $crypted, $key, OPENSSL_PKCS1_OAEP_PADDING); + openssl_public_encrypt($data, $crypted, padding:OPENSSL_PKCS1_OAEP_PADDING, key:$key); + openssl_public_encrypt($data, $crypted, padding:OPENSSL_NO_PADDING, key:$key); // Noncompliant // by default OPENSSL_PKCS1_PADDING is used openssl_public_encrypt($data, $crypted, $key); // Noncompliant diff --git a/php-checks/src/test/resources/checks/SSLCertificatesVerificationDisabledCheck.php b/php-checks/src/test/resources/checks/SSLCertificatesVerificationDisabledCheck.php index 58bc65eeb1..78c6322d53 100644 --- a/php-checks/src/test/resources/checks/SSLCertificatesVerificationDisabledCheck.php +++ b/php-checks/src/test/resources/checks/SSLCertificatesVerificationDisabledCheck.php @@ -18,6 +18,8 @@ CURL_setopt($curl, CURLOPT_SSL_VERIFYPEER, $verify_peer_off); // Noncompliant curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, '0'); // Noncompliant curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0); // Noncompliant +curl_setopt($curl, value:0, option:CURLOPT_SSL_VERIFYPEER); // Noncompliant +curl_setopt($curl, value:1, option:CURLOPT_SSL_VERIFYPEER); function isVerifyPeer() { return false; } diff --git a/php-checks/src/test/resources/checks/SSLHostVerificationDisabledCheck.php b/php-checks/src/test/resources/checks/SSLHostVerificationDisabledCheck.php index 444e8a5d5c..0edfb5129d 100644 --- a/php-checks/src/test/resources/checks/SSLHostVerificationDisabledCheck.php +++ b/php-checks/src/test/resources/checks/SSLHostVerificationDisabledCheck.php @@ -13,6 +13,8 @@ curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, $verify_host_off); // Noncompliant {{Enable server hostname verification on this SSL/TLS connection.}} curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, '0'); // Noncompliant curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 0); // Noncompliant +curl_setopt($curl, value:0, option:CURLOPT_SSL_VERIFYHOST); // Noncompliant +curl_setopt($curl, value:1, option:CURLOPT_SSL_VERIFYHOST); curl_setopt($curl, CURLOPT_OTHER_KEY); diff --git a/php-checks/src/test/resources/checks/SessionCookiePersistence.php b/php-checks/src/test/resources/checks/SessionCookiePersistence.php index b0ce83ec2a..dd46f0de4c 100644 --- a/php-checks/src/test/resources/checks/SessionCookiePersistence.php +++ b/php-checks/src/test/resources/checks/SessionCookiePersistence.php @@ -1,9 +1,11 @@ session_set_cookie_params(42); unrelated_function(42); diff --git a/php-checks/src/test/resources/checks/WeakSSLProtocolCheck.php b/php-checks/src/test/resources/checks/WeakSSLProtocolCheck.php index 64abaf9c90..569614ed6a 100644 --- a/php-checks/src/test/resources/checks/WeakSSLProtocolCheck.php +++ b/php-checks/src/test/resources/checks/WeakSSLProtocolCheck.php @@ -136,8 +136,14 @@ STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT // Noncompliant ], ]); +$ctx = stream_context_create( + params:['ssl' => ['crypto_method' => STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT]], + options:['ssl' => ['crypto_method' => STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT]] // Noncompliant +); stream_socket_enable_crypto($fp, true, STREAM_CRYPTO_METHOD_TLSv1_2_SERVER | STREAM_CRYPTO_METHOD_TLSv1_1_SERVER); // Noncompliant +stream_socket_enable_crypto($fp, crypto_type:STREAM_CRYPTO_METHOD_TLSv1_1_SERVER, enable:true); // Noncompliant +stream_socket_enable_crypto($fp, crypto_type:STREAM_CRYPTO_METHOD_TLSv1_2_SERVER, enable:true); // Curl @@ -164,3 +170,8 @@ curl_setopt($ch, CURLOPT_OTHER_KEY, CURL_SSLVERSION_SSLv3); curl_setopt($ch, foo(), CURL_SSLVERSION_SSLv3); + +curl_setopt($ch, value:CURL_SSLVERSION_TLSv1_2, option:CURLOPT_SSLVERSION); +curl_setopt($ch, value:CURL_SSLVERSION_TLSv1_1, option:CURLOPT_SSLVERSION); // Noncompliant +curl_setopt($ch, value:CURL_SSLVERSION_TLSv1_1); +curl_setopt($ch, option:CURLOPT_SSLVERSION); diff --git a/php-checks/src/test/resources/checks/security/LDAPAuthenticatedConnectionCheck.php b/php-checks/src/test/resources/checks/security/LDAPAuthenticatedConnectionCheck.php index 3f500d3183..a88bd3fc0e 100644 --- a/php-checks/src/test/resources/checks/security/LDAPAuthenticatedConnectionCheck.php +++ b/php-checks/src/test/resources/checks/security/LDAPAuthenticatedConnectionCheck.php @@ -29,6 +29,13 @@ ldap_bind($ldapconn, "username", "password"); ldap_bind($ldapconn, $username, $password); // unknown variables +ldap_bind(link_identifier:$ldapconn, bind_rdn:"username", bind_password:"password"); +ldap_bind(link_identifier:"", bind_rdn:"username", bind_password:"password"); +ldap_bind(bind_password:"password", bind_rdn:"username"); +ldap_bind(bind_password:"", bind_rdn:"username", link_identifier:$ldapconn); // Noncompliant +ldap_bind(link_identifier:$ldapconn, bind_rdn:"username"); // Noncompliant +ldap_bind(link_identifier:$ldapconn, bind_password:"password"); // Noncompliant + function foobar($cond) { $g = ""; $h = ""; diff --git a/php-checks/src/test/resources/checks/security/RobustCipherAlgorithmCheck.php b/php-checks/src/test/resources/checks/security/RobustCipherAlgorithmCheck.php index a25a3507b9..9604ea3f7d 100644 --- a/php-checks/src/test/resources/checks/security/RobustCipherAlgorithmCheck.php +++ b/php-checks/src/test/resources/checks/security/RobustCipherAlgorithmCheck.php @@ -1,5 +1,6 @@