RFC 6943

Issues in Identifier Comparison for Security Purposes

๐Ÿ“… published May 2013, from ietf

RFC 6943: Issues in Identifier Comparison for Security Purposes ๐ŸŽ€

Internet Architecture Board (IAB) ๐Ÿ’… is the stream, and D. Thaler, Ed. from Microsoft is the editor. It's Category: Informational ๐Ÿง , not Standards Track, and it dropped in May 2013 ๐ŸŒธ. The ISSN is 2070-1721. The title block doesn't list anything it obsoletes or updates, so it's a standalone doc bestie ๐Ÿฆ‹

Abstract โœจ

Okay so identifiers like hostnames, URIs, IP addresses, and email addresses are everywhere in security stuff ๐Ÿ”. They're how we name the people (security principals) and the things (resources) we're protecting. Usually an identifier comes in over some protocol, and then a policy compares it to decide things like whether a principal gets access, or how much authentication or encryption is needed ๐Ÿซถ

Here's the tea: if the two sides of a security decision compare identifiers using different algorithms, things can go really wrong, from denial of service all the way up to elevation of privilege ๐Ÿ’€ This document talks through those issues so designers can think about them when they define identifiers and protocols, and when they build architectures that mix multiple protocols ๐Ÿ‘‘

Status of This Memo โœจ

This doc is NOT an Internet Standards Track spec. It's published just for information purposes ๐ŸŒˆ

It's a product of the Internet Architecture Board (IAB), and it holds info the IAB thought was worth keeping on the permanent record ๐Ÿ“š It represents the consensus of the IAB. Anything the IAB approves for publication isn't a candidate for any level of Internet Standard. See Section 2 of RFC 5741 for the details ๐Ÿงš

You can find the current status of this document, any errata, and how to send feedback at http://www.rfc-editor.org/info/rfc6943 ๐Ÿ’œ

Copyright (c) 2013 IETF Trust and the persons identified as the document authors ๐ŸŽ€ All rights reserved.

This doc is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (http://trustee.ietf.org/license-info) as they stand on the publication date. Please read these carefully, bestie ๐Ÿฅน They spell out your rights and restrictions for this document.

Table of Contents ๐Ÿ“

1. Introduction ....................................................3
   1.1. Classes of Identifiers .....................................5
   1.2. Canonicalization ...........................................5
2. Identifier Use in Security Policies and Decisions ...............6
   2.1. False Positives and Negatives ..............................7
   2.2. Hypothetical Example .......................................8
3. Comparison Issues with Common Identifiers .......................9
   3.1. Hostnames ..................................................9
        3.1.1. IPv4 Literals ......................................11
        3.1.2. IPv6 Literals ......................................12
        3.1.3. Internationalization ...............................13
        3.1.4. Resolution for Comparison ..........................14
   3.2. Port Numbers and Service Names ............................14
   3.3. URIs ......................................................15
        3.3.1. Scheme Component ...................................16
        3.3.2. Authority Component ................................16
        3.3.3. Path Component .....................................17
        3.3.4. Query Component ....................................17
        3.3.5. Fragment Component .................................17
        3.3.6. Resolution for Comparison ..........................18
   3.4. Email Address-Like Identifiers ............................18
4. General Issues .................................................19
   4.1. Conflation ................................................19
   4.2. Internationalization ......................................20
   4.3. Scope .....................................................21
   4.4. Temporality ...............................................21
5. Security Considerations ........................................22
6. Acknowledgements ...............................................22
7. IAB Members at the Time of Approval ............................23
8. Informative References .........................................23

1. Introduction โœจ

Okay so in computing and on the Internet, all sorts of "identifiers" are used to name humans, devices, content, and more ๐Ÿฆ‹ This doc digs into the security issues designers should think about when they define identifiers and protocols, and when they build architectures that use multiple protocols ๐Ÿ’– Before we get into the security stuff, we'll cover some background on the typical processes that involve identifiers. Terms like "identifier", "identity", and "principal" are used as defined in [RFC4949] ๐Ÿ“–

Figure 1 shows the multiple processes that matter for our discussion ๐Ÿ‘€

  1. Generation ๐ŸŒฑ An identifier is first generated. If it's meant to be unique, the generation process must include some mechanism, like allocation by a central authority or verification among the members of a distributed authority, to help make sure it's unique. But "unique" is trickier than it sounds, since figuring it out means checking whether a putative identifier matches any other identifier that's already been allocated. As we'll see, for lots of identifier types this isn't just an exact binary match ๐Ÿ™ˆ

After generation, the identifier is often stored in two places: with the requester or "holder" of the identifier, and with some repository of identifiers (e.g., DNS) ๐Ÿ—‚๏ธ For example, if a central authority allocated the identifier, the repository might be that authority. If the identifier names a device or content on a device, the repository might be that device.

  1. Distribution ๐Ÿš€ The identifier gets distributed, either by its holder or by a repository, to others who could use it. This can happen electronically, but sometimes it goes through other channels like voice, business cards, billboards, or other advertisements ๐Ÿ“ฃ The identifier itself might be passed along directly, or it might be used to build a portion of another identifier that then gets distributed. For example, a URI or email address might include a server name, so distributing the URI or email address also inherently distributes the server name ๐Ÿซถ
  2. Use ๐ŸŽฏ Some party uses the identifier. Usually the user supplies it, which then gets sent (directly or indirectly) to the repository of identifiers. The repository must then try to match the user-supplied identifier with one in its repository ๐Ÿ‘€

For example, using an email address to send mail to the holder of an identifier may get the email to the holder's mail server, which has access to the mail stores ๐Ÿ“ฌ

                          +------------+
                          |  Holder of |     1. Generation
                          | identifier +<---------+
                          +----+-------+          |
                               |                  | Match
                               |                  v/
                               |          +-------+-------+
                               +----------+ Repository of |
                               |          |  identifiers  |
                               |          +-------+-------+
               2. Distribution |                  ^\
                               |                  | Match
                               v                  |
                     +---------+-------+          |
                     |      User of    |          |
                     |    identifier   +----------+
                     +-----------------+    3. Use

                  Figure 1: Typical Identifier Processes

Another variation is when a user gets the identifier of a resource (like a web site) to access securely, which is sometimes called a "reference identifier" [RFC6125] ๐ŸŒ The server hosting the resource then presents its identity at the time of use. In this case, the user application tries to match the presented identity against the reference identifier ๐Ÿ”

One key thing is that the identifier values used in generation, distribution, and use may all look different. For example, an identifier might be printed when it's generated, read out loud to a user over voice, and then used electronically. Because of that, the match process can get complicated ๐Ÿ˜ญ

It also gets more involved in lots of cases where the relationships between holders, repositories, and users are more layered. For example, when there's a hierarchy of web caches, each cache is kind of a repository too, and the match process is usually supposed to be the same as on the origin server ๐Ÿงš

Another thing to keep in mind: multiple identifiers can point to the same object (a resource, a human, a device, etc.) ๐ŸŽญ A human might have both a passport number and a driver's license number, and an RFC might be available at multiple locations (rfc-editor.org and ietf.org). In this document we focus on comparing two identifiers to see whether they're the same identifier, rather than comparing two different identifiers to see whether they refer to the same entity. (A few issues with the latter do get touched on in a couple of places, like Sections 3.1.4 and 3.3.6 ๐Ÿ’…)

1.1. Classes of Identifiers ๐ŸŒˆ

In this doc we'll refer to the following classes of identifiers:

  • Absolute ๐Ÿ”’ Identifiers that can be compared byte-by-byte for equality. Two identifiers with different bytes are defined to be different. For example, binary IP addresses are in this class.
  • Definite ๐ŸŽ€ Identifiers that have a single well-defined comparison algorithm. For example, URI scheme names are required to be US-ASCII [USASCII] and are defined to match case-insensitively. So the comparison is definite, since there's a well-specified algorithm (Section 9.2.1 of [RFC4790]) for doing a case-insensitive match among ASCII strings ๐Ÿค“
  • Indefinite ๐ŸŒ€ Identifiers that have no single well-defined comparison algorithm. For example, human names are in this class. Everyone might want the comparison tailored to their locale, for some definition of "locale". In some cases there are limited subsets of parties that could agree (for example, ASCII users might all agree on a common comparison algorithm, whereas users of other Roman-derived scripts, such as Turkish, may not). But identifiers often tend to leak out of those limited environments ๐Ÿ’€

1.2. Canonicalization โœจ

Okay so, the most common way to compare identifiers goes like this: you first turn each identifier into a canonical form (also called "canonicalization" or "normalization" ๐Ÿ’…), and then you check whether those canonical forms match bit for bit. Because of that, it is critical that every entity involved agrees on the same canonical form and uses the same canonicalization algorithm. Otherwise the whole comparison process isn't the same for everyone, and that's a mess ๐Ÿ˜ญ

Note that in some contexts, like internationalization, "canonicalization" and "normalization" have a precise meaning ๐Ÿค“. In this document, though, we use the two terms interchangeably in their more generic sense, meaning "converting to some standard form" ๐ŸŽ€.

Also, while the most popular comparison method includes canonicalization, you can compare things by defining an equivalence algorithm instead, where no single form counts as canonical ๐Ÿฆ‹. Honestly though, a canonical form is usually handy for other stuff too, like output, so in those cases just defining a canonical form is enough to define a comparison method โœจ.

2. Identifier Use in Security Policies and Decisions ๐Ÿ”

Identifiers like hostnames, URIs, and email addresses get used in security contexts to identify security principals (basically, entities that can be authenticated) and resources ๐ŸŒธ. They also identify other security parameters, like the types and values of claims ๐Ÿ’œ. Those identifiers then get used to make security decisions based on an identifier presented through some protocol. For example:

  • Authentication: a protocol might match a security principal's identifier to look up the expected keying material, and then match the keying material ๐Ÿ”‘.
  • Authorization: a protocol might match a resource name against some policy ๐Ÿ“œ. For example, it might look up an access control list (ACL) and then look up the security principal's identifier (or a surrogate for it) in that ACL ๐Ÿ‘‘.
  • Accounting: a system might create an accounting record for a security principal's identifier or resource name, and then later need to match a presented identifier to (for example) add new filtering rules based on those records, in order to stop an attack ๐Ÿ›ก๏ธ.

If the parties in a security decision use different matching algorithms for the same identifiers, then failure scenarios ranging from denial of service to elevation of privilege can result, as we will see ๐Ÿ’€.

This gets especially complicated with multiple parties and multiple protocols ๐Ÿ˜ฉ. For example, there are many scenarios where some form of "security token service" is used to grant a requester permission to access a resource, where the resource is held by a third party that relies on that security token service (see Figure 2) ๐ŸŽŸ๏ธ. The protocol used to request permission (e.g., Kerberos or OAuth) may be different from the protocol used to access the resource (e.g., HTTP) ๐ŸŒˆ. Opportunities for security problems pop up when two protocols define different comparison algorithms for the same type of identifier, or when a protocol is ambiguously specified and two endpoints (e.g., a security token service and a resource holder) implement different algorithms within the same protocol ๐Ÿ™ˆ.

      +----------+
      | security |
      |  token   |
      | service  |
      +----------+
           ^
           | 1. supply credentials and
           |    get token for resource
           |                                             +--------+
      +----------+  2. supply token and access resource  |resource|
      |requester |=------------------------------------->| holder |
      +----------+                                       +--------+

                 Figure 2: Simple Security Exchange

In many cases, the situation is even messier ๐Ÿ˜ตโ€๐Ÿ’ซ. With X.509 Public Key Infrastructure (PKIX) certificates [RFC6125], for example, the name in a certificate gets compared against names in ACLs or other things ๐Ÿ“‹. In the case of web site security, the name in the certificate gets compared to a portion of the URI that a user may have typed into a browser โŒจ๏ธ. The fact that so many different people are doing the typing, on so many different types of systems, makes the problem even harder ๐Ÿฅด.

And if you add the certificate enrollment step and the certificate issuance step, that's two more parties with a chance to adjust the encoding ๐Ÿ˜ฑ. Worse, the software supporting them might make changes that the parties don't even know are happening ๐Ÿซ .

2.1. False Positives and Negatives ๐Ÿ™ƒ

First, let's talk through what happens when the comparison algorithm makes errors. A "false positive" happens when two identifiers compare as equal but in reality refer to two different objects (e.g., security principals or resources) ๐Ÿ‘€. When privilege is granted on a match, a false positive results in an elevation of privilege, which means allowing an operation that should not have been permitted otherwise ๐Ÿšจ. When privilege is denied on a match (e.g., matching an entry in a block/deny list or a revocation list), a permissible operation gets denied ๐Ÿšซ. At best, this can cause worse performance (e.g., a cache miss or forcing redundant authentication), and at worst it can result in a denial of service ๐Ÿ˜–.

A "false negative" happens when two identifiers that in reality refer to the same thing compare as different, and the effects are the reverse of those for false positives ๐Ÿ”„. That is, when privilege is granted on a match, the result is at best worse performance and at worst a denial of service; when privilege is denied on a match, elevation of privilege results ๐Ÿ˜ฌ.

Figure 3 sums up these effects ๐Ÿ“Š.

                    | "Grant on match"       | "Deny on match"
     ---------------+------------------------+-----------------------
     False positive | Elevation of privilege | Denial of service
     ---------------+------------------------+-----------------------
     False negative | Denial of service      | Elevation of privilege
     ---------------+------------------------+-----------------------

         Figure 3: Worst Effects of False Positives/Negatives

When you design a comparison algorithm, you can usually tweak it to make false positives more likely and false negatives less likely, or the other way around โš–๏ธ. Which outcome is better depends on the context ๐Ÿคทโ€โ™€๏ธ.

Elevation of privilege is almost always seen as way worse than denial of service ๐Ÿ™…โ€โ™€๏ธ. So for URIs, for example, Section 6.1 of [RFC3986] states that "comparison methods are designed to minimize false negatives while strictly avoiding false positives" ๐Ÿ’–.

So URIs were defined with a "grant privilege on match" paradigm in mind, where it's critical to prevent elevation of privilege while minimizing denial of service ๐Ÿ›‘. Using URIs in a "deny privilege on match" system can therefore be problematic ๐Ÿ˜ฌ.

2.2. Hypothetical Example ๐Ÿ•ต๏ธโ€โ™€๏ธ

Okay, this example is kind of a tea spill ๐Ÿซ–. Both security principals and resources are identified using URIs. Foo Corp has paid example.com for access to the Stuff service. Foo Corp lets its employees create accounts on the Stuff service. Alice gets the account "http://example.com/Stuff/FooCorp/alice" and Bob gets "http://example.com/Stuff/FooCorp/bob" ๐Ÿง‘โ€๐Ÿ’ผ. It turns out, though, that Foo Corp's URI canonicalizer includes URI fragment components in comparisons, whereas example.com's does not, and Foo Corp does not disallow the # character in the account name ๐Ÿ˜ณ. So Chuck, a malicious employee of Foo Corp, asks to create an account at example.com with the name alice#stuff ๐Ÿ˜ˆ. Foo Corp's URI logic checks its records for accounts it has created with stuff and sees there is no account with the name alice#stuff. So in its records, it associates the account alice#stuff with Chuck, and will only issue tokens good for use with "http://example.com/Stuff/FooCorp/alice#stuff" to Chuck ๐Ÿ“.

Chuck, the attacker, goes to a security token service at Foo Corp and asks for a security token good for "http://example.com/Stuff/FooCorp/alice#stuff". Foo Corp issues the token, since Chuck is the legitimate owner (in Foo Corp's view) of the alice#stuff account ๐ŸŽซ. Chuck then submits the security token in a request to "http://example.com/Stuff/FooCorp/alice" ๐Ÿƒโ€โ™€๏ธ.

But example.com uses a URI canonicalizer that, for the purposes of checking equality, ignores fragments ๐Ÿ™ƒ. So when example.com looks in the security token to see if the requester has permission from Foo Corp to access the given account, it successfully matches the URI in the security token, "http://example.com/Stuff/FooCorp/alice#stuff", with the requested resource name "http://example.com/Stuff/FooCorp/alice" ๐Ÿ’ฅ.

Leveraging the inconsistencies between the canonicalizers used by Foo Corp and example.com, Chuck is able to successfully launch an elevation-of-privilege attack and access Alice's resource ๐Ÿ˜ฑ๐Ÿšจ.

Furthermore, consider an attacker using a similar corporation name, such as "foocorp" (or any variation containing a non-ASCII character that some humans might expect to represent the same corporation) ๐Ÿ‘ป. If the resource holder treats them as different but the security token service treats them as the same, then elevation of privilege can occur in this scenario as well ๐Ÿ’€.

3. Comparison Issues with Common Identifiers ๐Ÿงฉ

In this section, we walk through a number of common types of identifiers and discuss various comparison issues that may affect security whenever they are used to identify security principals or resources ๐Ÿ”. These examples illustrate common patterns that may come up with other types of identifiers too ๐Ÿฆ‹.

3.1. Hostnames ๐ŸŒธ

okay so hostnames (the dot-separated labels, like example.com) are literally everywhere ๐Ÿฆ‹ people use them straight up as identifiers, or as pieces inside URIs and email addresses. Another spot is Sections 7.2 and 7.3 of [RFC5280] (and updated in Section 3 of [RFC6818]), which cover PKIX certificates.

In this section we're gonna get into the issues with comparing strings that look like some kind of hostname ๐Ÿ‘€

First up, the word "hostname" is lowkey ambiguous ๐Ÿ’€ so any spec that uses it needs to say which definition it means. Some options are:

  • a. A Fully Qualified Domain Name (FQDN),
  • b. An FQDN that is associated with address records in the DNS,
  • c. The leftmost label in an FQDN, or
  • d. The leftmost label in an FQDN that is associated with address records.

Different places using different definitions is how you end up asking whether "example" and "example.com" are equal ๐Ÿ™ˆ so when you write new specs, be clear about which one you mean, bestie ๐Ÿ’…

Section 3 of [RFC6055] talks about the difference between a "hostname" and a "DNS name." The hostname is basically a subset of the DNS name, since it only uses a restricted set of characters (letters, digits, and hyphens) โœจ If one canonicalizer goes with "DNS name" and another goes with "hostname," a name could be valid in one and invalid in the other. As long as invalid identifiers are denied privilege, this difference won't lead to elevation of privilege ๐Ÿ”ฅ

Section 3.1 of [RFC1034] covers a "complete" domain name, which ends with a dot (like "example.com."), versus a multi-label relative name like "example.com" that assumes the root (".") is in the suffix search list ๐Ÿงš In most contexts these count as equal, but it can get messy if different entities in a security architecture read a relative domain name in different ways.

[IAB1123] briefly covers how murky it is whether a label counts as "alphabetic" (including how "alphabetic" should be read in an internationalized environment), and whether a hostname can be read as an IP address. We're gonna dig into that last one below ๐Ÿซถ

3.1.1. IPv4 Literals

Section 2.1 of [RFC1123] states:

   Whenever a user inputs the identity of an Internet host, it SHOULD
   be possible to enter either (1) a host domain name or (2) an IP
   address in dotted-decimal ("#.#.#.#") form.  The host SHOULD check
   the string syntactically for a dotted-decimal number before
   looking it up in the Domain Name System.

and

   This last requirement is not intended to specify the complete
   syntactic form for entering a dotted-decimal host number; that is
   considered to be a user-interface issue.

Now, the POSIX standard [IEEE-1003.1] defines inet_addr(), and it's giving chaos ๐Ÿ˜ญ its "IPv4 dotted decimal notation" allows not only strings like 10.0.1.2, but also octal, hexadecimal, and addresses with fewer than four parts. For example, 10.0.258, 0xA000102, and 012.0x102 all represent the same IPv4 address in standard "IPv4 dotted decimal" notation ๐Ÿ“ We'll call this the "loose" syntax of an IPv4 address literal.

Section 6.1 of [RFC3493] defines getaddrinfo() to support the same loose syntax as inet_addr():

   If the specified address family is AF_INET or AF_UNSPEC, address
   strings using Internet standard dot notation as specified in
   inet_addr() are valid.

But then Section 6.3 of that same RFC says the opposite vibe for inet_pton() ๐Ÿ™ƒ

   If the af argument of inet_pton() is AF_INET, the src string shall
   be in the standard IPv4 dotted-decimal form:

         ddd.ddd.ddd.ddd

   where "ddd" is a one to three digit decimal number between 0 and
   255.  The inet_pton() function does not accept other formats (such
   as the octal numbers, hexadecimal numbers, and fewer than four
   numbers that inet_addr() accepts).

As shown above, inet_pton() uses what we'll call the "strict" form of an IPv4 address literal. Some platforms also use the strict form with getaddrinfo() when the AI_NUMERICHOST flag is passed to it ๐Ÿ’…

Both the strict and loose forms are standard forms, so a protocol spec is still ambiguous if it just says a string is in the "standard IPv4 dotted decimal form" ๐Ÿ˜ฉ And because of these differences, names like 10.11.12 are ambiguous about whether they're an IP address or a hostname. Even 10.11.12.13 can be ambiguous, because of the SHOULD in the RFC 1123 text above, which makes it optional whether you treat it as an address or a DNS name ๐ŸŽ€

Protocols and data formats that can use addresses in string form for security purposes need to sort these ambiguities out โœจ For example, for the host component of URIs, Section 3.2.2 of [RFC3986] fixes the first ambiguity by only allowing the strict form, and fixes the second by saying it's considered an IPv4 address literal. New protocols and data formats should similarly consider using the strict form rather than the loose form, so they better match what users expect ๐Ÿฆ‹

A string might be valid under the "loose" definition but invalid under the "strict" one. As long as invalid identifiers are denied privilege, this difference won't result in elevation of privilege. Some protocols, though, use strings that can be either an IP address literal or a hostname. Those strings are at best Definite identifiers, and they often turn out to be Indefinite identifiers ๐Ÿฅบ (See Section 4.1 for more discussion.)

3.1.2. IPv6 Literals

IPv6 addresses have a wild variety of alternate but semantically identical string representations too, as defined in Section 2.2 of [RFC4291] and Section 2 of [RFC6874] ๐ŸŒˆ As discussed in Section 3.2.5 of [RFC5952], this causes problems in security contexts if the comparison (like in PKIX certificates) is done between strings instead of between the binary representations of addresses.

[RFC5952] specified a recommended canonical string format to try to fix this, but it may not be ubiquitously supported at present ๐Ÿซ  And when strings can contain non-ASCII characters, the same issues arise as with IPv4 literals (and even more, since hexadecimal and colons are allowed).

Here's the iconic part: (binary) IPv6 addresses are Absolute identifiers, but IPv6 address literals are Definite identifiers, since string-to-address conversion for IPv6 address literals is unambiguous ๐Ÿ‘‘

3.1.3. Internationalization

The IETF policy on character sets and languages [RFC2277] requires support for UTF-8 in protocols, so a lot of protocols now do support non-ASCII characters ๐ŸŒ When a hostname is sent in a UTF-8 field, there are a bunch of ways it could be encoded. For example, hostname labels might be encoded directly in UTF-8, or they might first be Punycode-encoded [RFC3492], or even percent-encoded from UTF-8 ๐Ÿ’–

For example, in URIs, Section 3.2.2 of [RFC3986] specifically allows percent-encoded UTF-8 characters in the hostname, as well as Internationalized Domain Names in Applications (IDNA) encoding [RFC3490] using the Punycode algorithm ๐Ÿง

Percent-encoding is unambiguous for hostnames, since the percent character can't appear in the strict definition of a "hostname," though it can appear in a DNS name ๐Ÿ™Œ

Punycode-encoded labels (or "A-labels"), on the other hand, can be ambiguous if hosts are actually allowed to be named with a name starting with "xn--", and that can cause false positives. It might be extremely unlikely in normal scenarios, but it still gives an attacker a possible vector ๐Ÿ˜ฑ

A hostname comparator needs to decide whether a Punycode-encoded label should or should not be considered a valid hostname label. And if it is, it also needs to decide whether it should match a label encoded in some other form, like a percent-encoded Unicode label (U-label).

For example, Section 3 of "Transport Layer Security (TLS) Extensions: Extension Definitions" [RFC6066] states:

   "HostName" contains the fully qualified DNS hostname of the
   server, as understood by the client.  The hostname is represented
   as a byte string using ASCII encoding without a trailing dot.
   This allows the support of internationalized domain names through
   the use of A-labels defined in [RFC5890].  DNS hostnames are case-
   insensitive.  The algorithm to compare hostnames is described in
   [RFC5890], Section 2.3.2.4.

For some more discussion of security issues that come up with internationalization, check out Section 4.2 and [TR36] ๐Ÿฆ‹

3.1.4. Resolution for Comparison

Some systems (specifically Java URLs [JAVAURL]) use the rule that if two hostnames resolve to the same IP address(es), then the hostnames are considered equal ๐Ÿค” That means the canonicalization algorithm involves name resolution, with an IP address being the canonical form.

For example, if resolution was done via DNS, and DNS contained:

                       example.com.  IN A 10.0.0.6
                       example.net.  CNAME example.com.
                       example.org.  IN A 10.0.0.6

then the algorithm might treat all three names as equal, even though the third name might refer to a different entity ๐Ÿ˜ญ

With the introduction of dynamic IP addresses; private IP addresses; multiple IP addresses per name; multiple address families (e.g., IPv4 vs. IPv6); devices that roam to new locations; commonly deployed DNS tricks that make the answer depend on things like the requester's location and the load on the server whose address is returned; etc., this method of comparison cannot be relied upon ๐Ÿ™…โ€โ™€๏ธ There's no guarantee that two names for the same host will resolve to the same IP addresses. There's also no guarantee that the addresses resolved refer to the same entity, like when the names resolve to private IP addresses. And there's no guarantee the system even has connectivity (or the willingness to wait for the delay) to resolve names at the time the answer is needed. The lifetime of the identifier, and of any cached state from a previous resolution, also affects security (see Section 4.4).

Also, a comparison mechanism that relies on resolving identifiers like hostnames to other identifiers like IP addresses leaks information about security decisions to outsiders if these queries are publicly observable ๐Ÿ‘€ (See [PRIVACY-CONS] for a deeper discussion of information disclosure.)

Finally, resolving two identifiers to figure out if they refer to the same entity can be thought of as a use of those identifiers, as opposed to actually comparing the identifiers themselves, which is the focus of this document โœจ

3.2. Port Numbers and Service Names ๐ŸŽ€

okay so port numbers and service names get the full deep dive in [RFC6335] ๐Ÿ’…. Historically there were three things floating around: port numbers, service names used in SRV records, and mnemonic identifiers for assigned port numbers (called port "keywords" at [IANA-PORT]) ๐ŸŒธ. The last two are now unified ๐Ÿซถ, and different protocols use one or more of these types inside their strings. For example, the common syntax that lots of URI schemes use lets you have port numbers but not service names. Some implementations of the getaddrinfo() API accept strings that can be either port numbers or port keywords (but not service names) ๐Ÿงš.

For protocols that use service names that have to be resolved, the issues are the same as the address resolution stuff in Section 3.1.4. On top of that, Section 5.1 of [RFC6335] clarifies that service names/port keywords must contain at least one letter. That way nobody gets confused with port numbers in strings where both are allowed ๐Ÿ”ฅ.

3.3. URIs ๐Ÿฆ‹

this section looks at URI issues that matter for security ๐Ÿ”. For example, Section 7.4 of [RFC5280] specifies how URIs in certificates get compared. URIs also show up in security-token-based access control systems like WS-*, SAML 2.0 [OASIS-SAMLv2-CORE], and OAuth Web Resource Authorization Profiles (WRAP) [OAuth-WRAP]. In those systems, a bunch of participants in the security infrastructure are identified by URIs โœจ. Requesters of security tokens are sometimes identified with URIs. The issuers of security tokens and the relying parties who are meant to consume them are frequently identified by URIs too. Claims in security tokens often have their types defined using URIs, and the values of the claims can be URIs as well ๐Ÿ’œ.

URIs are built from multiple components, and each one has its own rules. We'll go through each one in turn. But it's also important to know that there are multiple comparison algorithms ๐Ÿ‘€. Section 6.2 of [RFC3986] says:

A variety of methods are used in practice to test URI equivalence. These methods fall into a range, distinguished by the amount of processing required and the degree to which the probability of false negatives is reduced. As noted above, false negatives cannot be eliminated. In practice, their probability can be reduced, but this reduction requires more processing and is not cost-effective for all applications.
If this range of comparison practices is considered as a ladder, the following discussion will climb the ladder, starting with practices that are cheap but have a relatively higher chance of producing false negatives, and proceeding to those that have higher computational cost and lower risk of false negatives.

The ladder approach has pros and cons ๐Ÿชœ. On the plus side, some uses can optimize for security while others optimize for cost, so URIs can work for a really wide range of uses. The downside is that when different components in the same system take different approaches to the same identifiers, those inconsistencies can cause security issues ๐Ÿ˜ญ.

3.3.1. Scheme Component ๐ŸŒˆ

[RFC3986] defines URI schemes as case-insensitive US-ASCII, and Section 6.2.2.1 says scheme names should be normalized to lowercase characters.

New schemes can be defined over time. In general, though, two URIs with an unrecognized scheme cannot be safely compared. That's because the canonicalization and comparison rules for the other components may vary by scheme ๐Ÿ™ˆ. For example, a new URI scheme might have a default port of X, and without knowing that, a comparison algorithm can't tell whether "example.com" and "example.com:X" should match in the authority component. So, for security purposes, it's safest to treat unrecognized schemes as invalid identifiers. However, if the URIs are only used with a "grant access on match" paradigm, then unrecognized schemes can be supported by doing a generic case-sensitive comparison, at the expense of some false negatives ๐Ÿ“.

3.3.2. Authority Component ๐Ÿฐ

The authority component is scheme-specific, but lots of schemes follow a common syntax that allows for userinfo, host, and port.

3.3.2.1. Host ๐ŸŒท

Section 3.1 covers hostname issues in general. Section 3.2.2 of [RFC3986] also allows future changes using the IPvFuture production. Just like with IPv4 and IPv6 literals, IPvFuture formats can have multiple semantically identical string representations, and they may also be semantically identical to an IPv4 or IPv6 address. So false negatives may be common if IPvFuture is used ๐Ÿฅฒ.

3.3.2.2. Port ๐Ÿ”Œ

See the discussion in Section 3.2.

3.3.2.3. Userinfo ๐Ÿ‘ค

[RFC3986] defines the userinfo production, which lets you put arbitrary data about the user of the URI before '@' signs. For example, "ftp://alice:bob@example.com/bar" has the value "alice:bob" as its userinfo. When comparing URIs in a security context, you have to decide whether to treat the userinfo as significant or not. Some URI comparison services, for example, treat "ftp://alice:ick@example.com" and "ftp://example.com" as equal ๐Ÿ˜ณ.

When the userinfo is treated as significant, it comes with extra considerations (for example, whether or not it's case sensitive), which we cover in Section 3.4 ๐Ÿ’….

3.3.3. Path Component ๐Ÿ›ค๏ธ

[RFC3986] supports path segment values like "./" or "../" for relative URIs. As Section 6.2.2.3 of [RFC3986] explains, they're only meant for use within a reference that's relative to some other base URI. Even so, Section 5.2.4 of [RFC3986] defines an algorithm to remove them as part of URI normalization ๐Ÿงน.

Unless a scheme says otherwise, the path component is defined to be case sensitive. But if the resource is stored and accessed through a filesystem with case-insensitive paths, there will be lots of paths that point to the same resource. So false negatives can be common in this case ๐Ÿ™ƒ.

3.3.4. Query Component โ“

Is "http://example.com/foo" equal to "http://example.com/foo?", or to "http://example.com/foo?bar"? Each of these is a valid question, and the spec doesn't settle it ๐Ÿคทโ€โ™€๏ธ.

It's also unspecified whether the order of values matters. For example, should "http://example.com/blah?ick=bick&foo=bar" be considered equal to "http://example.com/blah?foo=bar&ick=bick"? And if a domain name is allowed to appear in a query component (for example, in a reference to another URI), then the same issues from Section 3.1 apply ๐Ÿ˜ตโ€๐Ÿ’ซ.

3.3.5. Fragment Component ๐Ÿงฉ

some URI formats include fragment identifiers. These are typically handles to locations within a resource, used for local reference. A classic example is fragments in HTTP URIs, where "http://example.com/blah.html#ick" means retrieve the resource "http://example.com/blah.html" and, once it has arrived locally, find the HTML anchor named "ick" and display that ๐Ÿ“„.

So, for example, when a user clicks the link "http://example.com/blah.html#baz", a browser will check its cache by doing a URI comparison for "http://example.com/blah.html". If the resource is in the cache, a match is declared โšก.

That's why comparisons for security purposes typically ignore the fragment component and treat all fragments as equal to the full resource. But if you were actually trying to compare the piece of a resource that the fragment identifier points to, ignoring it would lead to potential false positives ๐Ÿšจ.

3.3.6. Resolution for Comparison ๐Ÿ”

It might be tempting to define a URI comparison algorithm based on whether URIs resolve to the same content, kind of like resolving hostnames as described in Section 3.1.4. But that would run into similar problems ๐Ÿซ . Content can change dynamically over time, or depend on things like the requester's location. There might also be no external connectivity at the time or place the comparison happens, and it can add potentially undesirable delay, etc.

Plus, as Section 3.1.4 noted, resolution leaks information about security decisions to outsiders if the queries are publicly observable ๐Ÿ‘๏ธ.

3.4. Email Address-Like Identifiers ๐Ÿ’Œ

Section 3.4.1 of [RFC5322] defines the syntax of an email address-like identifier, and Section 3.2 of [RFC6532] updates it to support internationalization ๐ŸŒ. Section 7.5 of [RFC5280] goes further into using internationalized email addresses in certificates.

As for the security impact of internationalized email headers, [RFC6532] points to Section 14 of [RFC6530], which discusses a lot of issues that come with internationalization ๐Ÿง.

Email address-like identifiers have a local part and a domain part. The domain part has basically the same issues as hostnames, which we covered earlier in Section 3.1 ๐Ÿ .

The local part is left for each domain to define. People super commonly use email addresses as usernames on sites like banks or shopping sites, but the site doesn't know whether foo@example.com is the same person as FOO@example.com ๐Ÿค”. So email address-like identifiers are typically Indefinite identifiers.

To avoid false positives, some security mechanisms (like those described in [RFC5280]) compare the local part using an exact match. So, like URIs, email address-like identifiers are designed for grant-on-match security schemes, not deny-on-match schemes ๐ŸŽฏ.

Also, when these identifiers are actually used as email addresses, Section 2.4 of [RFC5321] says the local part of a mailbox must be treated as case sensitive. But if a mailbox is stored and accessed through a filesystem with case-insensitive paths, there may be many paths that point to the same mailbox. So false negatives can be common in this case ๐Ÿ“ฌ.

4. General Issues โœจ

4.1. Conflation ๐Ÿซง

there are a bunch of examples (some in the sections above) of strings that conflate two types of identifiers. They use some heuristic to try to figure out which type of identifier is meant. Similarly, two ways of encoding the same type of identifier might get conflated within the same string ๐ŸŒ€.

Some examples include:

  1. A string that might be an IPv4 address literal or an IPv6 address literal
  2. A string that might be an IP address literal or a hostname
  3. A string that might be a port number or a service name
  4. A DNS label that might be literal or be Punycode-encoded

Strings that allow this kind of conflation can only be considered Definite if there's a well-defined rule for figuring out which identifier type is meant ๐Ÿง . One way to do that is to make sure the valid syntax for the two is disjoint (for example, telling IPv4 and IPv6 address literals apart by the use of colons in the latter) ๐ŸŽ€. A second way is to define a precedence rule that makes some identifiers inaccessible via a conflated string (for example, a host literally named "xn--de-jg4avhby1noc0d" may be inaccessible because the "xn--" prefix denotes Punycode encoding) ๐Ÿ™ˆ. In some cases, that inaccessible space may be reserved so the actual set of identifiers in use is unambiguous. For example, Section 2.5.5.2 of [RFC4291] defines a range of the IPv6 address space for representing IPv4 addresses ๐Ÿ’œ.

4.2. Internationalization โœจ

okay so besides the hostname drama from Section 3.1.3, there's a whole pile of internationalization issues that show up for loads of Definite and Indefinite identifiers ๐ŸŒ๐Ÿ’…

first, DNS has no way to tell whether two strings that aren't identical would look equivalent to a human ๐Ÿ˜ญ even plain US-ASCII is messy here: think regional spellings like "color" vs "colour". then there's the non-English stuff, like partially numeric strings in Arabic script contexts, and Chinese strings in Simplified and Traditional forms, and so on. trying to generate those alternate forms with an algorithm could give you false positives, and that can actually hurt security ๐Ÿ™ˆ

second, some strings look almost exactly like other strings ๐Ÿ‘€ so if someone makes a security call by eyeballing it, there are tons of chances to get it wrong. visual inspection is just not reliable for security, periodt ๐Ÿ’€ confusability also makes identifiers harder to use when they're shared on visual media. the same kind of problem pops up with audio (like radio, or accessibility for blind users) instead of a visual medium ๐ŸŽง and here's the spicy part: when strings conflate two types of identifiers (see Section 4.1), letting in non-ASCII characters can make one type of identifier look like a different type to a human ๐Ÿ˜ฑ for example, characters that look like digits and dots might seem like an IPv4 literal, especially to someone who expects digits to show up in their own script. so conflation really does increase the chance of confusion ๐Ÿซ 

third, figuring out whether a string is a valid identifier should typically happen after canonicalization, or as part of it โœจ otherwise an attacker could use the canonicalization step to sneak in delimiters, like an @ in an email-address-like identifier or a . in a hostname. the ways they could do that include percent encoding, Normalization Form KC (NFKC), or non-shortest-form UTF-8 ๐Ÿ•ต๏ธโ€โ™€๏ธ

any case-insensitive comparisons need to define how the comparison is done, because it may vary by the locale of the endpoint. so using case-insensitive comparisons in general often leaves identifiers Indefinite, or Definite if the legal character set is restricted (e.g., to US-ASCII).

for a more visual take on a lot of this, check out [WEBER] ๐ŸŽ€

last one: the set of permitted characters and the canonical form of those characters (and therefore the canonicalization algorithm) sometimes differ between protocols, even when the goal is to use the same identifier, like when one protocol passes identifiers to another ๐Ÿ” see [RFC6885] for more on that ๐Ÿฆ‹


4.3. Scope ๐ŸŒ

another issue pops up when an identifier isn't globally unique, like localhost or 10.11.12.13 ๐Ÿ™ƒ Section 1.1 of [RFC3986] says:

URIs have a global scope and are interpreted consistently regardless of context, though the result of that interpretation may be in relation to the end-user's context. For example, "http://localhost/" has the same interpretation for every user of that reference, even though the network interface corresponding to "localhost" may be different for each end-user: interpretation is independent of access.

so whenever a non-globally-unique identifier gets passed to an entity outside its scope of uniqueness, it ends up pointing at a different resource, and that can cause a false positive ๐Ÿ˜ฌ the usual fix is to pair it with some other unique identifier for its context. for example, alice might uniquely identify a user inside one system, but you need alice@example.com to uniquely identify that user outside of it ๐Ÿ’–

it's also worth knowing that IPv6 addresses which aren't globally scoped can be written with, or associated with, a "zone ID" to name the context (see [RFC4007] for more info) โœจ but zone IDs are only unique within a host, so they usually narrow the scope of uniqueness rather than widen it ๐Ÿงš


4.4. Temporality โณ

identifiers are often not unique across all of time ๐Ÿ•ฐ๏ธ they usually have some lifetime, and after that they can be reassigned to someone else. for example, bob@example.com might belong to an employee of the Example company, but if he leaves and a new Bob gets hired, that same identifier could get reused ๐Ÿซฃ another one: IP address 203.0.113.1 could be assigned to one subscriber and then later reassigned to a different subscriber ๐ŸŒ security issues can come up if updates don't happen in every entity that stores the identifier, like an access control list (see Section 2) or a resolution cache (see Section 3.1.4) ๐Ÿšจ

this is similar to the scope issue from Section 4.3, except the scope of uniqueness is temporal instead of topological โญ


5. Security Considerations ๐Ÿ”

this entire document is about security considerations ๐Ÿ˜ค๐Ÿ’œ

to keep elevation of privilege issues to a minimum, any system that needs to use both deny and allow operations inside the same identifier space should avoid using Indefinite identifiers in security comparisons ๐Ÿ›ก๏ธ

to keep future security risks down, any new identifiers being designed should specify an Absolute or Definite comparison algorithm ๐Ÿ“ and if extensibility is allowed (like new schemes in URIs), the comparison algorithm should stay invariant so unrecognized extensions can still be compared ๐Ÿงฉ basically, you can cut security risk by specifying the comparison algorithm and sorting out any ambiguities this document points out (e.g., "standard dotted decimal") ๐Ÿ’…

some issues, like unrecognized extensions, can be mitigated by treating those identifiers as invalid โŒ validity checking is talked about more in [RFC3696] ๐ŸŽ€

the hardest stuff comes up when multiple protocols get used together, like in Figure 2, where the protocols are defined or implemented using different comparison algorithms ๐Ÿ˜ตโ€๐Ÿ’ซ if you're building an architecture that uses several of these protocols, designers should pay attention to any differences in comparison algorithms among them so they fully understand the security risks โš ๏ธ how to handle those risks in current systems is still an area for future work ๐Ÿ”ฎ


6. Acknowledgements ๐Ÿซถ

Yaron Goland contributed to the discussion on URIs ๐Ÿ’ซ Patrik Faltstrom contributed to the background on identifiers ๐ŸŒธ John Klensin contributed text in a number of different sections ๐Ÿ‘‘ extra helpful feedback and suggestions came from Bernard Aboba, Fred Baker, Leslie Daigle, Mark Davis, Jeff Hodges, Bjoern Hoehrmann, Russ Housley, Christian Huitema, Magnus Nystrom, Tom Petch, and Chris Weber ๐Ÿฅนโœจ


7. IAB Members at the Time of Approval ๐ŸŒˆ

  • Bernard Aboba
  • Jari Arkko
  • Marc Blanchet
  • Ross Callon
  • Alissa Cooper
  • Spencer Dawkins
  • Joel Halpern
  • Russ Housley
  • David Kessens
  • Danny McPherson
  • Jon Peterson
  • Dave Thaler
  • Hannes Tschofenig

8. Informative References โœจ

okay bestie, last stretch ๐ŸŽ€ here are all the receipts for the stuff this doc leans on. every single one is listed below exactly as written so nobody can say we fudged it ๐Ÿ’…

[IAB1123]  Internet Architecture Board, "IAB Statement: 'The
           interpretation of rules in the ICANN gTLD Applicant
           Guidebook'", February 2012, <http://www.iab.org/documents/
           correspondence-reports-documents/2012-2/iab-statement-the-
           interpretation-of-rules-in-the-icann-gtld-applicant-
           guidebook>.

[IANA-PORT]
           IANA, "Service Name and Transport Protocol Port Number
           Registry", March 2013,
           <http://www.iana.org/assignments/service-names-port-
           numbers/>.

[IEEE-1003.1]
           IEEE and The Open Group, "The Open Group Base
           Specifications, Issue 6, IEEE Std 1003.1, 2004 Edition",
           IEEE Std 1003.1, 2004.

[JAVAURL]  Oracle, "Class URL", Java(TM) Platform Standard Ed. 7,
           2013, <http://docs.oracle.com/javase/7/docs/api/java/net/
           URL.html>.

[OASIS-SAMLv2-CORE]
           Cantor, S., Ed., Kemp, J., Ed., Philpott, R., Ed., and E.
           Maler, Ed., "Assertions and Protocols for the OASIS
           Security Assertion Markup Language (SAML) V2.0", OASIS
           Standard saml-core-2.0-os, March 2005,
           <http://docs.oasis-open.org/security/saml/v2.0/
           saml-core-2.0-os.pdf>.

[OAuth-WRAP]
           Hardt, D., Ed., Tom, A., Eaton, B., and Y. Goland, "OAuth
           Web Resource Authorization Profiles", Work in Progress,
           January 2010.

[PRIVACY-CONS]
           Cooper, A., Tschofenig, H., Aboba, B., Peterson, J.,
           Morris, J., Hansen, M., and R. Smith, "Privacy
           Considerations for Internet Protocols", Work in Progress,
           April 2013.

[RFC1034]  Mockapetris, P., "Domain names - concepts and facilities",
           STD 13, RFC 1034, November 1987.

[RFC1123]  Braden, R., "Requirements for Internet Hosts - Application
           and Support", STD 3, RFC 1123, October 1989.

[RFC2277]  Alvestrand, H.T., "IETF Policy on Character Sets and
           Languages", BCP 18, RFC 2277, January 1998.

[RFC3490]  Faltstrom, P., Hoffman, P., and A. Costello,
           "Internationalizing Domain Names in Applications (IDNA)",
           RFC 3490, March 2003.

[RFC3492]  Costello, A., "Punycode: A Bootstring encoding of Unicode
           for Internationalized Domain Names in Applications
           (IDNA)", RFC 3492, March 2003.

[RFC3493]  Gilligan, R., Thomson, S., Bound, J., McCann, J., and W.
           Stevens, "Basic Socket Interface Extensions for IPv6",
           RFC 3493, February 2003.

[RFC3696]  Klensin, J., "Application Techniques for Checking and
           Transformation of Names", RFC 3696, February 2004.

[RFC3986]  Berners-Lee, T., Fielding, R., and L. Masinter, "Uniform
           Resource Identifier (URI): Generic Syntax", STD 66,
           RFC 3986, January 2005.

[RFC4007]  Deering, S., Haberman, B., Jinmei, T., Nordmark, E., and
           B. Zill, "IPv6 Scoped Address Architecture", RFC 4007,
           March 2005.

[RFC4291]  Hinden, R. and S. Deering, "IP Version 6 Addressing
           Architecture", RFC 4291, February 2006.

[RFC4790]  Newman, C., Duerst, M., and A. Gulbrandsen, "Internet
           Application Protocol Collation Registry", RFC 4790,
           March 2007.

[RFC4949]  Shirey, R., "Internet Security Glossary, Version 2",
           RFC 4949, August 2007.

[RFC5280]  Cooper, D., Santesson, S., Farrell, S., Boeyen, S.,
           Housley, R., and W. Polk, "Internet X.509 Public Key
           Infrastructure Certificate and Certificate Revocation List
           (CRL) Profile", RFC 5280, May 2008.

[RFC5321]  Klensin, J., "Simple Mail Transfer Protocol", RFC 5321,
           October 2008.

[RFC5322]  Resnick, P., Ed., "Internet Message Format", RFC 5322,
           October 2008.

[RFC5952]  Kawamura, S. and M. Kawashima, "A Recommendation for IPv6
           Address Text Representation", RFC 5952, August 2010.

[RFC6055]  Thaler, D., Klensin, J., and S. Cheshire, "IAB Thoughts on
           Encodings for Internationalized Domain Names", RFC 6055,
           February 2011.

[RFC6066]  Eastlake, D., "Transport Layer Security (TLS) Extensions:
           Extension Definitions", RFC 6066, January 2011.

[RFC6125]  Saint-Andre, P. and J. Hodges, "Representation and
           Verification of Domain-Based Application Service Identity
           within Internet Public Key Infrastructure Using X.509
           (PKIX) Certificates in the Context of Transport Layer
           Security (TLS)", RFC 6125, March 2011.

[RFC6335]  Cotton, M., Eggert, L., Touch, J., Westerlund, M., and S.
           Cheshire, "Internet Assigned Numbers Authority (IANA)
           Procedures for the Management of the Service Name and
           Transport Protocol Port Number Registry", BCP 165,
           RFC 6335, August 2011.

[RFC6530]  Klensin, J. and Y. Ko, "Overview and Framework for
           Internationalized Email", RFC 6530, February 2012.

[RFC6532]  Yang, A., Steele, S., and N. Freed, "Internationalized
           Email Headers", RFC 6532, February 2012.

[RFC6818]  Yee, P., "Updates to the Internet X.509 Public Key
           Infrastructure Certificate and Certificate Revocation List
           (CRL) Profile", RFC 6818, January 2013.

[RFC6874]  Carpenter, B., Cheshire, S., and R. Hinden, "Representing
           IPv6 Zone Identifiers in Address Literals and Uniform
           Resource Identifiers", RFC 6874, February 2013.

[RFC6885]  Blanchet, M. and A. Sullivan, "Stringprep Revision and
           Problem Statement for the Preparation and Comparison of
           Internationalized Strings (PRECIS)", RFC 6885, March 2013.

[TR36]     Unicode Consortium, "Unicode Security Considerations",
           Unicode Technical Report #36, Revision 11, July 2012,
           <http://www.unicode.org/reports/tr36/>.

[USASCII]  American National Standards Institute, "Coded Character
           Sets -- 7-bit American Standard Code for Information
           Interchange (7-bit ASCII)", ANSI X3.4, 1986.

[WEBER]    Weber, C., "Attacking Software Globalization", March 2010,
           <http://www.lookout.net/files/
           Chris_Weber_Character%20Transformations%20v1.7_IUC33.pdf>.

Author's Address ๐Ÿ’Œ

Dave Thaler (editor)
Microsoft Corporation
One Microsoft Way
Redmond, WA  98052
USA

Phone: +1 425 703 8835
EMail: dthaler@microsoft.com
๐Ÿ“ฆ where this page comes from