LGPD Brasil: Anonimització de dades sensibles
La Lei Geral de Proteção de Dados (LGPD) de Brasil és el standard de protecció de dades brasiler, similar a GDPR europeu però amb requisits diferenciat per a anonimització.
Requisits LGPD per a anonimització:
- Dades sensibles (dades de salut, originals ètnics, informació religiosa) han de ser anonimitzades irreversiblement
- Dades personals (noms, CPF, adreces) han de ser anonimitzades o criptografiat
- Anonimització ha de ser validada per a assegurar irreversibilitat
Autoritat de supervisió: ANPD (Agência Nacional de Proteção de Dados) — equivalent a ICO europeu
CPF: Estructura tècnica
CPF (Cadastro de Pessoas Físicas) és el número d'identificació personal brasileir, similar a SSN nord-americà o rodné číslo txec.
Format: 11 dígits, sovint escrits com XXX.XXX.XXX-XX
Estructura:
- 8 dígits: Número base (pseudo-random, no codifica data de naixement)
- 2 dígits: Dígits de verificació (verificació de mòdul 11)
- 1 dígit: Verificació regional (codi de sucursal)
Validació de suma de verificació mòdul 11 (primer dígit de verificació):
- Pesa els primers 9 dígits: 10, 9, 8, 7, 6, 5, 4, 3, 2
- Suma ponderada = (dígit[0] × 10) + (dígit[1] × 9) + ... + (dígit[8] × 2)
- Remainder = suma mod 11
- Si remainder < 2, primer dígit de verificació = 0; sinó, primer dígit = 11 - remainder
Validació de suma de verificació mòdul 11 (segon dígit de verificació):
- Pesa els 10 dígits (9 originals + primer dígit de verificació): 11, 10, 9, 8, 7, 6, 5, 4, 3, 2
- Suma ponderada = (dígit[0] × 11) + ... + (dígit[9] × 2)
- Remainder = suma mod 11
- Si remainder < 2, segon dígit de verificació = 0; sinó, segon dígit = 11 - remainder
Exemple:
- CPF: 12345678901
- Dígits: 1,2,3,4,5,6,7,8,9,0,1
- Verificació 1: (1×10)+(2×9)+(3×8)+(4×7)+(5×6)+(6×5)+(7×4)+(8×3)+(9×2) = 10+18+24+28+30+30+28+24+18 = 210
- Remainder = 210 mod 11 = 1 → primer dígit de verificació = 0 (expected) ✓
Auditoria de conformitat ANPD
Organitzacions brasilers que anonimitzen CPF han de:
-
Verificar que CPFs originals estan eliminats
- Cercar qualsevol seqüència de 11 dígits en documents anonimitzats
- Si es troben, validar que complissin suma de verificació de mòdul 11
- Si complissin, podrien ser CPFs reals — fallada d'auditoria
-
Verificar que CPFs anonimitzats no són reversibles
- Si els CPFs estan criptografiat (AES-256), la sortida es veurà com:
a7f9b2d1c8e4...(32 chars) - Si els CPFs estan substituïts per seqüències aleatòries de 11 dígits, verificar que < 1/100 complissin suma de verificació (1 in 100 random sequences validarà per casualitat)
- Si els CPFs estan Hash (SHA-256), la sortida es veurà com:
f5a6d3c2e8b1...(64 chars)— impossible confondre amb número real
- Si els CPFs estan criptografiat (AES-256), la sortida es veurà com:
-
Documentar procediment de anonimització
- Registrar quins CPFs foren processats
- Registrar quin método de anonimització fou usat (criptografia, hash, substitució)
- Registrar quan fou realitzada validació de suma de verificació
- Registrar resultats de validació ("X CPFs validats, 0 leaks detectats")
Script de validació de CPF (Python)
def validate_cpf(cpf_str):
"""Validar suma de verificació de CPF mòdul 11 (dos dígits)"""
# Eliminar puntuació
cpf = cpf_str.replace('.', '').replace('-', '')
if not re.match(r'^\d{11}$', cpf):
return False
# Verificació 1
digits_1 = [int(d) for d in cpf[:9]]
weights_1 = list(range(10, 1, -1))
sum_1 = sum(d * w for d, w in zip(digits_1, weights_1))
remainder_1 = sum_1 % 11
check_1 = 0 if remainder_1 < 2 else 11 - remainder_1
# Verificació 2
digits_2 = [int(d) for d in cpf[:10]]
weights_2 = list(range(11, 1, -1))
sum_2 = sum(d * w for d, w in zip(digits_2, weights_2))
remainder_2 = sum_2 % 11
check_2 = 0 if remainder_2 < 2 else 11 - remainder_2
return int(cpf[9]) == check_1 and int(cpf[10]) == check_2
# Auditoria ANPD
def audit_cpf_anonymization(file_path):
with open(file_path, 'r') as f:
text = f.read()
found_valid = []
# Cercar seqüències de 11 dígits
for match in re.finditer(r'\b\d{11}\b', text):
cpf = match.group()
if validate_cpf(cpf):
found_valid.append(cpf)
if len(found_valid) == 0:
return "PASSA: Cap CPF real detectat"
else:
return f"FALLADA: {len(found_valid)} CPFs potencialment válids trobats: {found_valid}"
print(audit_cpf_anonymization('/path/to/file'))
Fonts: