<?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.26 (Ruby 3.3.6) -->
<rfc xmlns:xi="http://www.w3.org/2001/XInclude" ipr="trust200902" docName="draft-httponlyprefix-weiss-http-00" category="info" consensus="true" submissionType="IETF" tocInclude="true" sortRefs="true" symRefs="true" version="3">
  <!-- xml2rfc v2v3 conversion 3.28.0 -->
  <front>
    <title abbrev="HttpOnlyPrefix">HttpOnly cookie prefix</title>
    <seriesInfo name="Internet-Draft" value="draft-httponlyprefix-weiss-http-00"/>
    <author fullname="Yoav Weiss">
      <organization>Shopify</organization>
      <address>
        <email>yoav@yoav.ws</email>
      </address>
    </author>
    <date year="2025" month="March" day="20"/>
    <keyword>next generation</keyword>
    <keyword>unicorn</keyword>
    <keyword>sparkling distributed ledger</keyword>
    <abstract>
      <?line 42?>

<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 48?>

<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 172?>

<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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

-->

</rfc>
