diff --git a/rules/java/security/use-of-blowfish-java.yml b/rules/java/security/use-of-blowfish-java.yml new file mode 100644 index 00000000..e8852419 --- /dev/null +++ b/rules/java/security/use-of-blowfish-java.yml @@ -0,0 +1,50 @@ +id: use-of-blowfish-java +severity: warning +language: java +message: >- + 'Use of Blowfish was detected. Blowfish uses a 64-bit block size + that makes it vulnerable to birthday attacks, and is therefore considered + non-compliant. Instead, use a strong, secure cipher: + Cipher.getInstance("AES/CBC/PKCS7PADDING"). See + https://owasp.org/www-community/Using_the_Java_Cryptographic_Extensions + for more information.' +note: >- + [CWE-327] Use of a Broken or Risky Cryptographic Algorithm. + [REFERENCES] + - https://owasp.org/Top10/A02_2021-Cryptographic_Failures + - https://googleprojectzero.blogspot.com/2022/10/rc4-is-still-considered-harmful.html + +ast-grep-essentials: true +rule: + kind: method_invocation + all: + - has: + kind: identifier + field: name + regex: ^getInstance$ + nthChild: + position: 2 + reverse: true + - has: + kind: argument_list + field: arguments + nthChild: + position: 1 + reverse: true + has: + nthChild: + position: 1 + ofRule: + not: + kind: line_comment + kind: string_literal + has: + kind: string_fragment + regex: ^Blowfish$ + not: + has: + nthChild: + position: 2 + ofRule: + not: + kind: line_comment diff --git a/rules/java/security/use-of-default-aes-java.yml b/rules/java/security/use-of-default-aes-java.yml new file mode 100644 index 00000000..efc9fb51 --- /dev/null +++ b/rules/java/security/use-of-default-aes-java.yml @@ -0,0 +1,320 @@ +id: use-of-default-aes-java +severity: warning +language: java +message: >- + "Use of AES with no settings detected. By default, java.crypto.Cipher + uses ECB mode. ECB doesn't provide message confidentiality and is not + semantically secure so should not be used. Instead, use a strong, secure + cipher: java.crypto.Cipher.getInstance(\"AES/CBC/PKCS7PADDING\"). See + https://owasp.org/www-community/Using_the_Java_Cryptographic_Extensions + for more information." +note: >- + [CWE-327] Use of a Broken or Risky Cryptographic Algorithm. + [REFERENCES] + - https://owasp.org/Top10/A02_2021-Cryptographic_Failures + - https://googleprojectzero.blogspot.com/2022/10/rc4-is-still-considered-harmful.html + +ast-grep-essentials: true +rule: + any: + - kind: method_invocation + all: + - has: + kind: field_access + nthChild: 1 + regex: ^javax.crypto.Cipher$ + - has: + kind: identifier + nthChild: 2 + regex: ^getInstance$ + - has: + kind: argument_list + nthChild: 3 + has: + pattern: $AES + nthChild: + position: 1 + ofRule: + not: + kind: line_comment + not: + has: + nthChild: + position: 2 + ofRule: + not: + kind: line_comment + inside: + stopBy: end + follows: + stopBy: end + kind: import_declaration + any: + - pattern: import javax.*; + - pattern: import javax; + - kind: import_declaration + has: + stopBy: neighbor + kind: scoped_identifier + has: + stopBy: end + kind: identifier + nthChild: 1 + regex: ^javax$ + - kind: method_invocation + all: + - has: + kind: field_access + nthChild: 1 + regex: ^crypto.Cipher$ + - has: + kind: identifier + nthChild: 2 + regex: ^getInstance$ + - has: + kind: argument_list + has: + pattern: $AES + nthChild: + position: 1 + ofRule: + not: + kind: line_comment + not: + has: + nthChild: + position: 2 + ofRule: + not: + kind: line_comment + inside: + stopBy: end + follows: + stopBy: end + kind: import_declaration + any: + - kind: import_declaration + has: + stopBy: neighbor + kind: scoped_identifier + has: + stopBy: end + kind: identifier + nthChild: 1 + regex: ^javax$ + - pattern: import javax.crypto; + - pattern: import javax.*; + - kind: import_declaration + has: + stopBy: neighbor + kind: scoped_identifier + has: + stopBy: end + kind: identifier + nthChild: 1 + regex: ^javax$ + - kind: method_invocation + all: + - has: + kind: identifier + nthChild: 1 + regex: ^Cipher$ + - has: + kind: identifier + nthChild: 2 + regex: ^getInstance$ + - has: + kind: argument_list + has: + pattern: $AES + nthChild: + position: 1 + ofRule: + not: + kind: line_comment + not: + has: + nthChild: + position: 2 + ofRule: + not: + kind: line_comment + - inside: + stopBy: end + follows: + stopBy: end + kind: import_declaration + any: + - pattern: import javax.crypto.*; + - pattern: import javax.crypto.Cipher; + - kind: import_declaration + has: + stopBy: neighbor + kind: scoped_identifier + has: + stopBy: end + kind: identifier + nthChild: 1 + regex: ^javax.crypto.*$ + - kind: method_invocation + all: + - has: + kind: identifier + nthChild: 1 + pattern: $INST + - has: + kind: identifier + nthChild: 2 + regex: ^getInstance$ + - has: + kind: argument_list + has: + pattern: $AES + nthChild: + position: 1 + ofRule: + not: + kind: line_comment + not: + has: + nthChild: + position: 2 + ofRule: + not: + kind: line_comment + - inside: + stopBy: end + follows: + stopBy: end + any: + - kind: field_declaration + - kind: local_variable_declaration + all: + - has: + kind: scoped_type_identifier + regex: ^javax.crypto.Cipher$ + - has: + kind: variable_declarator + has: + kind: identifier + pattern: $INST + - inside: + stopBy: end + follows: + stopBy: end + kind: import_declaration + any: + - pattern: import javax.crypto.Cipher; + - pattern: import javax; + - kind: method_invocation + all: + - has: + kind: identifier + nthChild: 1 + pattern: $INST + - has: + kind: identifier + nthChild: 2 + regex: ^getInstance$ + - has: + kind: argument_list + has: + pattern: $AES + nthChild: + position: 1 + ofRule: + not: + kind: line_comment + not: + has: + nthChild: + position: 2 + ofRule: + not: + kind: line_comment + - inside: + stopBy: end + follows: + stopBy: end + any: + - kind: field_declaration + - kind: local_variable_declaration + all: + - has: + kind: scoped_type_identifier + regex: ^crypto.Cipher$ + - has: + kind: variable_declarator + has: + kind: identifier + pattern: $INST + - inside: + stopBy: end + follows: + stopBy: end + kind: import_declaration + any: + - pattern: import javax.*; + - pattern: import javax.crypto; + - pattern: import javax.crypto.Cipher; + - kind: method_invocation + all: + - has: + kind: identifier + nthChild: 1 + pattern: $INST + - has: + kind: identifier + nthChild: 2 + regex: ^getInstance$ + - has: + kind: argument_list + has: + pattern: $AES + nthChild: + position: 1 + ofRule: + not: + kind: line_comment + not: + has: + nthChild: + position: 2 + ofRule: + not: + kind: line_comment + - inside: + stopBy: end + follows: + stopBy: end + any: + - kind: field_declaration + - kind: local_variable_declaration + all: + - has: + kind: type_identifier + regex: ^Cipher$ + - has: + kind: variable_declarator + has: + kind: identifier + pattern: $INST + - inside: + stopBy: end + follows: + stopBy: end + kind: import_declaration + any: + - pattern: import javax.crypto.Cipher; + - pattern: import javax.crypto.*; + not: + has: + stopBy: end + kind: ERROR +constraints: + AES: + kind: string_literal + all: + - has: + kind: string_fragment + regex: ^\s*(AES)\s*$ \ No newline at end of file diff --git a/rules/java/security/use-of-sha1-java.yml b/rules/java/security/use-of-sha1-java.yml new file mode 100644 index 00000000..b2268c1c --- /dev/null +++ b/rules/java/security/use-of-sha1-java.yml @@ -0,0 +1,172 @@ +id: use-of-sha1-java +severity: warning +language: java +message: >- + Detected SHA1 hash algorithm which is considered insecure. SHA1 is not + collision resistant and is therefore not suitable as a cryptographic + signature. Instead, use PBKDF2 for password hashing or SHA256 or SHA512 + for other hash function applications. +note: >- + [CWE-328] Use of Weak Hash. + [REFERENCES] + - https://owasp.org/Top10/A02_2021-Cryptographic_Failures + +ast-grep-essentials: true +utils: + java.security.MessageDigest.getInstance("SHA-1"): + kind: method_invocation + all: + - has: + kind: field_access + regex: ^java.security.MessageDigest$ + - has: + kind: identifier + regex: ^getInstance$ + - has: + kind: argument_list + has: + kind: string_literal + nthChild: + position: 1 + ofRule: + not: + kind: line_comment + has: + kind: string_fragment + any: + - regex: ^SHA-1 + - regex: ^SHA1 + + MessageDigest.getInstance("SHA-1"): + kind: method_invocation + all: + - has: + kind: identifier + regex: ^MessageDigest$ + nthChild: 1 + - has: + kind: identifier + regex: ^getInstance$ + nthChild: 2 + - has: + kind: argument_list + has: + kind: string_literal + nthChild: + position: 1 + ofRule: + not: + kind: line_comment + has: + kind: string_fragment + any: + - regex: ^SHA-1 + - regex: ^SHA1 + - inside: + stopBy: end + follows: + stopBy: end + kind: import_declaration + pattern: import java.security.MessageDigest + + MessageDigest.getInstance("SHA-1")_with_Instance: + kind: method_invocation + all: + - has: + kind: identifier + regex: ^MessageDigest$ + nthChild: 1 + - has: + kind: identifier + regex: ^getInstance$ + nthChild: 2 + - has: + kind: argument_list + has: + kind: identifier + pattern: $SHA + nthChild: + position: 1 + ofRule: + not: + kind: line_comment + - inside: + stopBy: end + follows: + stopBy: end + kind: import_declaration + pattern: import java.security.MessageDigest + - inside: + stopBy: end + follows: + stopBy: end + kind: local_variable_declaration + has: + kind: variable_declarator + all: + - has: + kind: identifier + pattern: $SHA + - has: + kind: string_literal + has: + kind: string_fragment + any: + - regex: ^SHA-1 + - regex: ^SHA1 + + java.security.MessageDigest.getInstance("SHA-1")_with_Instance: + kind: method_invocation + all: + - has: + kind: field_access + regex: ^java.security.MessageDigest$ + - has: + kind: identifier + regex: ^getInstance$ + - has: + kind: argument_list + has: + kind: identifier + pattern: $SHA + nthChild: + position: 1 + ofRule: + not: + kind: line_comment + - inside: + stopBy: end + follows: + stopBy: end + kind: local_variable_declaration + has: + kind: variable_declarator + all: + - has: + kind: identifier + pattern: $SHA + - has: + kind: string_literal + has: + kind: string_fragment + any: + - regex: ^SHA-1 + - regex: ^SHA1 + +rule: + kind: method_invocation + any: + - matches: java.security.MessageDigest.getInstance("SHA-1") + - pattern: $DU.getSha1Digest().digest($$$) + - matches: MessageDigest.getInstance("SHA-1") + - matches: MessageDigest.getInstance("SHA-1")_with_Instance + - matches: java.security.MessageDigest.getInstance("SHA-1")_with_Instance + all: + - not: + inside: + stopBy: end + kind: ERROR + - not: + has: + stopBy: end + kind: ERROR \ No newline at end of file diff --git a/tests/__snapshots__/use-of-blowfish-java-snapshot.yml b/tests/__snapshots__/use-of-blowfish-java-snapshot.yml new file mode 100644 index 00000000..4b759223 --- /dev/null +++ b/tests/__snapshots__/use-of-blowfish-java-snapshot.yml @@ -0,0 +1,52 @@ +id: use-of-blowfish-java +snapshots: + ? |- + public void useofBlowfish2() { + Cipher.getInstance("Blowfish"); + } + : labels: + - source: Cipher.getInstance("Blowfish") + style: primary + start: 31 + end: 61 + - source: getInstance + style: secondary + start: 38 + end: 49 + - source: Blowfish + style: secondary + start: 51 + end: 59 + - source: '"Blowfish"' + style: secondary + start: 50 + end: 60 + - source: ("Blowfish") + style: secondary + start: 49 + end: 61 + ? | + public void useofBlowfish2() { + useCipher(Cipher.getInstance("Blowfish")); + } + : labels: + - source: Cipher.getInstance("Blowfish") + style: primary + start: 41 + end: 71 + - source: getInstance + style: secondary + start: 48 + end: 59 + - source: Blowfish + style: secondary + start: 61 + end: 69 + - source: '"Blowfish"' + style: secondary + start: 60 + end: 70 + - source: ("Blowfish") + style: secondary + start: 59 + end: 71 diff --git a/tests/__snapshots__/use-of-default-aes-java-snapshot.yml b/tests/__snapshots__/use-of-default-aes-java-snapshot.yml new file mode 100644 index 00000000..f50c332c --- /dev/null +++ b/tests/__snapshots__/use-of-default-aes-java-snapshot.yml @@ -0,0 +1,78 @@ +id: use-of-default-aes-java +snapshots: + ? | + import javax.*; + { + crypto.Cipher.getInstance("AES"); + } + : labels: + - source: crypto.Cipher.getInstance("AES") + style: primary + start: 18 + end: 50 + - source: crypto.Cipher + style: secondary + start: 18 + end: 31 + - source: getInstance + style: secondary + start: 32 + end: 43 + - source: '"AES"' + style: secondary + start: 44 + end: 49 + - source: ("AES") + style: secondary + start: 43 + end: 50 + - source: import javax.*; + style: secondary + start: 0 + end: 15 + - source: import javax.*; + style: secondary + start: 0 + end: 15 + - source: AES + style: secondary + start: 45 + end: 48 + ? |- + import javax.crypto.*; + { + useCipher(Cipher.getInstance("AES")); + } + : labels: + - source: Cipher.getInstance("AES") + style: primary + start: 35 + end: 60 + - source: Cipher + style: secondary + start: 35 + end: 41 + - source: getInstance + style: secondary + start: 42 + end: 53 + - source: '"AES"' + style: secondary + start: 54 + end: 59 + - source: ("AES") + style: secondary + start: 53 + end: 60 + - source: import javax.crypto.*; + style: secondary + start: 0 + end: 22 + - source: import javax.crypto.*; + style: secondary + start: 0 + end: 22 + - source: AES + style: secondary + start: 55 + end: 58 diff --git a/tests/__snapshots__/use-of-sha1-java-snapshot.yml b/tests/__snapshots__/use-of-sha1-java-snapshot.yml new file mode 100644 index 00000000..994f88ec --- /dev/null +++ b/tests/__snapshots__/use-of-sha1-java-snapshot.yml @@ -0,0 +1,82 @@ +id: use-of-sha1-java +snapshots: + ? |- + import java.security.MessageDigest; + public byte[] bad1(String password) { + MessageDigest sha1Digest = MessageDigest.getInstance("SHA-1"); + sha1Digest.update(password.getBytes()); + byte[] hashValue = sha1Digest.digest(); + return hashValue; + } + : labels: + - source: MessageDigest.getInstance("SHA-1") + style: primary + start: 101 + end: 135 + - source: MessageDigest + style: secondary + start: 101 + end: 114 + - source: getInstance + style: secondary + start: 115 + end: 126 + - source: SHA-1 + style: secondary + start: 128 + end: 133 + - source: '"SHA-1"' + style: secondary + start: 127 + end: 134 + - source: ("SHA-1") + style: secondary + start: 126 + end: 135 + - source: import java.security.MessageDigest; + style: secondary + start: 0 + end: 35 + - source: import java.security.MessageDigest; + style: secondary + start: 0 + end: 35 + ? | + public byte[] bad2(String password) { + byte[] hashValue = DigestUtils.getSha1Digest().digest(password.getBytes()); + return hashValue; + } + : labels: + - source: DigestUtils.getSha1Digest().digest(password.getBytes()) + style: primary + start: 57 + end: 112 + ? | + public void bad3() { + java.security.MessageDigest md = java.security.MessageDigest.getInstance("SHA1", "SUN"); + } + : labels: + - source: java.security.MessageDigest.getInstance("SHA1", "SUN") + style: primary + start: 54 + end: 108 + - source: java.security.MessageDigest + style: secondary + start: 54 + end: 81 + - source: getInstance + style: secondary + start: 82 + end: 93 + - source: SHA1 + style: secondary + start: 95 + end: 99 + - source: '"SHA1"' + style: secondary + start: 94 + end: 100 + - source: ("SHA1", "SUN") + style: secondary + start: 93 + end: 108 diff --git a/tests/java/use-of-blowfish-java-test.yml b/tests/java/use-of-blowfish-java-test.yml new file mode 100644 index 00000000..b30073d6 --- /dev/null +++ b/tests/java/use-of-blowfish-java-test.yml @@ -0,0 +1,13 @@ +id: use-of-blowfish-java +valid: + - | + crypto.Cipher.getInstance("AES"); +invalid: + - | + public void useofBlowfish2() { + useCipher(Cipher.getInstance("Blowfish")); + } + - | + public void useofBlowfish2() { + Cipher.getInstance("Blowfish"); + } \ No newline at end of file diff --git a/tests/java/use-of-default-aes-java-test.yml b/tests/java/use-of-default-aes-java-test.yml new file mode 100644 index 00000000..10e4909f --- /dev/null +++ b/tests/java/use-of-default-aes-java-test.yml @@ -0,0 +1,15 @@ +id: use-of-default-aes-java +valid: + - | + crypto.Cipher.getInstance("AES"); +invalid: + - | + import javax.*; + { + crypto.Cipher.getInstance("AES"); + } + - | + import javax.crypto.*; + { + useCipher(Cipher.getInstance("AES")); + } \ No newline at end of file diff --git a/tests/java/use-of-sha1-java-test.yml b/tests/java/use-of-sha1-java-test.yml new file mode 100644 index 00000000..0120d110 --- /dev/null +++ b/tests/java/use-of-sha1-java-test.yml @@ -0,0 +1,22 @@ +id: use-of-sha1-java +valid: + - | + Cipher.getInstance("AES/GCM/NoPadding"); +invalid: + - | + public byte[] bad2(String password) { + byte[] hashValue = DigestUtils.getSha1Digest().digest(password.getBytes()); + return hashValue; + } + - | + public void bad3() { + java.security.MessageDigest md = java.security.MessageDigest.getInstance("SHA1", "SUN"); + } + - | + import java.security.MessageDigest; + public byte[] bad1(String password) { + MessageDigest sha1Digest = MessageDigest.getInstance("SHA-1"); + sha1Digest.update(password.getBytes()); + byte[] hashValue = sha1Digest.digest(); + return hashValue; + } \ No newline at end of file