java.lang.security.audit.cookie-missing-httponly.cookie-missing-httponly

Community Favorite
profile photo of semgrepsemgrep
Author
73,396
Download Count*

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);'

Run Locally

Run in CI

Defintion

rules:
  - id: cookie-missing-httponly
    metadata:
      cwe:
        - "CWE-1004: Sensitive Cookie Without 'HttpOnly' Flag"
      owasp:
        - A05:2021 - Security Misconfiguration
      source-rule-url: https://find-sec-bugs.github.io/bugs.htm#HTTPONLY_COOKIE
      asvs:
        section: "V3: Session Management Verification Requirements"
        control_id: 3.4.2 Missing Cookie Attribute
        control_url: https://github.com/OWASP/ASVS/blob/master/4.0/en/0x12-V3-Session-management.md#v34-cookie-based-session-management
        version: "4"
      category: security
      technology:
        - java
      references:
        - https://owasp.org/Top10/A05_2021-Security_Misconfiguration
      subcategory:
        - audit
      likelihood: LOW
      impact: LOW
      confidence: LOW
      license: Commons Clause License Condition v1.0[LGPL-2.1-only]
      vulnerability_class:
        - Cookie Security
    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);'
    severity: WARNING
    languages:
      - java
    patterns:
      - pattern-not-inside: $COOKIE.setValue(""); ...
      - pattern-either:
          - pattern: $COOKIE.setHttpOnly(false);
          - patterns:
              - pattern-not-inside: $COOKIE.setHttpOnly(...); ...
              - pattern-not-inside: $COOKIE = ResponseCookie.from(...). ...; ...
              - pattern: $RESPONSE.addCookie($COOKIE);

Examples

cookie-missing-httponly.java

@Controller
public class CookieController {

    @RequestMapping(value = "/cookie1", method = "GET")
    public void setCookie(@RequestParam String value, HttpServletResponse response) {
        Cookie cookie = new Cookie("cookie", value);
        // ruleid: cookie-missing-httponly
        response.addCookie(cookie);
    }

    @RequestMapping(value = "/cookie2", method = "GET")
    public void setSecureCookie(@RequestParam String value, HttpServletResponse response) {
        Cookie cookie = new Cookie("cookie", value);
        cookie.setSecure(true);
        // ruleid: cookie-missing-httponly
        response.addCookie(cookie);
    }

    @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);
        // ok: cookie-missing-httponly
        response.addCookie(cookie);
    }

    @RequestMapping(value = "/cookie4", method = "GET")
    public void explicitDisable(@RequestParam String value, HttpServletResponse response) {
        Cookie cookie = new Cookie("cookie", value);
        cookie.setSecure(false);
        // ruleid:cookie-missing-httponly
        cookie.setHttpOnly(false);
        response.addCookie(cookie);
    }

    @RequestMapping(value = "/cookie5", method = "GET")
    public void explicitDisable(@RequestParam String value, HttpServletResponse response) {
	// ignore cookies created by Spring's ResponseCookie builder, since the interface is different
	Cookie cookie = ResponseCookie.from("name", "value").build();
        // ok:cookie-missing-httponly
        response.addCookie(cookie);
    }

    // test case cf. https://github.com/Dreampie/Resty/blob/9ef059c065d1894c79e7d69c150e588a61eb1cd5/resty-common/src/main/java/cn/dreampie/common/http/HttpResponse.java#L69
    public Response addCookie(String name, String value, int expiration, boolean httpOnly) {
    Cookie existingCookie = HttpRequest.getCookie(request.getCookies(), name);
    if (existingCookie != null) {
      if (Constant.cookiePath.equals(existingCookie.getPath())
          || existingCookie.getPath() == null // in some cases cookies set on path '/' are returned with a null path
          ) {
        // update existing cookie
        existingCookie.setPath(Constant.cookiePath);
        existingCookie.setValue(value);
        existingCookie.setMaxAge(expiration);
        if (Constant.cookieHttpOnly) {
          setHttpOnly(existingCookie);
        }
        existingCookie.setSecure(Constant.cookieSecure);
        if (Constant.cookieDomain != null) {
          existingCookie.setDomain(Constant.cookieDomain);
        }
        // uses its own method to set httponly. will not detect
        // ruleid: cookie-missing-httponly
        response.addCookie(existingCookie);
      } else {
        // we have an existing cookie on another path: clear it, and add a new cookie on root path
        existingCookie.setValue("");
        existingCookie.setMaxAge(0);
        // ok: cookie-missing-httponly
        response.addCookie(existingCookie);

        Cookie c = new Cookie(name, value);
        c.setPath(Constant.cookiePath);
        c.setMaxAge(expiration);
        if (Constant.cookieHttpOnly) {
          setHttpOnly(existingCookie);
        }
        c.setSecure(Constant.cookieSecure);
        if (Constant.cookieDomain != null) {
          c.setDomain(Constant.cookieDomain);
        }
        // uses its own method to set httponly. will not detect
        // ruleid: cookie-missing-httponly
        response.addCookie(c);
      }
    } else {
      Cookie c = new Cookie(name, value);
      c.setPath(Constant.cookiePath);
      c.setMaxAge(expiration);
      if (Constant.cookieHttpOnly) {
        setHttpOnly(c);
      }
      c.setSecure(Constant.cookieSecure);
      if (Constant.cookieDomain != null) {
        c.setDomain(Constant.cookieDomain);
      }
      // uses its own method to set httponly. will not detect
      // ruleid: cookie-missing-httponly
      response.addCookie(c);
    }
    return this;
  }

  public Response clearCookie(String cookie) {
    Cookie existingCookie = HttpRequest.getCookie(request.getCookies(), cookie);
    if (existingCookie != null) {
      existingCookie.setPath(Constant.cookiePath);
      existingCookie.setValue("");
      existingCookie.setMaxAge(0);
      // ok: cookie-missing-httponly
      response.addCookie(existingCookie);
    }
    return this;
  }
}