GDPR za razvijalce programske opreme | Kaj dejansko morate implementirati
Vodnik za razvijalce o skladnosti z GDPR. Pokriva tehnične zahteve, vzorce obdelave podatkov in odločitve na ravni kode, ki jih morate sprejeti.
GDPR velja od leta 2018, vendar se večina vodnikov za razvijalce še vedno osredotoča na pravno teorijo. Ta vodnik je drugačen. Pokriva tehnične zahteve, kodo, ki jo morate napisati, in arhitekturne odločitve, ki naredijo skladnost praktično namesto boleče.
Če vaša programska oprema shranjuje, obdeluje ali se dotika osebnih podatkov ljudi v EU, to velja za vas. Ne glede na to, kje ima vaše podjetje sedež.
Pregled GDPR za razvijalce
Preskočite 99 členov. Tukaj je, kaj GDPR pomeni za vašo zbirko kode:
- Zbirajte le, kar potrebujete. Ne shranjujte podatkov “za vsak slučaj.”
- Povejte uporabnikom, kaj počnete z njihovimi podatki. In pridobite njihovo dovoljenje, ko je zahtevano.
- Dovolite uporabnikom dostop, izvoz in izbris njihovih podatkov. Za to potrebujete API končne točke.
- Varujte podatke. Šifriranje, kontrole dostopa, revizijske sledi.
- Hitro poročajte o kršitvah. Imate 72 ur za obvestilo organov po odkritju kršitve.
- Dokumentirajte vse. Vaše dejavnosti obdelave, vaše varnostne ukrepe, vaše podatkovne tokove.
To je praktičen povzetek. Preostanek tega vodnika vam pokaže, kako implementirati vsako zahtevo.
7 ključnih tehničnih zahtev
1. Upravljanje soglasij
Soglasje mora biti svobodno dano, specifično, informirano in nedvoumno. Vnaprej označena polja ne štejejo. Skupna soglasja (“strinjam se z vsem”) ne štejejo. Umik mora biti enako lahek kot podelitev soglasja.
Kaj zgraditi
Sistem soglasij potrebuje tri komponente:
- Shramba zapisov soglasij. Za vsakega uporabnika sledite, s čim je soglašal, kdaj in kako.
- Mehanizem preverjanja soglasja. Pred obdelavo podatkov za določen namen preverite, ali ima uporabnik aktivno soglasje.
- Mehanizem umika. Dovolite uporabnikom preklicati soglasje prek vašega vmesnika in takoj prenehajte z obdelavo.
Shema baze podatkov
CREATE TABLE user_consents (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL REFERENCES users(id),
consent_type VARCHAR(100) NOT NULL,
granted BOOLEAN NOT NULL,
granted_at TIMESTAMPTZ,
revoked_at TIMESTAMPTZ,
ip_address INET,
user_agent TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX idx_user_consents_lookup
ON user_consents (user_id, consent_type, granted);
Shranite celotno zgodovino. Nikoli ne brišite ali prepisujte zapisov soglasij. Ko uporabnik prekliče soglasje, vstavite novo vrstico z granted = false in nastavite revoked_at. To vam daje revizijsko sled.
Vmesna programska oprema za preverjanje soglasja
Tukaj je Express vmesna programska oprema, ki preverja soglasje pred obdelavo zahteve:
import { Request, Response, NextFunction } from "express";
import { db } from "./database";
interface ConsentRequirement {
type: string;
required: boolean;
}
function requireConsent(consentType: string) {
return async (req: Request, res: Response, next: NextFunction) => {
const userId = req.user?.id;
if (!userId) {
return res.status(401).json({ error: "Authentication required" });
}
const consent = await db.query(
`SELECT granted FROM user_consents
WHERE user_id = $1 AND consent_type = $2
ORDER BY created_at DESC
LIMIT 1`,
[userId, consentType]
);
if (!consent.rows[0]?.granted) {
return res.status(403).json({
error: "Consent required",
consentType,
message: `You must grant "${consentType}" consent to use this feature.`,
consentUrl: `/settings/privacy`,
});
}
next();
};
}
// Usage
app.post(
"/api/newsletter/subscribe",
requireConsent("marketing_emails"),
subscribeHandler
);
app.post(
"/api/analytics/track",
requireConsent("usage_analytics"),
trackHandler
);
2. Dostop do podatkov in izvoz (pravica do dostopa)
Uporabniki imajo pravico zahtevati kopijo vseh osebnih podatkov, ki jih imate o njih. Zagotoviti jih morate v splošno uporabljani, strojno berljivi obliki. JSON ali CSV sta ustrezna.
Kaj zgraditi
Končno točko, ki zbere vse osebne podatke za uporabnika iz vsake tabele in storitve, nato pa jih zapakira v prenosljivo datoteko.
interface DataExport {
exportedAt: string;
user: {
profile: Record<string, unknown>;
activity: Record<string, unknown>[];
consents: Record<string, unknown>[];
communications: Record<string, unknown>[];
};
}
app.get("/api/me/data-export", authenticate, async (req, res) => {
const userId = req.user.id;
const [profile, activity, consents, communications] = await Promise.all([
db.query("SELECT id, email, name, created_at FROM users WHERE id = $1", [
userId,
]),
db.query(
"SELECT action, metadata, created_at FROM user_activity WHERE user_id = $1 ORDER BY created_at DESC",
[userId]
),
db.query(
"SELECT consent_type, granted, granted_at, revoked_at FROM user_consents WHERE user_id = $1 ORDER BY created_at DESC",
[userId]
),
db.query(
"SELECT type, sent_at, subject FROM communications WHERE user_id = $1 ORDER BY sent_at DESC",
[userId]
),
]);
const exportData: DataExport = {
exportedAt: new Date().toISOString(),
user: {
profile: profile.rows[0],
activity: activity.rows,
consents: consents.rows,
communications: communications.rows,
},
};
res.setHeader("Content-Type", "application/json");
res.setHeader(
"Content-Disposition",
`attachment; filename="data-export-${userId}.json"`
);
res.json(exportData);
});
Ta končna točka mora pokriti vsako tabelo, ki vsebuje uporabniške podatke. Temeljito preverite svojo shemo. Manjkajoča tabela pomeni nepopoln izvoz, kar je kršitev skladnosti.
3. Pravica do izbrisa (pravica do pozabe)
Uporabniki lahko zahtevajo, da izbrišete vse njihove osebne podatke. Morate ugoditi, razen če imate pravno obveznost za hrambo (kot so davčni zapisi ali preprečevanje prevar).
Kaj zgraditi
Končno točko za izbris, ki odstrani ali anonimizira uporabniške podatke v vseh tabelah. To je težje, kot se sliši, zaradi omejitev tujih ključev in podatkov, od katerih so odvisni drugi sistemi.
app.delete("/api/me/account", authenticate, async (req, res) => {
const userId = req.user.id;
const client = await db.getClient();
try {
await client.query("BEGIN");
// Anonimizacija podatkov, ki jih je treba obdržati za poslovne zapise
await client.query(
`UPDATE orders
SET customer_name = 'deleted', customer_email = 'deleted'
WHERE user_id = $1`,
[userId]
);
// Izbris podatkov, ki jih je mogoče popolnoma odstraniti
await client.query("DELETE FROM user_activity WHERE user_id = $1", [
userId,
]);
await client.query("DELETE FROM user_consents WHERE user_id = $1", [
userId,
]);
await client.query("DELETE FROM communications WHERE user_id = $1", [
userId,
]);
await client.query("DELETE FROM sessions WHERE user_id = $1", [userId]);
// Anonimizacija uporabniškega zapisa namesto izbrisa
// To ohranja referenčno integriteto
await client.query(
`UPDATE users SET
email = 'deleted-' || id || '@removed.invalid',
name = 'Deleted User',
phone = NULL,
address = NULL,
deleted_at = NOW()
WHERE id = $1`,
[userId]
);
await client.query("COMMIT");
// Sprožitev izbrisa v zunanjih sistemih
await Promise.allSettled([
emailService.deleteSubscriber(userId),
analyticsService.deleteUser(userId),
searchIndex.removeUser(userId),
]);
res.json({ message: "Account and personal data deleted" });
} catch (error) {
await client.query("ROLLBACK");
throw error;
} finally {
client.release();
}
});
Ključne odločitve:
- Izbris ali anonimizacija. Zapise, potrebne za računovodstvo (naročila, računi), je treba anonimizirati. Vse ostalo izbrišite.
- Zunanji sistemi. Podatke, poslane storitvam tretjih oseb, je treba izbrisati tudi tam.
- Časovni okvir. GDPR pravi “brez nepotrebnega odlašanja.” Izbris dokončajte v 30 dneh. Za večino sistemov ga naredite takojšnjega.
4. Minimizacija podatkov
Zbirajte in shranjujte le podatke, ki jih dejansko potrebujete za navedeni namen. Če zahtevate telefonsko številko, a uporabnikov nikoli ne kličete, je ne bi smeli zbirati.
Praktična pravila
- Preverite vsako polje obrazca. Za vsako polje vprašajte: “Katera specifična funkcionalnost se pokvari, če to odstranimo?” Če je odgovor nobena, ga odstranite.
- Nastavite obdobja hrambe. Ne shranjujte podatkov za vedno. Opredelite, koliko časa je posamezna vrsta podatkov potrebna, nato jih samodejno izbrišite.
- Minimizirajte beleženje. Odstranite osebne podatke iz zapisov dnevnika. Beležite ID-je uporabnikov, ne imen ali e-poštnih naslovov.
-- Samodejna hramba podatkov s PostgreSQL
-- Zaženite kot razporejeno opravilo (npr. pg_cron)
DELETE FROM user_activity
WHERE created_at < NOW() - INTERVAL '2 years';
DELETE FROM session_logs
WHERE created_at < NOW() - INTERVAL '90 days';
DELETE FROM password_reset_tokens
WHERE created_at < NOW() - INTERVAL '24 hours';
5. Šifriranje
GDPR zahteva “ustrezne tehnične ukrepe” za zaščito osebnih podatkov. Šifriranje je najpomembnejše.
V mirovanju
- Šifrirajte disk baze podatkov. Vsi večji ponudniki oblaka to podpirajo. Omogočite in preverite.
- Za zelo občutljiva polja (EMŠO, zdravstveni podatki) dodajte šifriranje na ravni aplikacije poleg tega.
- Šifrirajte varnostne kopije. Nešifrirana varnostna kopija je kršitev, ki čaka, da se zgodi.
V prenosu
- TLS povsod. Vsaka povezava med storitvami, bazami podatkov in uporabniki. Brez izjem.
- Zahtevajte HTTPS. Preusmerite HTTP. Nastavite HSTS glave.
- Uporabite TLS za povezave z bazo podatkov. PostgreSQL to podpira že v osnovi.
// PostgreSQL povezava s TLS
import { Pool } from "pg";
const pool = new Pool({
host: process.env.DB_HOST,
port: 5432,
database: process.env.DB_NAME,
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
ssl: {
rejectUnauthorized: true,
ca: fs.readFileSync("/path/to/server-ca.pem").toString(),
},
});
6. Obveščanje o kršitvah
Če so osebni podatki ogroženi, morate obvestiti pristojni organ za varstvo podatkov v 72 urah. Če kršitev predstavlja visoko tveganje za posameznike, morate obvestiti tudi prizadete uporabnike.
Kaj zgraditi
- Revizijsko beleženje. Sledite vsakemu dostopu do osebnih podatkov. Kdo je dostopal, kdaj in od kod.
- Zaznavanje anomalij. Opozorila ob nenavadnih vzorcih dostopa (množični izvozi podatkov, dostop z novih IP naslovov, dostop zunaj poslovnih ur).
- Načrt odziva na incidente. Dokumentirajte, kdo kaj stori, ko je zaznana kršitev. To ni koda. Je kontrolni seznam, ki ga vaša ekipa vadbi.
CREATE TABLE data_access_log (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL,
accessed_by UUID NOT NULL,
access_type VARCHAR(50) NOT NULL,
resource_type VARCHAR(100) NOT NULL,
resource_id UUID,
ip_address INET,
user_agent TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX idx_data_access_log_user
ON data_access_log (user_id, created_at);
CREATE INDEX idx_data_access_log_accessor
ON data_access_log (accessed_by, created_at);
7. Zasebnost po zasnovi
GDPR pravi, da mora biti zasebnost vgrajena v sisteme od začetka, ne privijačena pozneje. V praksi to pomeni, da je zasebnost privzeta.
- Privzeto je zasebno. Nove funkcionalnosti naj zbirajo minimalno podatkov in zahtevajo privolitev za karkoli prek temeljne funkcije.
- Nastavitve so privzeto na najbolj zasebni možnosti. Uporabniki, ki nikoli ne dotaknejo svojih nastavitev, morajo imeti najvišjo zaščito zasebnosti.
- Ločite zadeve. Ne mešajte analitičnih podatkov s funkcionalnimi podatki. Ne ponovno uporabljajte avtentikacijskih žetonov za sledenje.
Anonimizacija ali psevdonimizacija
To ni ista stvar in razlika je pomembna.
- Psevdonimizacija nadomesti identifikacijske informacije z reverzibilnim žetonom. Primer: zgoščevanje e-poštnih naslovov. Če imate zgoščevalno funkcijo in izvirni e-poštni naslov, lahko ponovno identificirate osebo. GDPR še vedno velja, ker je ponovna identifikacija mogoča.
- Anonimizacija trajno odstrani identifikacijske informacije. Primer: zbirna analitika (“1.247 uporabnikov je obiskalo stran s cenami”) brez možnosti identifikacije, kateri uporabniki. GDPR ne velja za resnično anonimizirane podatke.
Resnična anonimizacija je težka. Če vaš “anonimni” nabor podatkov vključuje časovni žig, mesto in vrsto naprave, ta kombinacija morda edinstveno identificira nekoga. Bodite konzervativni.
Soglasje za piškotke
Če vaša spletna stran uporablja piškotke prek tistega, kar je strogo potrebno, potrebujete soglasje pred njihovo nastavitvijo.
Zahteva soglasje: analitični piškotki, oglaševalski piksli, gradniki družbenih medijev, katerikoli skript za sledenje tretjih oseb.
Ne zahteva soglasja: sejni piškotki, piškotki nakupovalne košarice, CSRF žetoni, sam piškotek za nastavitev soglasja za piškotke.
Vaš pasica za soglasje mora blokirati nebistvene piškotke, dokler ni soglasje podano, ponuditi natančne izbire in narediti “zavrni vse” enako enostavno kot “sprejmi vse.” Ne gradite tega od začetka. Orodja kot Cookiebot obvladajo kompleksnost. Ključno pravilo: nobena skripta za sledenje se ne sproži pred podelitvijo soglasja.
Tretji obdelovalci podatkov
Vsaka storitev tretje osebe, ki obdeluje podatke vaših uporabnikov, je “obdelovalec podatkov” po GDPR. Vi ste odgovorni za njihovo skladnost.
Kaj preveriti
Pred integracijo katerekoli storitve tretje osebe, ki se dotika osebnih podatkov:
- Ali imajo DPA? Pogodba o obdelavi podatkov je obvezna. Večina SaaS ponudnikov jih objavlja javno.
- Kje shranjujejo podatke? Če zunaj EU, preverite pravno podlago za prenos.
- Do katerih podatkov dostopajo? Minimizirajte, kar pošiljate. Če storitev potrebuje le e-poštni naslov, ne pošiljajte celotnega profila.
- Ali lahko izbrišete podatke iz njihovih sistemov? Zahteve za izbris uporabnikov se morajo razširiti povsod.
- Kako obravnavajo kršitve? Njihov DPA mora določati časovne okvire za obveščanje.
Pogosti tretji obdelovalci za pregled
- E-poštne storitve (Resend, SendGrid, Mailchimp)
- Analitika (Google Analytics, Mixpanel, Amplitude)
- Sledenje napak (Sentry, Bugsnag)
- Obdelava plačil (Stripe, Adyen)
- Oblačno gostovanje (AWS, Google Cloud, Vercel)
- Orodja za podporo strankam (Intercom, Zendesk)
- AI API-ji (OpenAI, Anthropic, Google AI)
Vzdržujte seznam vseh obdelovalcev. Pregledujte ga četrtletno.
Politike hrambe podatkov
Ne shranjujte osebnih podatkov dlje, kot je potrebno. Opredelite obdobja hrambe za vsako vrsto podatkov.
| Vrsta podatkov | Predlagano obdobje hrambe | Razlog |
|---|---|---|
| Podatki uporabniškega računa | Do zahteve za izbris | Potrebni za storitev |
| Dnevniki sej | 90 dni | Varnost in odpravljanje napak |
| Dnevniki aktivnosti uporabnikov | 1-2 leti | Analitika izdelka |
| Zahtevki podpore | 3 leta | Kakovost storitev |
| Finančni zapisi | 7 let | Davčne/pravne obveznosti |
| Žetoni za ponastavitev gesla | 24 ur | Varnost |
| Neuspeli poskusi prijave | 90 dni | Varnostno spremljanje |
Implementirajte samodejna opravila čiščenja. Ne zanašajte se na to, da se bo nekdo spomnil zagnati skripto.
GDPR kontrolni seznam za razvijalce
Uporabite to kot izhodišče pri gradnji ali reviziji sistema.
Zbiranje podatkov
- Vsako polje obrazca ima naveden namen
- Nepotrebni podatki se ne zbirajo
- Politika zasebnosti je povezana z vsake točke zbiranja podatkov
- Soglasje je zbrano pred obdelavo (kjer je zahtevano)
- Zapisi soglasij so shranjeni s časovnimi žigi
Shranjevanje podatkov
- Šifriranje baze podatkov v mirovanju je omogočeno
- TLS je zahtevan za vse povezave
- Občutljiva polja imajo šifriranje na ravni aplikacije
- Varnostne kopije so šifrirane
- Dostop do produkcijskih podatkov je omejen in beležen
Pravice uporabnikov
- Končna točka za izvoz podatkov obstaja in pokriva vse tabele
- Končna točka za izbris računa obstaja in obravnava vse podatke
- Uporabniki lahko pregledajo in umaknejo soglasje v svojih nastavitvah
- Izbris se razširi na storitve tretjih oseb
- Na vse zahteve uporabnikov za pravice se odzovete v 30 dneh
Piškotki in sledenje
- Pasica za soglasje o piškotkih je implementirana
- Nebistveni piškotki so blokirani pred soglasjem
- Izbire soglasja so natančne (ne vse ali nič)
- “Zavrni vse” je enako vidno kot “Sprejmi vse”
Tretje osebe
- Vsi obdelovalci podatkov so dokumentirani
- DPA so podpisani z vsakim obdelovalcem
- Podatki, poslani tretjim osebam, so minimizirani
- Izbris podatkov pri tretjih osebah je mogoč
Varnost
- Revizijski dnevniki sledijo dostopu do osebnih podatkov
- Opozorila o anomalijah so konfigurirana
- Načrt odziva na incidente je dokumentiran
- Postopek obveščanja o kršitvah je opredeljen (72-urni rok)
Hramba
- Obdobja hrambe so opredeljena za vse vrste podatkov
- Samodejna opravila čiščenja so razporejena
- Potečeni podatki se dejansko brišejo (preverite to)
Zaključne misli
Skladnost z GDPR ni enkraten projekt. Je nabor praks, vtkan v način gradnje programske opreme. Tehnično delo je preprosto: shranjevanje soglasij, izvoz podatkov, končne točke za izbris, šifriranje, revizijsko beleženje. Standardno inženirstvo.
Težji del je temeljitost. Enostavno je pozabiti na tisto datoteko dnevnika, tisti analitični dogodek ali tisto integracijo tretje osebe, ki shranjuje e-poštne naslove uporabnikov. Redno revidirajte. Testirajte svojo končno točko za izbris. Preverite, ali so vaši izvozi popolni. Vgradite zasebnost v svoj proces od začetka.
Potrebujete pomoč pri gradnji programske opreme, skladne z GDPR, ali reviziji obstoječih sistemov? Stopite v stik. Gradimo aplikacije z zasebnostjo na prvem mestu za evropska podjetja in podjetja, ki služijo uporabnikom v EU.