<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE rfc [
  <!ENTITY nbsp    "&#160;">
  <!ENTITY zwsp   "&#8203;">
  <!ENTITY nbhy   "&#8209;">
  <!ENTITY wj     "&#8288;">
]>
<?xml-stylesheet type="text/xsl" href="rfc2629.xslt" ?>
<!-- generated by https://github.com/cabo/kramdown-rfc version 1.7.27 (Ruby 3.3.6) -->
<rfc xmlns:xi="http://www.w3.org/2001/XInclude" ipr="trust200902" docName="draft-httponlyprefix-weiss-http-01" category="info" consensus="true" submissionType="IETF" tocInclude="true" sortRefs="true" symRefs="true" version="3">
  <!-- xml2rfc v2v3 conversion 3.28.1 -->
  <front>
    <title abbrev="HttpOnlyPrefix">HttpOnly cookie prefix</title>
    <seriesInfo name="Internet-Draft" value="draft-httponlyprefix-weiss-http-01"/>
    <author fullname="Yoav Weiss">
      <organization>Shopify</organization>
      <address>
        <email>yoav@yoav.ws</email>
      </address>
    </author>
    <author fullname="Matthew Metzger">
      <organization>Shopify</organization>
      <address>
        <email>matthew.o.metzger@gmail.com</email>
      </address>
    </author>
    <date year="2025" month="April" day="09"/>
    <keyword>next generation</keyword>
    <keyword>unicorn</keyword>
    <keyword>sparkling distributed ledger</keyword>
    <abstract>
      <?line 46?>

<t>This draft introduces the __HttpOnly and __HostHttpOnly cookie name prefixes
that ensure the cookie was set with an HttpOnly attribute.</t>
    </abstract>
    <note removeInRFC="true">
      <name>About This Document</name>
      <t>
        The latest revision of this draft can be found at <eref target="https://yoavweiss.github.io/httponly_prefix/draft-httponlyprefix-weiss-http.html"/>.
        Status information for this document may be found at <eref target="https://datatracker.ietf.org/doc/draft-httponlyprefix-weiss-http/"/>.
      </t>
      <t>Source for this draft and an issue tracker can be found at
        <eref target="https://github.com/yoavweiss/httponly_prefix"/>.</t>
    </note>
  </front>
  <middle>
    <?line 52?>

<section anchor="introduction">
      <name>Introduction</name>
      <t>There are cases where it's important to distinguish on the server side
between cookies <xref target="COOKIES"/> that were set by the server and
ones that were set by the client.</t>
      <t>One such case is cookies that are normally <em>always</em> set by the server,
unless some unexpected code (an XSS exploit, a malicious extension, a
commit from a confused developer, etc.) happens to set them on the client.</t>
      <t>This draft add a signal that would enable servers to make such a distinction.</t>
      <t>More specifically, it defines the __HttpOnly and __HostHttpOnly prefixes,
that make sure that a cookie is not set on the client side using script.</t>
      <section anchor="conventions-and-definitions">
        <name>Conventions and Definitions</name>
        <t>The key words "<bcp14>MUST</bcp14>", "<bcp14>MUST NOT</bcp14>", "<bcp14>REQUIRED</bcp14>", "<bcp14>SHALL</bcp14>", "<bcp14>SHALL
NOT</bcp14>", "<bcp14>SHOULD</bcp14>", "<bcp14>SHOULD NOT</bcp14>", "<bcp14>RECOMMENDED</bcp14>", "<bcp14>NOT RECOMMENDED</bcp14>",
"<bcp14>MAY</bcp14>", and "<bcp14>OPTIONAL</bcp14>" in this document are to be interpreted as
described in BCP 14 <xref target="RFC2119"/> <xref target="RFC8174"/> when, and only when, they
appear in all capitals, as shown here.</t>
        <?line -18?>

</section>
    </section>
    <section anchor="server-requirements">
      <name>Server Requirements</name>
      <t>These requirements apply to cookies set in <tt>Set-Cookie</tt> response headers by the server,
as well as ones received in a <tt>Cookie</tt> request header from the client.</t>
      <section anchor="cookie-name-prefixes">
        <name>Cookie Name Prefixes</name>
        <section anchor="the-httponly-prefix">
          <name>The "__HttpOnly-" prefix</name>
          <section anchor="cookie-creation">
            <name>Cookie creation</name>
            <t>If a server creates a cookie whose name begins with a case-sensitive match for
the string <tt>__HttpOnly-</tt>, then all the following <bcp14>MUST</bcp14> be true:</t>
            <ol spacing="normal" type="1"><li>
                <t>The <tt>Set-Cookie</tt> HTTP header <bcp14>MUST</bcp14> include the <tt>Secure</tt> attribute.</t>
              </li>
              <li>
                <t>The <tt>Set-Cookie</tt> HTTP header <bcp14>MUST</bcp14> include the <tt>HttpOnly</tt> attribute.</t>
              </li>
            </ol>
          </section>
          <section anchor="cookie-processing">
            <name>Cookie processing</name>
            <t>If a server processes a cookie received in a <tt>Cookie</tt> request header whose name begins with a case-sensitive
match for the string <tt>__HttpOnly-</tt>, this indicates that <strong>all</strong> the following are true:</t>
            <ol spacing="normal" type="1"><li>
                <t>The cookie was originally created using a <tt>Set-Cookie</tt> HTTP header sent from this server.</t>
              </li>
              <li>
                <t>The <tt>Set-Cookie</tt> HTTP header included the <tt>Secure</tt> attribute.</t>
              </li>
              <li>
                <t>The <tt>Set-Cookie</tt> HTTP header included the <tt>HttpOnly</tt> attribute.</t>
              </li>
            </ol>
          </section>
        </section>
        <section anchor="the-hosthttponly-prefix">
          <name>The "__HostHttpOnly-" prefix</name>
          <section anchor="cookie-creation-1">
            <name>Cookie creation</name>
            <t>If a server uses a <tt>Set-Cookie</tt> HTTP header to create a cookie whose name begins with a case-sensitive match for
the string <tt>__HostHttpOnly-</tt>, then all the following <bcp14>MUST</bcp14> be true:</t>
            <ol spacing="normal" type="1"><li>
                <t>The <tt>Set-Cookie</tt> HTTP header <bcp14>MUST</bcp14> include the <tt>Secure</tt> attribute.</t>
              </li>
              <li>
                <t>The <tt>Set-Cookie</tt> HTTP header <bcp14>MUST</bcp14> include the <tt>HttpOnly</tt> attribute.</t>
              </li>
              <li>
                <t>The <tt>Set-Cookie</tt> HTTP header <bcp14>MUST</bcp14> include the <tt>Path</tt> attribute with a value of <tt>/</tt>.</t>
              </li>
              <li>
                <t>The <tt>Set-Cookie</tt> HTTP header <bcp14>MUST NOT</bcp14> include the <tt>Domain</tt> attribute.</t>
              </li>
            </ol>
          </section>
          <section anchor="cookie-processing-1">
            <name>Cookie processing</name>
            <t>If a server processes a cookie received in a <tt>Cookie</tt> request header whose name begins with a case-sensitive
match for the string <tt>__HostHttpOnly-</tt>, this indicates that <strong>all</strong> the following are true:</t>
            <ol spacing="normal" type="1"><li>
                <t>The cookie was originally created using a <tt>Set-Cookie</tt> HTTP header sent from this server</t>
              </li>
              <li>
                <t>The <tt>Set-Cookie</tt> HTTP header included the <tt>Secure</tt> attribute.</t>
              </li>
              <li>
                <t>The <tt>Set-Cookie</tt> HTTP header included the <tt>HttpOnly</tt> attribute.</t>
              </li>
              <li>
                <t>The <tt>Set-Cookie</tt> HTTP header included the <tt>Path</tt> attribute with a value of <tt>/</tt>.</t>
              </li>
              <li>
                <t>The <tt>Set-Cookie</tt> HTTP header did not include the <tt>Domain</tt> attribute.</t>
              </li>
            </ol>
          </section>
        </section>
      </section>
    </section>
    <section anchor="user-agent-requirements">
      <name>User Agent Requirements</name>
      <t>These requirements apply to cookies received in a <tt>Set-Cookie</tt> response header from the server.</t>
      <section anchor="cookie-name-prefixes-1">
        <name>Cookie Name Prefixes</name>
        <t>User agents' requirements for cookie name prefixes differ slightly from servers', as UAs <bcp14>MUST</bcp14> match the prefix string case-insensitively.</t>
        <section anchor="storage-model">
          <name>Storage Model</name>
          <t>Add the following steps after step 21 of section 5.7 in <xref target="COOKIES"/>.</t>
          <ol spacing="normal" type="1"><li>
              <t>If the cookie-name begins with a case-insensitive match for the string "__HttpOnly-",
              </t>
              <ol spacing="normal" type="1"><li>
                  <t>Abort these steps and ignore the cookie entirely unless all the following conditions are true:
                  </t>
                  <ol spacing="normal" type="1"><li>
                      <t>The cookie's <tt>secure-only-flag</tt> is true.</t>
                    </li>
                    <li>
                      <t>The cookie's <tt>http-only-flag</tt> is true.</t>
                    </li>
                    <li>
                      <t>The <tt>cookie-attribute-list</tt> contains an attribute with an <tt>attribute-name</tt> of "Path", and the cookie's path is "/".</t>
                    </li>
                  </ol>
                </li>
              </ol>
            </li>
            <li>
              <t>If the cookie-name begins with a case-insensitive match for the string "__HostHttpOnly-",
              </t>
              <ol spacing="normal" type="1"><li>
                  <t>Abort these steps and ignore the cookie entirely unless all the following conditions are true:
                  </t>
                  <ol spacing="normal" type="1"><li>
                      <t>The cookie's <tt>secure-only-flag</tt> is true.</t>
                    </li>
                    <li>
                      <t>The cookie's <tt>http-only-flag</tt> is true.</t>
                    </li>
                    <li>
                      <t>The cookie's <tt>host-only-flag</tt> is true.</t>
                    </li>
                    <li>
                      <t>The <tt>cookie-attribute-list</tt> contains an attribute with an <tt>attribute-name</tt> of "Path", and the cookie's path is "/".</t>
                    </li>
                    <li>
                      <t>The <tt>cookie-attribute-list</tt> does not contain an attribute with an <tt>attribute-name</tt> of "Domain".</t>
                    </li>
                  </ol>
                </li>
              </ol>
            </li>
          </ol>
        </section>
      </section>
    </section>
    <section anchor="security-considerations">
      <name>Security Considerations</name>
      <t>There are no particular security considerations.
These new prefixes will only limit the ability of non-compliant cookies to be set.
They do not open up new capabilities for server to set cookies where they previously could not.</t>
    </section>
    <section anchor="iana-considerations">
      <name>IANA Considerations</name>
      <t>This document has no IANA actions.</t>
    </section>
  </middle>
  <back>
    <references anchor="sec-normative-references">
      <name>Normative References</name>
      <reference anchor="COOKIES" target="https://datatracker.ietf.org/doc/draft-ietf-httpbis-rfc6265bis/">
        <front>
          <title>Cookies HTTP State Management Mechanism</title>
          <author>
            <organization/>
          </author>
          <date year="2025" month="February"/>
        </front>
      </reference>
      <reference anchor="RFC2119">
        <front>
          <title>Key words for use in RFCs to Indicate Requirement Levels</title>
          <author fullname="S. Bradner" initials="S." surname="Bradner"/>
          <date month="March" year="1997"/>
          <abstract>
            <t>In many standards track documents several words are used to signify the requirements in the specification. These words are often capitalized. This document defines these words as they should be interpreted in IETF documents. This document specifies an Internet Best Current Practices for the Internet Community, and requests discussion and suggestions for improvements.</t>
          </abstract>
        </front>
        <seriesInfo name="BCP" value="14"/>
        <seriesInfo name="RFC" value="2119"/>
        <seriesInfo name="DOI" value="10.17487/RFC2119"/>
      </reference>
      <reference anchor="RFC8174">
        <front>
          <title>Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words</title>
          <author fullname="B. Leiba" initials="B." surname="Leiba"/>
          <date month="May" year="2017"/>
          <abstract>
            <t>RFC 2119 specifies common key words that may be used in protocol specifications. This document aims to reduce the ambiguity by clarifying that only UPPERCASE usage of the key words have the defined special meanings.</t>
          </abstract>
        </front>
        <seriesInfo name="BCP" value="14"/>
        <seriesInfo name="RFC" value="8174"/>
        <seriesInfo name="DOI" value="10.17487/RFC8174"/>
      </reference>
    </references>
    <?line 176?>

<section numbered="false" anchor="acknowledgments">
      <name>Acknowledgments</name>
      <t>Thanks to Rory Hewitt for his contributions to this draft.
TODO acknowledge.</t>
    </section>
  </back>
  <!-- ##markdown-source:
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
xd7dJvDQ/wHU8ECmdxgAAA==

-->

</rfc>
