version2.rst 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. .. _rfc4122.version2:
  2. =======================
  3. Version 2: DCE Security
  4. =======================
  5. .. tip::
  6. DCE Security UUIDs are so-called because they were defined as part of the
  7. "Authentication and Security Services" for the `Distributed Computing
  8. Environment`_ (DCE) in the early 1990s.
  9. Version 2 UUIDs are not widely used. See :ref:`rfc4122.version2.problems`
  10. before deciding whether to use them.
  11. Like a :ref:`version 1 UUID <rfc4122.version1>`, a version 2 UUID uses the
  12. current time, along with the MAC address (or *node*) for a network interface on
  13. the local machine. Additionally, a version 2 UUID replaces the low part of the
  14. time field with a local identifier such as the user ID or group ID of the local
  15. account that created the UUID. This serves three purposes:
  16. 1. You can know *when* the identifier was created (see
  17. :ref:`rfc4122.version2.timestamp-problems`).
  18. 2. You can know *where* the identifier was created.
  19. 3. You can know *who* created the identifier.
  20. In a distributed system, these three pieces of information can be valuable. Not
  21. only is there no need for a central authority to generate identifiers, but you
  22. can determine what nodes in your infrastructure created the UUIDs, at what time
  23. they were created, and the account on the machine that created them.
  24. By default, ramsey/uuid will attempt to look up a MAC address for the machine it
  25. is running on, using this value as the node. If it cannot find a MAC address, it
  26. will generate a random node.
  27. .. code-block:: php
  28. :caption: Use a domain to generate a version 2, DCE Security UUID
  29. :name: rfc4122.version2.example
  30. use Ramsey\Uuid\Uuid;
  31. $uuid = Uuid::uuid2(Uuid::DCE_DOMAIN_PERSON);
  32. printf(
  33. "UUID: %s\nVersion: %d\nDate: %s\nNode: %s\nDomain: %s\nID: %s\n",
  34. $uuid->toString(),
  35. $uuid->getFields()->getVersion(),
  36. $uuid->getDateTime()->format('r'),
  37. $uuid->getFields()->getNode()->toString(),
  38. $uuid->getLocalDomainName(),
  39. $uuid->getLocalIdentifier()->toString()
  40. );
  41. This will generate a version 2 UUID and print out its string representation, the
  42. time the UUID was created, and the node used to create it, as well as the name
  43. of the local domain specified and the local domain identifier (in this case, a
  44. `POSIX`_ UID, automatically obtained from the local machine).
  45. It will look something like this:
  46. .. code-block:: text
  47. UUID: 000001f5-5e9a-21ea-9e00-0242ac130003
  48. Version: 2
  49. Date: Thu, 05 Mar 2020 04:30:10 +0000
  50. Node: 0242ac130003
  51. Domain: person
  52. ID: 501
  53. Just as with version 1 UUIDs, you may provide custom values for version 2 UUIDs,
  54. including local identifier, node, and clock sequence.
  55. .. code-block:: php
  56. :caption: Provide custom identifier, node, and clock sequence to create a
  57. version 2, DCE Security UUID
  58. :name: rfc4122.version2.custom-example
  59. use Ramsey\Uuid\Provider\Node\StaticNodeProvider;
  60. use Ramsey\Uuid\Type\Hexadecimal;
  61. use Ramsey\Uuid\Type\Integer;
  62. use Ramsey\Uuid\Uuid;
  63. $localId = new Integer(1001);
  64. $nodeProvider = new StaticNodeProvider(new Hexadecimal('121212121212'));
  65. $clockSequence = 63;
  66. $uuid = Uuid::uuid2(
  67. Uuid::DCE_DOMAIN_ORG,
  68. $localId,
  69. $nodeProvider->getNode(),
  70. $clockSequence
  71. );
  72. .. tip::
  73. Version 2 UUIDs generated in ramsey/uuid are instances of UuidV2. Check out
  74. the :php:class:`Ramsey\\Uuid\\Rfc4122\\UuidV2` API documentation to learn
  75. more about what you can do with a UuidV2 instance.
  76. .. _rfc4122.version2.domains:
  77. Domains
  78. #######
  79. The *domain* value tells what the local identifier represents.
  80. If using the *person* or *group* domains, ramsey/uuid will attempt to look up
  81. these values from the local machine. On `POSIX`_ systems, it will use ``id -u``
  82. and ``id -g``, respectively. On Windows, it will use ``whoami`` and ``wmic``.
  83. The *org* domain is site-defined. Its intent is to identify the organization
  84. that generated the UUID, but since this can have different meanings for
  85. different companies and projects, you get to define its value.
  86. .. list-table:: DCE Security Domains
  87. :widths: 30 70
  88. :align: center
  89. :header-rows: 1
  90. :name: rfc4122.version2.table-domains
  91. * - Constant
  92. - Description
  93. * - :php:const:`Uuid::DCE_DOMAIN_PERSON <Ramsey\\Uuid\\Uuid::DCE_DOMAIN_PERSON>`
  94. - The local identifier refers to a *person* (e.g., UID).
  95. * - :php:const:`Uuid::DCE_DOMAIN_GROUP <Ramsey\\Uuid\\Uuid::DCE_DOMAIN_GROUP>`
  96. - The local identifier refers to a *group* (e.g., GID).
  97. * - :php:const:`Uuid::DCE_DOMAIN_ORG <Ramsey\\Uuid\\Uuid::DCE_DOMAIN_ORG>`
  98. - The local identifier refers to an *organization* (this is site-defined).
  99. .. note::
  100. According to section 5.2.1.1 of `DCE 1.1: Authentication and Security Services
  101. <https://publications.opengroup.org/c311>`_, the domain "can potentially hold
  102. values outside the range [0, 2\ :sup:`8` -- 1]; however, the only values
  103. currently registered are in the range [0, 2]."
  104. As a result, ramsey/uuid supports only the *person*, *group*, and *org*
  105. domains.
  106. .. _rfc4122.version2.nodes:
  107. Custom and Random Nodes
  108. #######################
  109. In the :ref:`example above <rfc4122.version2.custom-example>`, we provided a
  110. custom node when generating a version 2 UUID. You may also generate random
  111. node values.
  112. To learn more, see the :ref:`rfc4122.version1.custom` and
  113. :ref:`rfc4122.version1.random` sections under :ref:`rfc4122.version1`.
  114. .. _rfc4122.version2.clock:
  115. Clock Sequence
  116. ##############
  117. In a version 2 UUID, the clock sequence serves the same purpose as in a version
  118. 1 UUID. See :ref:`rfc4122.version1.clock` to learn more.
  119. .. warning::
  120. The clock sequence in a version 2 UUID is a 6-bit number. It supports values
  121. from 0 to 63. This is different from the 14-bit number used by version 1
  122. UUIDs.
  123. See :ref:`rfc4122.version2.uniqueness-problems` to understand how this
  124. affects version 2 UUIDs.
  125. .. _rfc4122.version2.problems:
  126. Problems With Version 2 UUIDs
  127. #############################
  128. Version 2 UUIDs can be useful for the data they contain. However, there are
  129. trade-offs in choosing to use them.
  130. .. _rfc4122.version2.privacy-problems:
  131. Privacy
  132. -------
  133. Unless using a randomly-generated node, version 2 UUIDs use the MAC address for
  134. a local hardware interface as the node value. In addition, they use a local
  135. identifier --- usually an account or group ID. Some may consider the use of
  136. these identifying features a breach of privacy. The use of a timestamp further
  137. complicates the issue, since these UUIDs could be used to identify a user
  138. account on a specific machine at a specific time.
  139. If you don't need an identifier with a local identifier and timestamp value
  140. embedded in it, see :ref:`rfc4122.version4` to learn about random UUIDs.
  141. .. _rfc4122.version2.uniqueness-problems:
  142. Limited Uniqueness
  143. ------------------
  144. With the inclusion of the local identifier and domain comes a serious limitation
  145. in the number of unique UUIDs that may be created. This is because:
  146. 1. The local identifier replaces the lower 32 bits of the timestamp.
  147. 2. The domain replaces the lower 8 bits of the clock sequence.
  148. As a result, the timestamp advances --- the clock *ticks* --- only once every
  149. 429.49 seconds (about 7 minutes). This means the clock sequence is important to
  150. ensure uniqueness, but since the clock sequence is only 6 bits, compared to 14
  151. bits for version 1 UUIDs, **only 64 unique UUIDs per combination of node,
  152. domain, and identifier may be generated per 7-minute tick of the clock**.
  153. You can overcome this lack of uniqueness by using a
  154. :ref:`random node <rfc4122.version2.nodes>`, which provides 47 bits of
  155. randomness to the UUID --- after setting the unicast/multicast bit (see
  156. discussion on :ref:`rfc4122.version1.custom`) --- increasing the number of UUIDs
  157. per 7-minute clock tick to 2\ :sup:`53` (or 9,007,199,254,740,992), at the
  158. expense of remaining locally unique.
  159. .. note::
  160. This lack of uniqueness did not present a problem for DCE, since:
  161. [T]he security architecture of DCE depends upon the uniqueness of
  162. security-version UUIDs *only within the context of a cell*; that is,
  163. only within the context of the local [Registration Service's]
  164. (persistent) datastore, and that degree of uniqueness can be guaranteed
  165. by the RS itself (namely, the RS maintains state in its datastore, in
  166. the sense that it can always check that every UUID it maintains is
  167. different from all other UUIDs it maintains). In other words, while
  168. security-version UUIDs are (like all UUIDs) specified to be "globally
  169. unique in space and time", security is not compromised if they are
  170. merely "locally unique per cell".
  171. -- `DCE 1.1: Authentication and Security Services, section 5.2.1.1
  172. <https://publications.opengroup.org/c311>`_
  173. .. _rfc4122.version2.timestamp-problems:
  174. Lossy Timestamps
  175. ----------------
  176. Version 2 UUIDs are generated in the same way as version 1 UUIDs, but the low
  177. part of the timestamp (the ``time_low`` field) is replaced by a 32-bit integer
  178. that represents a local identifier. Because of this, not only do version 2 UUIDs
  179. have :ref:`limited uniqueness <rfc4122.version2.uniqueness-problems>`, but they
  180. also lack time precision.
  181. When reconstructing the timestamp to return a `DateTimeInterface`_ instance from
  182. :php:meth:`UuidV2::getDateTime() <Ramsey\\Uuid\\Rfc4122\\UuidV2::getDateTime>`,
  183. we replace the 32 lower bits of the timestamp with zeros, since the local
  184. identifier should not be part of the timestamp. This results in a loss of
  185. precision, causing the timestamp to be off by a range of 0 to 429.4967295
  186. seconds (or 7 minutes, 9 seconds, and 496,730 microseconds).
  187. When using version 2 UUIDs, treat the timestamp as an approximation. At worst,
  188. it could be off by about 7 minutes.
  189. .. hint::
  190. If the value 429.4967295 looks familiar, it's because it directly
  191. corresponds to 2\ :sup:`32` -- 1, or ``0xffffffff``. The local identifier is
  192. 32-bits, and we have set each of these bits to 0, so the maximum range of
  193. timestamp drift is ``0x00000000`` to ``0xffffffff`` (counted in
  194. 100-nanosecond intervals).
  195. .. _Distributed Computing Environment: https://en.wikipedia.org/wiki/Distributed_Computing_Environment
  196. .. _POSIX: https://en.wikipedia.org/wiki/POSIX
  197. .. _DateTimeInterface: https://www.php.net/datetimeinterface