IP-based tracking
Why it matters Blocking cookies does not stop a site from seeing your IP address, and some trackers use "IP address plus browser" as a stand-in ID. In this lab you measure how well that works over a simulated week, and you will see it is both weaker and more dangerous than it sounds.
An IP address is a bit like a street address for a block of flats. It gets packets to the building, but several people may live there, and people move.
Why IP addresses are shared
There are not enough old-style (IPv4) addresses for every device, so networks share them.
NAT: Network Address Translation: a home router or office gateway lets many devices share one public IP address. Every phone and laptop at home looks like the same address to websites.
Carrier-grade NAT: the same trick done by a mobile network on a large scale: thousands of phones share a small pool of addresses, and your phone may get a different one each time it connects.
User agent: a short text your browser sends with every request, naming the browser and system, such as Brook/31.0 (Laptop; OS-A). Many people send exactly the same one.
So a tracker that combines the two into one weak ID, like 203.0.113.7 | Brook/31.0 (Laptop; OS-A), can go wrong in two ways:
- Splitting: one person appears under many IDs, because their phone moves between home Wi-Fi, the office and the mobile network, or their home address changes.
- Merging: different people share one ID, because they share an office or a household and use the same popular browser.
Merging is the dangerous one for privacy: a tracker may wrongly pin your housemate's browsing on you, or reveal that someone in your home looked at something sensitive.
The practice data
watched.leg5a_network.simulate_week(seed) gives a week of visits to one news site. Each visit is a dict:
{'day': 0, 'hour': 10, 'person': 'ana', 'device': 'laptop',
'network': 'office', 'ip': '192.0.2.31',
'user_agent': 'Brook/31.0 (Laptop; OS-A)'}The site itself only sees ip and user_agent. The person field is the truth that the simulator knows and a real site never does; you use it only to score the weak ID. Days run from 0 (Monday) to 6 (Sunday).
To count different things, a Python set is handy: it keeps each value once.
seen = set()
for v in visits:
seen.add(v["ip"])
print(len(seen)) # how many different IPsTo find the most common item, count with a dict and take the biggest count with max(counts.values()).
In other languages
Building a weak ID and counting distinct values looks much the same everywhere.
// JavaScript
const weakId = v => `${v.ip} | ${v.user_agent}`;
const ids = new Set(week.filter(v => v.person === "ana").map(weakId));
console.log(ids.size);// Go
ids := map[string]bool{}
for _, v := range week {
if v.Person == "ana" {
ids[v.IP+" | "+v.UserAgent] = true
}
}
fmt.Println(len(ids))// PHP
$ids = [];
foreach ($week as $v) {
if ($v['person'] === 'ana') { $ids[$v['ip'] . ' | ' . $v['user_agent']] = true; }
}
echo count($ids);The defence
For you: a VPN or relay replaces your IP with a shared one, and keeping your browser up to date keeps your user agent common. For the sites you build: do not treat an IP address as an identity. Shorten or drop IP addresses in logs as soon as you can (for example keep only the first three parts of an IPv4 address), because a raw IP plus a time can point to one household.
Recap
- An IP address belongs to a connection, often shared by a household, an office or thousands of phones.
- IP plus user agent splits one person into many IDs and merges different people into one.
- Merging can wrongly expose someone else's browsing, which is why IP-based IDs are risky as well as weak.
- In your own logs, shorten or drop IP addresses early.
WEEK is one simulated week of visits. Write four functions:
weak_id(visit): return one text combiningvisit["ip"]andvisit["user_agent"], such asip + " | " + user_agent. Two visits must get the same ID exactly when both parts match.ids_for_person(week, person): return how many different weak IDs that person's visits carried (0 if none).people_behind_id(week): return a dict mapping each weak ID to how many different people made visits under it.stability(week, person): return the share (0.0 to 1.0) of that person's visits made under their single most common weak ID, or 0.0 if they have no visits.
This lesson is locked
Lessons open one at a time. Finish the previous lesson to unlock this one.