Skip to content

Commit 3113fce

Browse files
committed
feature symfony#38333 [Uid] make UUIDv6 always return truly random nodes to prevent leaking the MAC of the host (nicolas-grekas)
This PR was merged into the 5.2-dev branch. Discussion ---------- [Uid] make UUIDv6 always return truly random nodes to prevent leaking the MAC of the host | Q | A | ------------- | --- | Branch? | master | Bug fix? | no | New feature? | yes | Deprecations? | no | Tickets | - | License | MIT | Doc PR | - As explained in http://gh.peabody.io/uuidv6/, the wording of the UUIDv1 spec suggests that using the MAC of the host is preferred to compute the "node" field of UUIDs. This is what the uuid extension does, and the reason why the 12 last chars of the UUIDv1 it generates are stable. But this is a privacy leak. There are stories in the wild about how knowing the MAC has been abused in the past. UUIDv6 prefers putting a secure random number there. So here is the PR to do so. Commits ------- b9c61ca [Uid] make UUIDv6 always return truly random nodes to prevent leaking the MAC of the host
2 parents a429dee + b9c61ca commit 3113fce

File tree

3 files changed

+32
-1
lines changed

3 files changed

+32
-1
lines changed

src/Symfony/Component/Uid/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
CHANGELOG
22
=========
33

4+
5.2.0
5+
-----
6+
7+
* made UUIDv6 always return truly random node fields to prevent leaking the MAC of the host
8+
49
5.1.0
510
-----
611

src/Symfony/Component/Uid/Tests/UuidTest.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,14 @@ public function testV6()
8989
$this->assertSame('3499710062d0', $uuid->getNode());
9090
}
9191

92+
public function testV6IsSeeded()
93+
{
94+
$uuidV1 = Uuid::v1();
95+
$uuidV6 = Uuid::v6();
96+
97+
$this->assertNotSame(substr($uuidV1, 24), substr($uuidV6, 24));
98+
}
99+
92100
public function testBinary()
93101
{
94102
$uuid = new UuidV4(self::A_UUID_V4);

src/Symfony/Component/Uid/UuidV6.php

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
/**
1515
* A v6 UUID is lexicographically sortable and contains a 60-bit timestamp and 62 extra unique bits.
1616
*
17+
* Unlike UUIDv1, this implementation of UUIDv6 doesn't leak the MAC address of the host.
18+
*
1719
* @experimental in 5.1
1820
*
1921
* @author Nicolas Grekas <[email protected]>
@@ -22,11 +24,27 @@ class UuidV6 extends Uuid
2224
{
2325
protected const TYPE = 6;
2426

27+
private static $seed;
28+
2529
public function __construct(string $uuid = null)
2630
{
2731
if (null === $uuid) {
2832
$uuid = uuid_create(\UUID_TYPE_TIME);
29-
$this->uid = substr($uuid, 15, 3).substr($uuid, 9, 4).$uuid[0].'-'.substr($uuid, 1, 4).'-6'.substr($uuid, 5, 3).substr($uuid, 18);
33+
$this->uid = substr($uuid, 15, 3).substr($uuid, 9, 4).$uuid[0].'-'.substr($uuid, 1, 4).'-6'.substr($uuid, 5, 3).substr($uuid, 18, 6);
34+
35+
// uuid_create() returns a stable "node" that can leak the MAC of the host, but
36+
// UUIDv6 prefers a truly random number here, let's XOR both to preserve the entropy
37+
38+
if (null === self::$seed) {
39+
self::$seed = [random_int(0, 0xffffff), random_int(0, 0xffffff)];
40+
}
41+
42+
$node = unpack('N2', hex2bin('00'.substr($uuid, 24, 6)).hex2bin('00'.substr($uuid, 30)));
43+
44+
$this->uid .= sprintf('%06x%06x',
45+
(self::$seed[0] ^ $node[1]) | 0x010000,
46+
self::$seed[1] ^ $node[2]
47+
);
3048
} else {
3149
parent::__construct($uuid);
3250
}

0 commit comments

Comments
 (0)