diff --git a/rules/java/security/cookie-missing-samesite-java.yml b/rules/java/security/cookie-missing-samesite-java.yml new file mode 100644 index 00000000..58ec9d7b --- /dev/null +++ b/rules/java/security/cookie-missing-samesite-java.yml @@ -0,0 +1,67 @@ +id: cookie-missing-samesite-java +severity: warning +language: java +message: >- + The application does not appear to verify inbound requests which can + lead to a Cross-site request forgery (CSRF) vulnerability. If the + application uses cookie-based authentication, an attacker can trick users + into sending authenticated HTTP requests without their knowledge from any + arbitrary domain they visit. To prevent this vulnerability start by + identifying if the framework or library leveraged has built-in features or + offers plugins for CSRF protection. CSRF tokens should be unique and + securely random. The `Synchronizer Token` or `Double Submit Cookie` + patterns with defense-in-depth mechanisms such as the `sameSite` cookie + flag can help prevent CSRF. For more information, see: [Cross-site request + forgery prevention](https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Req\ + uest_Forgery_Prevention_Cheat_Sheet.html). +note: >- + [CWE-352] Cross-Site Request Forgery (CSRF). + [REFERENCES] + - https://stackoverflow.com/questions/42717210/samesite-cookie-in-java-application +rule: + any: + - pattern: $RESP.setHeader("Set-Cookie", $T); + inside: + stopBy: end + kind: block + follows: + stopBy: end + kind: formal_parameters + has: + stopBy: end + kind: formal_parameter + all: + - has: + stopBy: end + kind: type_identifier + regex: "^HttpServletResponse$" + - has: + stopBy: neighbor + kind: identifier + - pattern: $RESP.addCookie($$$); + not: + follows: + stopBy: end + kind: expression_statement + pattern: $RESP.setHeader("Set-Cookie", $T); + inside: + stopBy: end + kind: block + follows: + stopBy: end + kind: formal_parameters + has: + stopBy: end + kind: formal_parameter + all: + - has: + stopBy: end + kind: type_identifier + regex: "^HttpServletResponse$" + - has: + stopBy: neighbor + kind: identifier +constraints: + T: + not: + regex: ".*SameSite=.*|null" diff --git a/rules/swift/security/aes-hardcoded-secret-swift.yml b/rules/swift/security/aes-hardcoded-secret-swift.yml new file mode 100644 index 00000000..6f9ba968 --- /dev/null +++ b/rules/swift/security/aes-hardcoded-secret-swift.yml @@ -0,0 +1,285 @@ +id: aes-hardcoded-secret-swift +language: swift +severity: warning +message: >- + A secret is hard-coded in the application. Secrets stored in source + code, such as credentials, identifiers, and other types of sensitive data, + can be leaked and used by internal or external malicious actors. Use + environment variables to securely provide credentials and other secrets or + retrieve them from a secure vault or Hardware Security Module (HSM). +note: >- + [OWASP A07:2021]:Identification and Authentication Failures + [CWE-272]: Least Privilege Violation + [REFERENCES] + https://cheatsheetseries.owasp.org/cheatsheets/Secrets_Management_Cheat_Sheet.html +utils: + match_pattern_try_expression_directly: + kind: try_expression + has: + stopBy: neighbor + kind: call_expression + all: + - has: + stopBy: end + kind: simple_identifier + regex: "^AES$" + - has: + stopBy: end + kind: call_suffix + has: + stopBy: end + kind: value_arguments + has: + stopBy: end + kind: value_argument + all: + - has: + stopBy: end + kind: simple_identifier + regex: "^key$" + - has: + stopBy: neighbor + kind: line_string_literal + has: + stopBy: end + kind: line_str_text + + match_pattern_AES_statement_directly: + kind: call_expression + all: + - has: + stopBy: end + kind: simple_identifier + regex: "^AES$" + - has: + stopBy: end + kind: call_suffix + has: + stopBy: end + kind: value_arguments + has: + stopBy: end + kind: value_argument + all: + - has: + stopBy: end + kind: simple_identifier + regex: "^key$" + - has: + stopBy: end + kind: line_string_literal + has: + stopBy: neighbor + kind: line_str_text + - not: + inside: + stopBy: end + kind: try_expression + + match_pattern_AES_expression_with_instance: + kind: call_expression + all: + - has: + stopBy: end + kind: simple_identifier + regex: "^AES$" + - has: + stopBy: end + kind: call_suffix + has: + stopBy: end + kind: value_arguments + has: + stopBy: end + kind: value_argument + all: + - has: + stopBy: end + kind: simple_identifier + regex: "^key$" + - has: + stopBy: end + kind: simple_identifier + nthChild: 2 + pattern: $R + - not: + inside: + stopBy: neighbor + kind: try_expression + - follows: + stopBy: end + kind: property_declaration + all: + - has: + stopBy: end + kind: pattern + has: + stopBy: end + kind: simple_identifier + pattern: $R + - has: + stopBy: neighbor + kind: call_expression + pattern: Array("$$$".utf8) + + match_pattern_try_expression_with_instance: + kind: try_expression + all: + - has: + stopBy: neighbor + kind: call_expression + all: + - has: + stopBy: end + kind: simple_identifier + regex: "^AES$" + - has: + stopBy: end + kind: call_suffix + has: + stopBy: end + kind: value_arguments + has: + stopBy: end + kind: value_argument + all: + - has: + stopBy: end + kind: simple_identifier + regex: "^key$" + - has: + stopBy: end + kind: simple_identifier + nthChild: 2 + pattern: $R + - follows: + stopBy: end + kind: property_declaration + all: + - has: + stopBy: end + kind: pattern + has: + stopBy: end + kind: simple_identifier + pattern: $R + - has: + stopBy: neighbor + kind: call_expression + pattern: Array("$$$".utf8) + + match_pattern_AES_expression_with_utf8: + kind: call_expression + all: + - has: + stopBy: neighbor + kind: simple_identifier + regex: "^AES$" + - has: + stopBy: neighbor + kind: call_suffix + has: + stopBy: end + kind: value_argument + all: + - has: + stopBy: end + kind: simple_identifier + regex: "^key$" + - has: + stopBy: end + kind: call_expression + all: + - has: + stopBy: neighbor + kind: simple_identifier + regex: "^Array$" + - has: + stopBy: neighbor + kind: call_suffix + has: + stopBy: end + kind: value_argument + has: + stopBy: neighbor + kind: navigation_expression + all: + - has: + stopBy: neighbor + kind: line_string_literal + has: + stopBy: neighbor + kind: line_str_text + - has: + stopBy: neighbor + kind: navigation_suffix + has: + stopBy: neighbor + kind: simple_identifier + regex: "^utf8$" + + match_pattern_try_expression_with_utf8: + kind: try_expression + has: + stopBy: neighbor + kind: call_expression + all: + - has: + stopBy: neighbor + kind: simple_identifier + regex: "^AES$" + - has: + stopBy: neighbor + kind: call_suffix + has: + stopBy: end + kind: value_argument + all: + - has: + stopBy: neighbor + kind: simple_identifier + regex: "^key$" + - has: + stopBy: neighbor + kind: call_expression + all: + - has: + stopBy: neighbor + kind: simple_identifier + regex: "^Array$" + - has: + stopBy: neighbor + kind: call_suffix + has: + stopBy: end + kind: value_argument + has: + stopBy: neighbor + kind: navigation_expression + all: + - has: + stopBy: neighbor + kind: line_string_literal + has: + stopBy: neighbor + kind: line_str_text + - has: + stopBy: neighbor + kind: navigation_suffix + has: + stopBy: neighbor + kind: simple_identifier + regex: "^utf8$" +rule: + any: + - kind: try_expression + any: + - matches: match_pattern_try_expression_directly + - matches: match_pattern_try_expression_with_instance + - matches: match_pattern_try_expression_with_utf8 + + - kind: call_expression + any: + - matches: match_pattern_AES_statement_directly + - matches: match_pattern_AES_expression_with_instance + - matches: match_pattern_AES_expression_with_utf8 diff --git a/tests/__snapshots__/aes-hardcoded-secret-swift-snapshot.yml b/tests/__snapshots__/aes-hardcoded-secret-swift-snapshot.yml new file mode 100644 index 00000000..a151bd90 --- /dev/null +++ b/tests/__snapshots__/aes-hardcoded-secret-swift-snapshot.yml @@ -0,0 +1,93 @@ +id: aes-hardcoded-secret-swift +snapshots: + ? | + let password: Array = Array("s33krit".utf8) + try AES(key: password, iv: "123") + : labels: + - source: 'try AES(key: password, iv: "123")' + style: primary + start: 51 + end: 84 + - source: AES + style: secondary + start: 55 + end: 58 + - source: key + style: secondary + start: 59 + end: 62 + - source: password + style: secondary + start: 64 + end: 72 + - source: 'key: password' + style: secondary + start: 59 + end: 72 + - source: '(key: password, iv: "123")' + style: secondary + start: 58 + end: 84 + - source: '(key: password, iv: "123")' + style: secondary + start: 58 + end: 84 + - source: 'AES(key: password, iv: "123")' + style: secondary + start: 55 + end: 84 + - source: password + style: secondary + start: 4 + end: 12 + - source: password + style: secondary + start: 4 + end: 12 + - source: Array("s33krit".utf8) + style: secondary + start: 29 + end: 50 + - source: 'let password: Array = Array("s33krit".utf8)' + style: secondary + start: 0 + end: 50 + ? | + try AES(key: "hello", iv: "123") + : labels: + - source: 'try AES(key: "hello", iv: "123")' + style: primary + start: 0 + end: 32 + - source: AES + style: secondary + start: 4 + end: 7 + - source: key + style: secondary + start: 8 + end: 11 + - source: hello + style: secondary + start: 14 + end: 19 + - source: '"hello"' + style: secondary + start: 13 + end: 20 + - source: 'key: "hello"' + style: secondary + start: 8 + end: 20 + - source: '(key: "hello", iv: "123")' + style: secondary + start: 7 + end: 32 + - source: '(key: "hello", iv: "123")' + style: secondary + start: 7 + end: 32 + - source: 'AES(key: "hello", iv: "123")' + style: secondary + start: 4 + end: 32 diff --git a/tests/__snapshots__/cookie-missing-samesite-java-snapshot.yml b/tests/__snapshots__/cookie-missing-samesite-java-snapshot.yml new file mode 100644 index 00000000..dc3df37f --- /dev/null +++ b/tests/__snapshots__/cookie-missing-samesite-java-snapshot.yml @@ -0,0 +1,19 @@ +id: cookie-missing-samesite-java +snapshots: + ? | + @RequestMapping(value = "/cookie3", method = "GET") + public void setSecureHttponlyCookie(@RequestParam String value, HttpServletResponse response) { + Cookie cookie = new Cookie("cookie", value); + cookie.setSecure(true); + cookie.setHttpOnly(true); + response.addCookie(cookie); + } + @RequestMapping(value = "/cookie2", method = "GET") + public void setSecureCookie(@RequestParam String value, HttpServletResponse response) { + response.setHeader("Set-Cookie", "key=value; HttpOnly;"); + } + : labels: + - source: response.addCookie(cookie); + style: primary + start: 255 + end: 282 diff --git a/tests/java/cookie-missing-samesite-java-test.yml b/tests/java/cookie-missing-samesite-java-test.yml new file mode 100644 index 00000000..bfd4cd62 --- /dev/null +++ b/tests/java/cookie-missing-samesite-java-test.yml @@ -0,0 +1,20 @@ +id: cookie-missing-samesite-java +valid: + - | + @RequestMapping(value = "/cookie1", method = "GET") + public void setCookie(@RequestParam String value, HttpServletResponse response) { + response.setHeader("Set-Cookie", "key=value; HttpOnly; SameSite=strict"); + } +invalid: + - | + @RequestMapping(value = "/cookie3", method = "GET") + public void setSecureHttponlyCookie(@RequestParam String value, HttpServletResponse response) { + Cookie cookie = new Cookie("cookie", value); + cookie.setSecure(true); + cookie.setHttpOnly(true); + response.addCookie(cookie); + } + @RequestMapping(value = "/cookie2", method = "GET") + public void setSecureCookie(@RequestParam String value, HttpServletResponse response) { + response.setHeader("Set-Cookie", "key=value; HttpOnly;"); + } diff --git a/tests/swift/aes-hardcoded-secret-swift-test.yml b/tests/swift/aes-hardcoded-secret-swift-test.yml new file mode 100644 index 00000000..9aa125aa --- /dev/null +++ b/tests/swift/aes-hardcoded-secret-swift-test.yml @@ -0,0 +1,10 @@ +id: aes-hardcoded-secret-swift +valid: + - | + +invalid: + - | + let password: Array = Array("s33krit".utf8) + try AES(key: password, iv: "123") + - | + try AES(key: "hello", iv: "123")