diff --git a/rules/java/security/cookie-httponly-false-java.yml b/rules/java/security/cookie-httponly-false-java.yml new file mode 100644 index 00000000..5916d17b --- /dev/null +++ b/rules/java/security/cookie-httponly-false-java.yml @@ -0,0 +1,13 @@ +id: cookie-httponly-false-java +language: java +message: >- + A cookie was detected without setting the 'HttpOnly' flag. The + 'HttpOnly' flag for cookies instructs the browser to forbid client-side + scripts from reading the cookie. Set the 'HttpOnly' flag by calling + 'cookie.setHttpOnly(true);' +note: >- + [CWE-1004] Sensitive Cookie Without 'HttpOnly' Flag. + [REFERENCES] + - https://capec.mitre.org/data/definitions/463.html +rule: + pattern: $COOKIE.setHttpOnly(false); diff --git a/rules/java/security/missing-secure-java.yml b/rules/java/security/missing-secure-java.yml new file mode 100644 index 00000000..755e6660 --- /dev/null +++ b/rules/java/security/missing-secure-java.yml @@ -0,0 +1,70 @@ +id: missing-secure-java +language: java +severity: warning +message: >- + Detected a cookie where the `Secure` flag is either missing or + disabled. The `Secure` cookie flag instructs the browser to forbid sending + the cookie over an insecure HTTP request. Set the `Secure` flag to `true` + so the cookie will only be sent over HTTPS. +note: >- + [CWE-614]: Sensitive Cookie in HTTPS Session Without 'Secure' Attribute + [OWASP A05:2021]: Security Misconfiguration + [REFERENCES] + - https://owasp.org/Top10/A05_2021-Security_Misconfiguration +utils: + match_without_httponly: + kind: argument_list + has: + kind: object_creation_expression + inside: + stopBy: end + kind: method_invocation + + match_cookie_last: + kind: argument_list + has: + kind: method_invocation + has: + kind: argument_list + has: + kind: string_literal + + match_instance: + kind: local_variable_declaration + has: + stopBy: end + kind: identifier + follows: + stopBy: end + kind: variable_declarator + + match_identifier_with_simplecookie: + kind: identifier + inside: + stopBy: end + kind: local_variable_declaration + all: + - has: + stopBy: end + kind: type_identifier + regex: '^SimpleCookie$|^Cookie$' + - has: + stopBy: neighbor + kind: variable_declarator + all: + - has: + stopBy: neighbor + kind: identifier + - has: + stopBy: neighbor + kind: object_creation_expression + - not: + precedes: + stopBy: neighbor + kind: expression_statement +rule: + any: + - matches: match_instance + - matches: match_without_httponly + - matches: match_cookie_last + - matches: match_identifier_with_simplecookie diff --git a/tests/__snapshots__/cookie-httponly-false-java-snapshot.yml b/tests/__snapshots__/cookie-httponly-false-java-snapshot.yml new file mode 100644 index 00000000..c1460483 --- /dev/null +++ b/tests/__snapshots__/cookie-httponly-false-java-snapshot.yml @@ -0,0 +1,16 @@ +id: cookie-httponly-false-java +snapshots: + ? |2 + + @RequestMapping(value = "/cookie4", method = "GET") + public void explicitDisable(@RequestParam String value, HttpServletResponse response) { + Cookie cookie = new Cookie("cookie", value); + cookie.setSecure(false); + cookie.setHttpOnly(false); + response.addCookie(cookie); + } + : labels: + - source: cookie.setHttpOnly(false); + style: primary + start: 223 + end: 249 diff --git a/tests/__snapshots__/missing-secure-java-snapshot.yml b/tests/__snapshots__/missing-secure-java-snapshot.yml new file mode 100644 index 00000000..3931463b --- /dev/null +++ b/tests/__snapshots__/missing-secure-java-snapshot.yml @@ -0,0 +1,32 @@ +id: missing-secure-java +snapshots: + ? | + SimpleCookie s = new SimpleCookie("foo", "bar"); + .orElse( new NettyCookie( "foo", "bar" ) ); + Cookie z = new NettyCookie("foo", "bar"); + return HttpResponse.ok().cookie(Cookie.of("zzz", "ddd")); + : labels: + - source: s + style: primary + start: 13 + end: 14 + - source: SimpleCookie + style: secondary + start: 0 + end: 12 + - source: s + style: secondary + start: 13 + end: 14 + - source: new SimpleCookie("foo", "bar") + style: secondary + start: 17 + end: 47 + - source: s = new SimpleCookie("foo", "bar") + style: secondary + start: 13 + end: 47 + - source: SimpleCookie s = new SimpleCookie("foo", "bar"); + style: secondary + start: 0 + end: 48 diff --git a/tests/java/cookie-httponly-false-java-test.yml b/tests/java/cookie-httponly-false-java-test.yml new file mode 100644 index 00000000..1d1f3397 --- /dev/null +++ b/tests/java/cookie-httponly-false-java-test.yml @@ -0,0 +1,20 @@ +id: cookie-httponly-false-java +valid: + - | + @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); + } +invalid: + - | + + @RequestMapping(value = "/cookie4", method = "GET") + public void explicitDisable(@RequestParam String value, HttpServletResponse response) { + Cookie cookie = new Cookie("cookie", value); + cookie.setSecure(false); + cookie.setHttpOnly(false); + response.addCookie(cookie); + } diff --git a/tests/java/missing-secure-java-test.yml b/tests/java/missing-secure-java-test.yml new file mode 100644 index 00000000..507f951f --- /dev/null +++ b/tests/java/missing-secure-java-test.yml @@ -0,0 +1,15 @@ +id: missing-secure-java +valid: + - | + Cookie c1 = getCookieSomewhere(); + return HttpResponse.ok().cookie(Cookie.of("foo", "bar").secure(true)); + Cookie cookie = request.getCookies().findCookie( "foobar" ) + Cookie c = new NettyCookie("foo", "bar"); + c.secure(true); + NettyCookie r = new NettyCookie("foo", "bar").secure(true); +invalid: + - | + SimpleCookie s = new SimpleCookie("foo", "bar"); + .orElse( new NettyCookie( "foo", "bar" ) ); + Cookie z = new NettyCookie("foo", "bar"); + return HttpResponse.ok().cookie(Cookie.of("zzz", "ddd"));