feature #32194 [HttpFoundation] Add a way to anonymize IPs (Seldaek)
This PR was merged into the 4.4 branch.
Discussion
----------
[HttpFoundation] Add a way to anonymize IPs
| Q | A
| ------------- | ---
| Branch? | 4.4
| Bug fix? | no
| New feature? | yes
| BC breaks? | no
| Deprecations? | no
| Tests pass? | yes
| Fixed tickets |
| License | MIT
| Doc PR | symfony/symfony-docs#... <!-- required for new features --> TODO
This is helpful for GDPR compliance reasons, and it isn't much code saved but it's also good if you don't have to think about how to do it.
Commits
-------
9e62330bc4
[HttpFoundation] Add a way to anonymize IPs
This commit is contained in:
commit
f4c925418b
@ -11,6 +11,7 @@ CHANGELOG
|
|||||||
make sure to run `CREATE INDEX EXPIRY ON sessions (sess_lifetime)` to update your database
|
make sure to run `CREATE INDEX EXPIRY ON sessions (sess_lifetime)` to update your database
|
||||||
to speed up garbage collection of expired sessions.
|
to speed up garbage collection of expired sessions.
|
||||||
* added `SessionHandlerFactory` to create session handlers with a DSN
|
* added `SessionHandlerFactory` to create session handlers with a DSN
|
||||||
|
* added `IpUtils::anonymize()` to help with GDPR compliance.
|
||||||
|
|
||||||
4.3.0
|
4.3.0
|
||||||
-----
|
-----
|
||||||
|
@ -153,4 +153,36 @@ class IpUtils
|
|||||||
|
|
||||||
return self::$checkedIps[$cacheKey] = true;
|
return self::$checkedIps[$cacheKey] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Anonymizes an IP/IPv6.
|
||||||
|
*
|
||||||
|
* Removes the last byte for v4 and the last 8 bytes for v6 IPs
|
||||||
|
*/
|
||||||
|
public static function anonymize(string $ip): string
|
||||||
|
{
|
||||||
|
$wrappedIPv6 = false;
|
||||||
|
if ('[' === substr($ip, 0, 1) && ']' === substr($ip, -1, 1)) {
|
||||||
|
$wrappedIPv6 = true;
|
||||||
|
$ip = substr($ip, 1, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
$packedAddress = inet_pton($ip);
|
||||||
|
if (4 === \strlen($packedAddress)) {
|
||||||
|
$mask = '255.255.255.0';
|
||||||
|
} elseif ($ip === inet_ntop($packedAddress & inet_pton('::ffff:ffff:ffff'))) {
|
||||||
|
$mask = '::ffff:ffff:ff00';
|
||||||
|
} elseif ($ip === inet_ntop($packedAddress & inet_pton('::ffff:ffff'))) {
|
||||||
|
$mask = '::ffff:ff00';
|
||||||
|
} else {
|
||||||
|
$mask = 'ffff:ffff:ffff:ffff:0000:0000:0000:0000';
|
||||||
|
}
|
||||||
|
$ip = inet_ntop($packedAddress & inet_pton($mask));
|
||||||
|
|
||||||
|
if ($wrappedIPv6) {
|
||||||
|
$ip = '['.$ip.']';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $ip;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -101,4 +101,30 @@ class IpUtilsTest extends TestCase
|
|||||||
'invalid request IP with invalid proxy wildcard' => ['0.0.0.0', '*'],
|
'invalid request IP with invalid proxy wildcard' => ['0.0.0.0', '*'],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider anonymizedIpData
|
||||||
|
*/
|
||||||
|
public function testAnonymize($ip, $expected)
|
||||||
|
{
|
||||||
|
$this->assertSame($expected, IpUtils::anonymize($ip));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function anonymizedIpData()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
['192.168.1.1', '192.168.1.0'],
|
||||||
|
['1.2.3.4', '1.2.3.0'],
|
||||||
|
['2a01:198:603:0:396e:4789:8e99:890f', '2a01:198:603::'],
|
||||||
|
['2a01:198:603:10:396e:4789:8e99:890f', '2a01:198:603:10::'],
|
||||||
|
['::1', '::'],
|
||||||
|
['0:0:0:0:0:0:0:1', '::'],
|
||||||
|
['1:0:0:0:0:0:0:1', '1::'],
|
||||||
|
['0:0:603:50:396e:4789:8e99:0001', '0:0:603:50::'],
|
||||||
|
['[0:0:603:50:396e:4789:8e99:0001]', '[0:0:603:50::]'],
|
||||||
|
['[2a01:198::3]', '[2a01:198::]'],
|
||||||
|
['::ffff:123.234.235.236', '::ffff:123.234.235.0'], // IPv4-mapped IPv6 addresses
|
||||||
|
['::123.234.235.236', '::123.234.235.0'], // deprecated IPv4-compatible IPv6 address
|
||||||
|
];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user