From dbb7ac453ae7ff56e7dd0e42aba4dc3a325453ba Mon Sep 17 00:00:00 2001 From: Eric Brown Date: Thu, 18 Apr 2024 17:43:26 -0700 Subject: [PATCH] Add Java rule for insecure java.net.HttpCookie (#432) Similar to javax.servlet.http.Cookie, the java.net.HttpCookie is also a class whether the contents of the cookie can be marked secure. This rule advises to always set secure to true. Signed-off-by: Eric Brown --- docs/rules.md | 1 + .../java/stdlib/java-net-insecure-cookie.md | 10 ++ .../java/stdlib/java_net_insecure_cookie.py | 103 ++++++++++++++++++ .../javax_servlet_http_insecure_cookie.py | 4 +- setup.cfg | 3 + .../rules/java/stdlib/java_net/__init__.py | 0 .../examples/HttpCookieSecureFalse.java | 15 +++ .../examples/HttpCookieSecureTrue.java | 11 ++ .../stdlib/java_net/test_insecure_cookie.py | 46 ++++++++ .../examples/CookieSecureFalse.java | 2 +- .../examples/CookieSecureTrue.java | 2 +- 11 files changed, 193 insertions(+), 4 deletions(-) create mode 100644 docs/rules/java/stdlib/java-net-insecure-cookie.md create mode 100644 precli/rules/java/stdlib/java_net_insecure_cookie.py create mode 100644 tests/unit/rules/java/stdlib/java_net/__init__.py create mode 100644 tests/unit/rules/java/stdlib/java_net/examples/HttpCookieSecureFalse.java create mode 100644 tests/unit/rules/java/stdlib/java_net/examples/HttpCookieSecureTrue.java create mode 100644 tests/unit/rules/java/stdlib/java_net/test_insecure_cookie.py diff --git a/docs/rules.md b/docs/rules.md index cfffbc48..eab304a6 100644 --- a/docs/rules.md +++ b/docs/rules.md @@ -17,6 +17,7 @@ | JAV003 | [java.security — weak key](rules/java/stdlib/java-security-weak-key.md) | Inadequate Encryption Strength Using Weak Keys in `java.security` Package | | JAV004 | [java.security — weak random](rules/java/stdlib/java-security-weak-random.md) | Use of Cryptographically Weak Pseudo-Random Number Generator `SHA1PRNG` | | JAV005 | [javax.servlet.http — insecure cookie](rules/java/stdlib/javax-servlet-http-insecure-cookie.md) | Sensitive Cookie in HTTPS Session Without 'Secure' Attribute | +| JAV006 | [java.net — insecure cookie](rules/java/stdlib/java-net-insecure-cookie.md) | Sensitive Cookie in HTTPS Session Without 'Secure' Attribute | ## Python Standard Library diff --git a/docs/rules/java/stdlib/java-net-insecure-cookie.md b/docs/rules/java/stdlib/java-net-insecure-cookie.md new file mode 100644 index 00000000..82eda149 --- /dev/null +++ b/docs/rules/java/stdlib/java-net-insecure-cookie.md @@ -0,0 +1,10 @@ +--- +id: JAV006 +title: java.net — insecure cookie +hide_title: true +pagination_prev: null +pagination_next: null +slug: /rules/JAV006 +--- + +::: precli.rules.java.stdlib.java_net_insecure_cookie diff --git a/precli/rules/java/stdlib/java_net_insecure_cookie.py b/precli/rules/java/stdlib/java_net_insecure_cookie.py new file mode 100644 index 00000000..1b5f9677 --- /dev/null +++ b/precli/rules/java/stdlib/java_net_insecure_cookie.py @@ -0,0 +1,103 @@ +# Copyright 2024 Secure Saurce LLC +r""" +# Sensitive Cookie in HTTPS Session Without 'Secure' Attribute + +This rule identifies and flags any instance where cookies in Java web +applications are created or set without the Secure flag. The absence of this +flag allows the cookie to be transmitted over non-HTTPS connections, which +poses a risk of interception by an attacker, especially through +man-in-the-middle (MITM) attacks. + +Cookies are often used to store sensitive information such as session +identifiers and personal data. When a cookie is set without the Secure flag, +it can be sent over both secure (HTTPS) and insecure (HTTP) connections. +This vulnerability exposes the cookie to potential interception when +transmitted over an insecure connection. To mitigate this risk, the Secure +flag should be set on all cookies that are intended for HTTPS sites, ensuring +they are only sent via secure connections. + +## Example + +```java +import java.net.HttpCookie; + +public class SessionCookie { + public static void main(String[] args) { + HttpCookie cookie = new HttpCookie("cookieName", "cookieValue"); + cookie.setSecure(false); + } +} +``` + +## Remediation + +All cookies containing sensitive data or used in a secure context must have +the Secure flag enabled. This practice ensures that the cookies are +transmitted only over HTTPS, providing protection against eavesdropping and +MITM attacks on the communication channel. + +```java +import java.net.HttpCookie; + +public class SessionCookie { + public static void main(String[] args) { + HttpCookie cookie = new HttpCookie("cookieName", "cookieValue"); + cookie.setSecure(true); + } +} +``` + +## See also + +- [HttpCookie (Java SE & JDK))](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/net/HttpCookie.html) +- [CWE-614: Sensitive Cookie in HTTPS Session Without 'Secure' Attribute (PRNG)](https://cwe.mitre.org/data/definitions/614.html) + +_New in version 0.5.1_ + +""" # noqa: E501 +from precli.core.call import Call +from precli.core.location import Location +from precli.core.result import Result +from precli.rules import Rule + + +class InsecureCookie(Rule): + def __init__(self, id: str): + super().__init__( + id=id, + name="insecure_cookie", + description=__doc__, + cwe_id=614, + message="The cookie '{0}' was found without the 'Secure' flag " + "set.", + wildcards={ + "java.net.*": [ + "HttpCookie", + ], + }, + ) + + def analyze_method_invocation(self, context: dict, call: Call) -> Result: + if call.name_qualified not in [ + "java.net.HttpCookie.setSecure", + ]: + return + + argument = call.get_argument(position=0) + secure = argument.value + + if secure is True: + return + + fixes = Rule.get_fixes( + context=context, + deleted_location=Location(node=argument.node), + description="Set the 'Secure' flag to True on all cookies.", + inserted_content="true", + ) + return Result( + rule_id=self.id, + location=Location(node=argument.node), + message=self.message.format(call.var_node.text.decode()), + fixes=fixes, + ) diff --git a/precli/rules/java/stdlib/javax_servlet_http_insecure_cookie.py b/precli/rules/java/stdlib/javax_servlet_http_insecure_cookie.py index f721f581..81b1e405 100644 --- a/precli/rules/java/stdlib/javax_servlet_http_insecure_cookie.py +++ b/precli/rules/java/stdlib/javax_servlet_http_insecure_cookie.py @@ -23,7 +23,7 @@ public class SessionCookie { public static void main(String[] args) { - Cookie cookie = Cookie(); + Cookie cookie = new Cookie("cookieName", "cookieValue"); cookie.setSecure(false); } } @@ -41,7 +41,7 @@ public class SessionCookie { public static void main(String[] args) { - Cookie cookie = Cookie(); + Cookie cookie = new Cookie("cookieName", "cookieValue"); cookie.setSecure(true); } } diff --git a/setup.cfg b/setup.cfg index 8e73b0d3..a7923ae4 100644 --- a/setup.cfg +++ b/setup.cfg @@ -61,6 +61,9 @@ precli.rules.java = # precli/rules/java/stdlib/javax_servlet_http_insecure_cookie.py JAV005 = precli.rules.java.stdlib.javax_servlet_http_insecure_cookie:InsecureCookie + # precli/rules/java/stdlib/java_net_insecure_cookie.py + JAV006 = precli.rules.java.stdlib.java_net_insecure_cookie:InsecureCookie + precli.rules.python = # precli/rules/python/stdlib/assert.py PY001 = precli.rules.python.stdlib.assert:Assert diff --git a/tests/unit/rules/java/stdlib/java_net/__init__.py b/tests/unit/rules/java/stdlib/java_net/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/unit/rules/java/stdlib/java_net/examples/HttpCookieSecureFalse.java b/tests/unit/rules/java/stdlib/java_net/examples/HttpCookieSecureFalse.java new file mode 100644 index 00000000..1a8fdc1c --- /dev/null +++ b/tests/unit/rules/java/stdlib/java_net/examples/HttpCookieSecureFalse.java @@ -0,0 +1,15 @@ +// level: WARNING +// start_line: 13 +// end_line: 13 +// start_column: 25 +// end_column: 30 +import java.net.*; + + +public class HttpCookieSecureFalse { + public static void main(String[] args) { + HttpCookie cookie = new HttpCookie("cookieName", "cookieValue"); + cookie.setHttpOnly(true); + cookie.setSecure(false); + } +} diff --git a/tests/unit/rules/java/stdlib/java_net/examples/HttpCookieSecureTrue.java b/tests/unit/rules/java/stdlib/java_net/examples/HttpCookieSecureTrue.java new file mode 100644 index 00000000..44de3025 --- /dev/null +++ b/tests/unit/rules/java/stdlib/java_net/examples/HttpCookieSecureTrue.java @@ -0,0 +1,11 @@ +// level: NONE +import java.net.*; + + +public class HttpCookieSecureTrue { + public static void main(String[] args) { + HttpCookie cookie = new HttpCookie("cookieName", "cookieValue"); + cookie.setHttpOnly(true); + cookie.setSecure(true); + } +} diff --git a/tests/unit/rules/java/stdlib/java_net/test_insecure_cookie.py b/tests/unit/rules/java/stdlib/java_net/test_insecure_cookie.py new file mode 100644 index 00000000..f5cfc913 --- /dev/null +++ b/tests/unit/rules/java/stdlib/java_net/test_insecure_cookie.py @@ -0,0 +1,46 @@ +# Copyright 2024 Secure Saurce LLC +import os + +from parameterized import parameterized + +from precli.core.level import Level +from precli.parsers import java +from precli.rules import Rule +from tests.unit.rules import test_case + + +class InsecureCookieTests(test_case.TestCase): + def setUp(self): + super().setUp() + self.rule_id = "JAV006" + self.parser = java.Java() + self.base_path = os.path.join( + "tests", + "unit", + "rules", + "java", + "stdlib", + "java_net", + "examples", + ) + + def test_rule_meta(self): + rule = Rule.get_by_id(self.rule_id) + self.assertEqual(self.rule_id, rule.id) + self.assertEqual("insecure_cookie", rule.name) + self.assertEqual( + f"https://docs.securesauce.dev/rules/{self.rule_id}", rule.help_url + ) + self.assertEqual(True, rule.default_config.enabled) + self.assertEqual(Level.WARNING, rule.default_config.level) + self.assertEqual(-1.0, rule.default_config.rank) + self.assertEqual("614", rule.cwe.cwe_id) + + @parameterized.expand( + [ + "HttpCookieSecureFalse.java", + "HttpCookieSecureTrue.java", + ] + ) + def test(self, filename): + self.check(filename) diff --git a/tests/unit/rules/java/stdlib/javax_servlet_http/examples/CookieSecureFalse.java b/tests/unit/rules/java/stdlib/javax_servlet_http/examples/CookieSecureFalse.java index c5925b16..569d0e59 100644 --- a/tests/unit/rules/java/stdlib/javax_servlet_http/examples/CookieSecureFalse.java +++ b/tests/unit/rules/java/stdlib/javax_servlet_http/examples/CookieSecureFalse.java @@ -8,7 +8,7 @@ public class CookieSecureFalse { public static void main(String[] args) { - Cookie cookie = Cookie(); + Cookie cookie = new Cookie("cookieName", "cookieValue"); cookie.setHttpOnly(true); cookie.setSecure(false); } diff --git a/tests/unit/rules/java/stdlib/javax_servlet_http/examples/CookieSecureTrue.java b/tests/unit/rules/java/stdlib/javax_servlet_http/examples/CookieSecureTrue.java index 04e9fd95..b6cf7fa9 100644 --- a/tests/unit/rules/java/stdlib/javax_servlet_http/examples/CookieSecureTrue.java +++ b/tests/unit/rules/java/stdlib/javax_servlet_http/examples/CookieSecureTrue.java @@ -4,7 +4,7 @@ public class CookieSecureTrue { public static void main(String[] args) { - Cookie cookie = Cookie(); + Cookie cookie = new Cookie("cookieName", "cookieValue"); cookie.setHttpOnly(true); cookie.setSecure(true); }