Deeps-2005/java-ssl-scanner
0
1import com.github.javaparser.*;2import com.github.javaparser.ast.CompilationUnit;3import com.github.javaparser.ast.body.*;4import com.github.javaparser.ast.expr.*; // This import already covers ArrayCreationExpr, ArrayAccessExpr, ArrayInitializerExpr5import com.github.javaparser.ast.stmt.*;6import com.github.javaparser.ast.visitor.ModifierVisitor;7import com.github.javaparser.ast.type.ClassOrInterfaceType;8import com.github.javaparser.ast.body.MethodDeclaration;9import com.github.javaparser.ast.type.Type;10// REMOVED these incorrect/redundant imports:11// import com.github.javaparser.ast.ArrayCreationLevel;12// import com.github.javaparser.ast.ArrayCreationExpr;13// import com.github.javaparser.ast.ArrayAccessExpr;14// import com.github.javaparser.ast.ArrayInitializerExpr;15 16 17import java.io.File;18import java.io.FileInputStream;19import java.util.Arrays;20import java.util.List;21import java.util.Set;22import java.util.HashSet;23 24 25public class Analyzer {26 27 // SSL/JSSE related constants28 private static final List<String> INSECURE_PROTOCOLS = Arrays.asList("sslv2", "sslv3", "tlsv1", "tlsv1.0", "tlsv1.1");29 private static final List<String> WEAK_CIPHER_KEYWORDS = Arrays.asList("null", "anon", "export", "rc4", "des", "md5");30 private static final List<String> NON_PFS_CIPHERS = Arrays.asList("_RSA_","_STATIC_","_DH_","_ECDH_");31 32 // NEW: Cryptography related constants33 private static final List<String> WEAK_HASHING_ALGORITHMS = Arrays.asList("md5", "sha-1");34 private static final Set<String> XML_FACTORIES = new HashSet<>(Arrays.asList(35 "DocumentBuilderFactory", "SAXParserFactory", "XMLInputFactory"36 ));37 private static final String HARDCODED_KEY_PATTERN = ".*(key|secret|password|salt|token|cipher|auth).*";38 39 40 public static void main(String[] args) throws Exception {41 if (args.length == 0) {42 System.out.println("Usage: java Analyzer <JavaFile>");43 return;44 }45 46 File file = new File(args[0]);47 if (!file.exists()) {48 System.err.println("Error: File not found - " + args[0]);49 return;50 }51 if (!file.isFile()) {52 System.err.println("Error: Not a file - " + args[0]);53 return;54 }55 56 CompilationUnit cu = StaticJavaParser.parse(new FileInputStream(file));57 58 cu.accept(new ModifierVisitor<Void>() {59 60 @Override61 public MethodCallExpr visit(MethodCallExpr mce, Void arg) {62 super.visit(mce, arg); // Call super to ensure full traversal63 64 int line = mce.getBegin().map(p -> p.line).orElse(-1);65 66 // NEW: Certificate Pinning Check67 if (mce.getNameAsString().equals("checkServerTrusted") && 68 mce.getScope().isPresent() &&69 (mce.getScope().get().toString().contains("X509TrustManager") ||70 mce.getScope().get().toString().contains("TrustManager"))) {71 72 boolean hasPinning = mce.getParentNode()73 .filter(parent -> parent instanceof MethodDeclaration)74 .map(parent -> ((MethodDeclaration) parent).getBody())75 .flatMap(body -> body.map(b -> b.toString().contains("PublicKey") && 76 b.toString().contains("X509Certificate")))77 .orElse(false);78 79 if (!hasPinning) {80 System.out.println("[Line " + line + "] ISSUE: Missing certificate pinning implementation - Vulnerable to MITM attacks. Implement certificate public key pinning. Severity: CRITICAL");81 }82 }83 84 // NEW: Forward Secrecy Check85 if (mce.getNameAsString().equals("setEnabledCipherSuites") &&86 mce.getScope().isPresent() &&87 (mce.getScope().get().toString().contains("SSLSocket") || 88 mce.getScope().get().toString().contains("SSLEngine"))) {89 90 mce.getArguments().forEach(argExpr -> {91 if (argExpr.isArrayInitializerExpr()) {92 argExpr.asArrayInitializerExpr().getValues().forEach(cipherExpr -> {93 if (cipherExpr.isStringLiteralExpr()) {94 String cipher = cipherExpr.asStringLiteralExpr().getValue();95 if (NON_PFS_CIPHERS.stream().anyMatch(cipher::contains)) {96 System.out.println("[Line " + line + "] ISSUE: Non-PFS cipher suite enabled: " + cipher + " - Prefer ECDHE cipher suites for forward secrecy. Severity: HIGH");97 }98 }99 });100 }101 });102 }103 104 // NEW: HSTS Header Check105 if ((mce.getNameAsString().equals("setHeader") || 106 mce.getNameAsString().equals("addHeader")) &&107 mce.getArguments().size() >= 2 &&108 mce.getArgument(0).isStringLiteralExpr()) {109 110 String headerName = mce.getArgument(0).asStringLiteralExpr().getValue();111 if (headerName.equalsIgnoreCase("Strict-Transport-Security")) {112 if (mce.getArgument(1).isStringLiteralExpr()) {113 String headerValue = mce.getArgument(1).asStringLiteralExpr().getValue();114 if (!headerValue.toLowerCase().contains("max-age") ||115 headerValue.toLowerCase().contains("max-age=0")) {116 System.out.println("[Line " + line + "] ISSUE: Weak HSTS header configuration: " + headerValue + " - Should include 'max-age' with substantial duration. Severity: HIGH");117 }118 }119 }120 }121 122 // NEW: CRL/OCSP Validation Check123 if (mce.getNameAsString().equals("setRevocationEnabled") &&124 mce.getScope().isPresent() &&125 mce.getScope().get().toString().contains("PKIXBuilderParameters")) {126 127 if (mce.getArguments().size() == 1 &&128 mce.getArgument(0).isBooleanLiteralExpr() &&129 !mce.getArgument(0).asBooleanLiteralExpr().getValue()) {130 System.out.println("[Line " + line + "] ISSUE: Certificate revocation checking explicitly disabled - Enables revoked certificate acceptance. Severity: CRITICAL");131 }132 }133 134 // NEW: Server Name Indication (SNI) Check135 if (mce.getNameAsString().equals("setServerNames") &&136 mce.getScope().isPresent() &&137 mce.getScope().get().toString().contains("SSLParameters")) {138 139 if (mce.getArguments().size() == 1 &&140 mce.getArgument(0).isNullLiteralExpr()) {141 System.out.println("[Line " + line + "] ISSUE: SNI explicitly disabled - May cause TLS handshake failures. Severity: MEDIUM");142 }143 }144 145 146 // Check for System.setProperty calls (debug logging, renegotiation)147 if (mce.getNameAsString().equals("setProperty") && mce.getArguments().size() == 2) {148 Expression arg0 = mce.getArgument(0);149 if (arg0.isStringLiteralExpr()) {150 String propName = arg0.asStringLiteralExpr().getValue();151 if (propName.contains("javax.net.debug")) {152 System.out.println("[Line " + line + "] ISSUE: Debug logging enabled (javax.net.debug) - Exposes sensitive SSL/TLS handshaking details. Severity: HIGH");153 }154 if (propName.contains("com.ibm.jsse2.renegotiate")) {155 System.out.println("[Line " + line + "] ISSUE: TLS renegotiation potentially enabled - Can be abused for DoS attacks. Severity: HIGH");156 }157 }158 }159 160 // Check for HostnameVerifier related issues161 if (mce.getNameAsString().equals("setDefaultHostnameVerifier") && mce.getArguments().size() == 1) {162 Expression arg0 = mce.getArgument(0);163 if (arg0.isLambdaExpr()) {164 LambdaExpr lambda = arg0.asLambdaExpr();165 if (lambda.getBody().isExpressionStmt() &&166 lambda.getBody().asExpressionStmt().getExpression().isBooleanLiteralExpr() &&167 lambda.getBody().asExpressionStmt().getExpression().asBooleanLiteralExpr().getValue()) {168 System.out.println("[Line " + line + "] ISSUE: Insecure HostnameVerifier (lambda always returns true) - Bypasses hostname validation, vulnerable to MITM. Severity: CRITICAL");169 } else if (lambda.getBody().isBlockStmt()) {170 BlockStmt block = lambda.getBody().asBlockStmt();171 for (Statement stmt : block.getStatements()) {172 if (stmt instanceof ReturnStmt) {173 ReturnStmt returnStmt = (ReturnStmt) stmt;174 if (returnStmt.getExpression().isPresent() &&175 returnStmt.getExpression().get().isBooleanLiteralExpr() &&176 returnStmt.getExpression().get().asBooleanLiteralExpr().getValue()) {177 System.out.println("[Line " + line + "] ISSUE: Insecure HostnameVerifier (lambda block always returns true) - Bypasses hostname validation, vulnerable to MITM. Severity: CRITICAL");178 break;179 }180 }181 }182 }183 }184 }185 186 // Check for hardcoded password passed to keystore load()187 if (mce.getNameAsString().equals("load") &&188 mce.getScope().isPresent() &&189 mce.getScope().get().toString().contains("KeyStore") &&190 mce.getArguments().size() == 2 &&191 (mce.getArgument(1).isCharLiteralExpr() || mce.getArgument(1).isStringLiteralExpr())) {192 System.out.println("[Line " + line + "] ISSUE: Hardcoded literal password passed to KeyStore.load() - Sensitive info in source code. Severity: HIGH");193 }194 195 // Check for outdated/weak SSL/TLS protocols in SSLContext.getInstance()196 if (mce.getNameAsString().equals("getInstance") &&197 mce.getScope().isPresent() &&198 mce.getScope().get().toString().contains("SSLContext") &&199 mce.getArguments().size() >= 1) {200 Expression arg0 = mce.getArgument(0);201 if (arg0.isStringLiteralExpr()) {202 String protocol = arg0.asStringLiteralExpr().getValue().toLowerCase();203 if (INSECURE_PROTOCOLS.contains(protocol)) {204 System.out.println("[Line " + line + "] ISSUE: Insecure SSL/TLS protocol requested: " + protocol.toUpperCase() + " - Known vulnerabilities exist. Severity: CRITICAL");205 }206 }207 }208 209 // Check for enabling weak/outdated PROTOCOLS via setEnabledProtocols()210 if (mce.getNameAsString().equals("setEnabledProtocols") &&211 mce.getScope().isPresent() &&212 (mce.getScope().get().toString().contains("SSLSocket") || mce.getScope().get().toString().contains("SSLEngine"))) {213 214 mce.getArguments().forEach(argExpr -> {215 if (argExpr.isArrayInitializerExpr()) {216 argExpr.asArrayInitializerExpr().getValues().forEach(protoExpr -> {217 if (protoExpr.isStringLiteralExpr()) {218 String protocol = protoExpr.asStringLiteralExpr().getValue().toLowerCase();219 if (INSECURE_PROTOCOLS.contains(protocol)) {220 System.out.println("[Line " + line + "] ISSUE: Insecure SSL/TLS protocol enabled via setEnabledProtocols(): " + protocol.toUpperCase() + " - Known vulnerabilities exist. Severity: CRITICAL");221 }222 }223 });224 } else if (argExpr.isStringLiteralExpr()) {225 String protocol = argExpr.asStringLiteralExpr().getValue().toLowerCase();226 if (INSECURE_PROTOCOLS.contains(protocol)) {227 System.out.println("[Line " + line + "] ISSUE: Insecure SSL/TLS protocol enabled via setEnabledProtocols(): " + protocol.toUpperCase() + " - Known vulnerabilities exist. Severity: CRITICAL");228 }229 }230 });231 }232 233 // Check for enabling weak CIPHER SUITES via setEnabledCipherSuites()234 if (mce.getNameAsString().equals("setEnabledCipherSuites") &&235 mce.getScope().isPresent() &&236 (mce.getScope().get().toString().contains("SSLSocket") || mce.getScope().get().toString().contains("SSLEngine"))) {237 238 mce.getArguments().forEach(argExpr -> {239 if (argExpr.isArrayInitializerExpr()) {240 argExpr.asArrayInitializerExpr().getValues().forEach(cipherExpr -> {241 if (cipherExpr.isStringLiteralExpr()) {242 String cipherSuite = cipherExpr.asStringLiteralExpr().getValue().toLowerCase();243 if (WEAK_CIPHER_KEYWORDS.stream().anyMatch(cipherSuite::contains)) {244 System.out.println("[Line " + line + "] ISSUE: Weak cipher suite enabled via setEnabledCipherSuites(): " + cipherSuite.toUpperCase() + " - Use stronger cryptographic algorithms. Severity: CRITICAL");245 }246 }247 });248 } else if (argExpr.isStringLiteralExpr()) {249 String cipherSuite = argExpr.asStringLiteralExpr().getValue().toLowerCase();250 if (WEAK_CIPHER_KEYWORDS.stream().anyMatch(cipherSuite::contains)) {251 System.out.println("[Line " + line + "] ISSUE: Weak cipher suite enabled via setEnabledCipherSuites(): " + cipherSuite.toUpperCase() + " - Use stronger cryptographic algorithms. Severity: CRITICAL");252 }253 }254 });255 }256 257 // Check for potential HttpURLConnection usage for HTTPS (insecure default)258 if (mce.getNameAsString().equals("URL") &&259 mce.getArguments().size() == 1) {260 Expression arg0 = mce.getArgument(0);261 if (arg0.isStringLiteralExpr()) {262 String urlString = arg0.asStringLiteralExpr().getValue();263 if (urlString.startsWith("http://") && !urlString.contains("localhost") && !urlString.contains("127.0.0.1")) { // Exclude localhost264 System.out.println("[Line " + line + "] WARNING: URL constructed with 'http://' scheme: " + urlString + " - Ensure sensitive data is not sent over insecure HTTP. Severity: MEDIUM");265 }266 }267 }268 269 // NEW: Weak Hashing Algorithms (MD5, SHA-1)270 if (mce.getNameAsString().equals("getInstance") &&271 mce.getScope().isPresent() &&272 mce.getScope().get().toString().contains("MessageDigest") &&273 mce.getArguments().size() >= 1) {274 Expression arg0 = mce.getArgument(0);275 if (arg0.isStringLiteralExpr()) {276 String algorithm = arg0.asStringLiteralExpr().getValue().toLowerCase();277 if (WEAK_HASHING_ALGORITHMS.contains(algorithm)) {278 System.out.println("[Line " + line + "] ISSUE: Weak hashing algorithm used: " + algorithm.toUpperCase() + " - Use stronger algorithms like SHA-256 or SHA-512. Severity: HIGH");279 }280 }281 }282 283 // NEW: XML External Entity (XXE) Vulnerability - factory instantiation284 // Flagging instantiation and suggesting secure features285 if (mce.getNameAsString().equals("newInstance") &&286 mce.getScope().isPresent() &&287 XML_FACTORIES.contains(mce.getScope().get().toString())) {288 System.out.println("[Line " + line + "] ISSUE: XML parsing factory created without explicit XXE hardening - Potentially vulnerable to XXE attacks. Ensure external entities and DTDs are disabled. Severity: CRITICAL");289 }290 291 292 return mce;293 }294 295 @Override296 public ObjectCreationExpr visit(ObjectCreationExpr oce, Void arg) {297 super.visit(oce, arg); // Call super to ensure full traversal298 299 int line = oce.getBegin().map(p -> p.line).orElse(-1);300 301 // NEW: FIPS Compliance Check302 if (oce.getType().getNameAsString().equals("Security") &&303 oce.getParentNode().isPresent() &&304 oce.getParentNode().get() instanceof MethodCallExpr) {305 306 MethodCallExpr parentCall = (MethodCallExpr) oce.getParentNode().get();307 if (parentCall.getNameAsString().equals("addProvider") &&308 parentCall.getArguments().size() == 1 &&309 parentCall.getArgument(0).isObjectCreationExpr()) {310 311 ObjectCreationExpr provider = parentCall.getArgument(0).asObjectCreationExpr();312 if (!provider.getType().getNameAsString().toLowerCase().contains("fips")) {313 System.out.println("[Line " + line + "] WARNING: Non-FIPS compliant cryptographic provider - Consider using FIPS validated modules for compliance. Severity: MEDIUM");314 }315 }316 }317 318 // NEW: Certificate Transparency Check319 if (oce.getType().getNameAsString().equals("CTVerifier")) {320 boolean hasValidation = oce.getParentNode()321 .filter(parent -> parent instanceof VariableDeclarator)322 .map(parent -> (VariableDeclarator) parent)323 .flatMap(varDecl -> varDecl.getParentNode()) // returns Optional<Node>324 .filter(grandparent -> grandparent instanceof FieldDeclaration)325 .map(grandparent -> (FieldDeclaration) grandparent)326 .isPresent();327 328 if (!hasValidation) {329 System.out.println("[Line " + line + "] ISSUE: Certificate Transparency verifier created but not used - Implement CT validation for issued certificates. Severity: HIGH");330 }331 }332 333 // Check for Anonymous X509TrustManager/TrustManager334 if (oce.getAnonymousClassBody().isPresent() &&335 (oce.getType().getNameAsString().equals("X509TrustManager") ||336 oce.getType().getNameAsString().equals("TrustManager"))) {337 338 System.out.println("[Line " + line + "] ISSUE: Anonymous X509TrustManager/TrustManager detected - Verify implementation for proper certificate validation. Severity: CRITICAL");339 340 oce.getAnonymousClassBody().get().forEach(bodyDeclaration -> {341 if (bodyDeclaration instanceof MethodDeclaration) {342 MethodDeclaration md = (MethodDeclaration) bodyDeclaration;343 String methodName = md.getNameAsString();344 345 if (("checkClientTrusted".equals(methodName) || "checkServerTrusted".equals(methodName)) && md.getBody().isPresent()) {346 BlockStmt methodBody = md.getBody().get();347 for (Statement stmt : methodBody.getStatements()) {348 if (stmt instanceof ReturnStmt) {349 ReturnStmt returnStmt = (ReturnStmt) stmt;350 if (returnStmt.getExpression().isPresent() &&351 returnStmt.getExpression().get().isBooleanLiteralExpr() &&352 returnStmt.getExpression().get().asBooleanLiteralExpr().getValue()) {353 System.out.println(" [Line " + line + "] - Method '" + methodName + "' unconditionally returns true, implying no validation. Severity: CRITICAL");354 break;355 }356 } else if (stmt instanceof TryStmt) {357 TryStmt ts = (TryStmt) stmt;358 ts.getCatchClauses().forEach(catchClause -> {359 Type caughtType = catchClause.getParameter().getType();360 if (caughtType instanceof ClassOrInterfaceType) {361 String typeName = ((ClassOrInterfaceType) caughtType).getNameAsString();362 if (typeName.equals("Exception") || typeName.equals("Throwable") ||363 typeName.equals("CertificateException") || typeName.equals("NoSuchAlgorithmException")) {364 if (catchClause.getBody().getStatements().isEmpty() ||365 (catchClause.getBody().getStatements().size() == 1 &&366 catchClause.getBody().getStatement(0).isExpressionStmt() &&367 catchClause.getBody().getStatement(0).asExpressionStmt().getExpression().isMethodCallExpr() &&368 catchClause.getBody().getStatement(0).asExpressionStmt().getExpression().asMethodCallExpr().getNameAsString().equals("printStackTrace"))) {369 System.out.println(" [Line " + line + "] - Method '" + methodName + "' catches " + typeName + " and may swallow validation errors. Severity: CRITICAL");370 }371 }372 }373 });374 }375 }376 }377 }378 });379 }380 381 // Check for Unseeded SecureRandom instance382 if (oce.getType().getNameAsString().equals("SecureRandom") &&383 oce.getArguments().isEmpty()) {384 System.out.println("[Line " + line + "] ISSUE: Unseeded SecureRandom instance - May lead to predictable keys or nonce values if not explicitly seeded. Severity: HIGH");385 }386 387 // Check for Anonymous HostnameVerifier388 if (oce.getAnonymousClassBody().isPresent() &&389 oce.getType().getNameAsString().equals("HostnameVerifier")) {390 System.out.println("[Line " + line + "] ISSUE: Anonymous HostnameVerifier detected - Verify implementation for proper hostname validation. Severity: CRITICAL");391 oce.getAnonymousClassBody().get().forEach(bodyDeclaration -> {392 if (bodyDeclaration instanceof MethodDeclaration) {393 MethodDeclaration md = (MethodDeclaration) bodyDeclaration;394 if (md.getNameAsString().equals("verify") && md.getBody().isPresent()) {395 BlockStmt methodBody = md.getBody().get();396 for (Statement stmt : methodBody.getStatements()) {397 if (stmt instanceof ReturnStmt) {398 ReturnStmt returnStmt = (ReturnStmt) stmt;399 if (returnStmt.getExpression().isPresent() &&400 returnStmt.getExpression().get().isBooleanLiteralExpr() &&401 returnStmt.getExpression().get().asBooleanLiteralExpr().getValue()) {402 System.out.println(" [Line " + line + "] - Method 'verify' unconditionally returns true, implying no validation. Severity: CRITICAL");403 break;404 }405 }406 }407 }408 }409 });410 }411 412 // NEW: Hardcoded Cryptographic Keys/Salts413 if (oce.getType().getNameAsString().equals("SecretKeySpec") ||414 oce.getType().getNameAsString().equals("IvParameterSpec")) {415 boolean hasLiteralArgument = false;416 for (Expression argExpr : oce.getArguments()) {417 if (argExpr.isStringLiteralExpr() || (argExpr.isMethodCallExpr() && argExpr.asMethodCallExpr().getNameAsString().equals("getBytes"))) {418 // Check for "hardcoded_key".getBytes() or similar419 if (argExpr.isStringLiteralExpr() && argExpr.asStringLiteralExpr().getValue().toLowerCase().matches(HARDCODED_KEY_PATTERN)) {420 hasLiteralArgument = true;421 break;422 } else if (argExpr.isMethodCallExpr() && argExpr.asMethodCallExpr().getScope().isPresent() && argExpr.asMethodCallExpr().getScope().get().isStringLiteralExpr() && argExpr.asMethodCallExpr().getScope().get().asStringLiteralExpr().getValue().toLowerCase().matches(HARDCODED_KEY_PATTERN)) {423 hasLiteralArgument = true;424 break;425 }426 } else if (argExpr.isArrayCreationExpr()) {427 // Check for new byte[]{...} with suspicious values428 ArrayCreationExpr ace = argExpr.asArrayCreationExpr();429 if (ace.getInitializer().isPresent()) {430 ArrayInitializerExpr init = ace.getInitializer().get();431 for (Expression valExpr : init.getValues()) {432 if (valExpr.isIntegerLiteralExpr() || valExpr.isCharLiteralExpr() || valExpr.isStringLiteralExpr()) {433 hasLiteralArgument = true; // Flag any literal here, needs manual review434 break;435 }436 }437 }438 }439 }440 if (hasLiteralArgument) {441 System.out.println("[Line " + line + "] ISSUE: Potentially hardcoded cryptographic key/salt/IV in " + oce.getType().getNameAsString() + " initialization. Store sensitive keys securely (e.g., environment variables, KeyVault). Severity: CRITICAL");442 }443 }444 445 // NEW: Deserialization of Untrusted Data446 if (oce.getType().getNameAsString().equals("ObjectInputStream")) {447 System.out.println("[Line " + line + "] ISSUE: Deserialization of untrusted data via ObjectInputStream - Vulnerable to Remote Code Execution (RCE) if input is malicious. Avoid deserializing untrusted data. Severity: CRITICAL");448 }449 450 return oce;451 }452 453 454 @Override455 public WhileStmt visit(WhileStmt ws, Void arg) {456 super.visit(ws, arg);457 458 int line = ws.getBegin().map(p -> p.line).orElse(-1);459 460 if (ws.getCondition().isBooleanLiteralExpr() &&461 ws.getCondition().asBooleanLiteralExpr().getValue()) {462 System.out.println("[Line " + line + "] ISSUE: Potential infinite loop (while(true)) - Could indicate a DoS vulnerability if related to resource consumption. Severity: HIGH");463 }464 465 return ws;466 }467 468 @Override469 public VariableDeclarator visit(VariableDeclarator vd, Void arg) {470 super.visit(vd, arg);471 472 int line = vd.getBegin().map(p -> p.line).orElse(-1);473 474 // NEW: HTTP/2 Protocol Check475 if (vd.getType().isArrayType() &&476 vd.getType().asArrayType().getComponentType().toString().equals("String") &&477 vd.getInitializer().isPresent() &&478 vd.getInitializer().get() instanceof ArrayInitializerExpr) {479 480 ArrayInitializerExpr init = (ArrayInitializerExpr) vd.getInitializer().get();481 boolean hasHttp2 = init.getValues().stream()482 .filter(Expression::isStringLiteralExpr)483 .map(expr -> expr.asStringLiteralExpr().getValue())484 .anyMatch(val -> val.equalsIgnoreCase("h2"));485 486 if (!hasHttp2 && init.getValues().stream()487 .filter(Expression::isStringLiteralExpr)488 .map(expr -> expr.asStringLiteralExpr().getValue())489 .anyMatch(val -> val.startsWith("http/1"))) {490 System.out.println("[Line " + line + "] WARNING: HTTP/1.x protocol enabled without HTTP/2 - Prefer HTTP/2 for better security and performance. Severity: MEDIUM");491 }492 }493 494 // Weak cipher suites in array declaration495 if (vd.getType().isArrayType() &&496 vd.getType().asArrayType().getComponentType().toString().equals("String") &&497 vd.getInitializer().isPresent() &&498 vd.getInitializer().get() instanceof ArrayInitializerExpr) {499 500 ArrayInitializerExpr init = (ArrayInitializerExpr) vd.getInitializer().get();501 502 for (Expression expr : init.getValues()) {503 if (expr.isStringLiteralExpr()) {504 String value = expr.asStringLiteralExpr().getValue().toLowerCase();505 if (WEAK_CIPHER_KEYWORDS.stream().anyMatch(value::contains)) {506 System.out.println("[Line " + line + "] ISSUE: Weak cipher suite keyword detected in array: '" + value + "' - Use stronger cryptographic algorithms. Severity: CRITICAL");507 break;508 }509 }510 }511 }512 513 // Check for hardcoded password assigned to variable514 if (vd.getInitializer().isPresent() && vd.getInitializer().get().isStringLiteralExpr()) {515 String val = vd.getInitializer().get().asStringLiteralExpr().getValue().toLowerCase();516 if (val.matches(".*(password|pass|secret|key|pwd|123).*") && val.length() > 3) {517 System.out.println("[Line " + line + "] ISSUE: Hardcoded password/sensitive string assigned to variable: '" + val + "' - Store credentials securely (e.g., environment variables, KeyVault). Severity: CRITICAL");518 }519 }520 521 return vd;522 }523 524 @Override525 public TryStmt visit(TryStmt ts, Void arg) {526 super.visit(ts, arg);527 528 int line = ts.getBegin().map(p -> p.line).orElse(-1);529 530 ts.getCatchClauses().forEach(catchClause -> {531 Type caughtType = catchClause.getParameter().getType();532 if (caughtType instanceof ClassOrInterfaceType) {533 String typeName = ((ClassOrInterfaceType) caughtType).getNameAsString();534 if (typeName.equals("Exception") || typeName.equals("Throwable")) {535 if (catchClause.getBody().getStatements().isEmpty() ||536 (catchClause.getBody().getStatements().size() == 1 &&537 catchClause.getBody().getStatement(0).isExpressionStmt() &&538 catchClause.getBody().getStatement(0).asExpressionStmt().getExpression().isMethodCallExpr() &&539 catchClause.getBody().getStatement(0).asExpressionStmt().getExpression().asMethodCallExpr().getNameAsString().equals("printStackTrace"))) {540 System.out.println("[Line " + line + "] WARNING: Overly broad catch for '" + typeName + "' with minimal error handling - May hide critical exceptions. Severity: MEDIUM");541 }542 }543 }544 });545 return ts;546 }547 }, null);548 }549}550 