GDPR kehittäjille | Mitä sinun todella pitää toteuttaa
Kehittäjälähtöinen opas GDPR-vaatimustenmukaisuuteen. Kattaa tekniset vaatimukset, datankäsittelymallit ja kooditason päätökset, jotka sinun pitää tehdä.
GDPR on ollut voimassa vuodesta 2018, mutta useimmat kehittäjäoppaat keskittyvät edelleen oikeudelliseen teoriaan. Tämä opas on erilainen. Se kattaa tekniset vaatimukset, koodin, jota sinun pitää kirjoittaa, ja arkkitehtuuripäätökset, jotka tekevät vaatimustenmukaisuudesta käytännöllistä tuskallisen sijaan.
Jos ohjelmistosi tallentaa, käsittelee tai koskettaa EU:ssa olevien ihmisten henkilötietoja, tämä koskee sinua. Sillä ei ole väliä, missä yrityksesi sijaitsee.
GDPR:n yleiskatsaus kehittäjille
Ohita 99 artiklaa. Tässä mitä GDPR tarkoittaa koodikannassasi:
- Kerää vain tarvitsemasi. Älä tallenna dataa “varmuuden vuoksi”.
- Kerro käyttäjille, mitä teet heidän datallaan. Ja hanki heidän lupansa, kun se vaaditaan.
- Anna käyttäjien pääsy dataan, viedä se ja poistaa se. Tarvitset API-päätepisteet tähän.
- Pidä data turvassa. Salaus, pääsynhallinta, auditointilokit.
- Ilmoita tietomurroista nopeasti. Sinulla on 72 tuntia ilmoittaa viranomaisille tietomurron havaitsemisen jälkeen.
- Dokumentoi kaikki. Käsittelytoimintasi, tietoturvatoimenpiteesi, datavirtasi.
Tämä on käytännön yhteenveto. Tämän oppaan loppuosa näyttää, miten jokainen vaatimus toteutetaan.
7 keskeistä teknistä vaatimusta
1. Suostumuksen hallinta
Suostumuksen on oltava vapaasti annettu, yksilöity, tietoinen ja yksiselitteinen. Valmiiksi rastitetut ruudut eivät kelpaa. Nipussa annettu suostumus (“hyväksy kaikki”) ei kelpaa. Suostumuksen peruuttamisen on oltava yhtä helppoa kuin sen antaminen.
Mitä rakentaa
Suostumusjärjestelmä tarvitsee kolme komponenttia:
- Suostumustietojen tallennuspaikka. Jokaiselle käyttäjälle seuraa, mihin he suostuivat, milloin ja miten.
- Suostumuksen tarkistusmekanismi. Ennen datan käsittelyä tiettyä tarkoitusta varten, varmista, että käyttäjällä on aktiivinen suostumus.
- Peruuttamismekanismi. Anna käyttäjien peruuttaa suostumus käyttöliittymässäsi ja lopeta käsittely välittömästi.
Tietokantaskeema
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);
Tallenna koko historia. Älä koskaan poista tai ylikirjoita suostumustietueita. Kun käyttäjä peruuttaa suostumuksen, lisää uusi rivi granted = false ja aseta revoked_at. Tämä antaa sinulle auditointiketjun.
Suostumuksen tarkistuksen väliohjelmisto
Tässä Express-väliohjelmisto, joka tarkistaa suostumuksen ennen pyynnön käsittelyä:
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. Datan saatavuus ja vienti (oikeus saada pääsy)
Käyttäjillä on oikeus pyytää kopio kaikista heistä hallussasi olevista henkilötiedoista. Sinun on toimitettava se yleisesti käytetyssä, koneluettavassa muodossa. JSON tai CSV toimii hyvin.
Mitä rakentaa
Päätepiste, joka kerää kaikki käyttäjän henkilötiedot jokaisesta taulusta ja palvelusta ja pakkaa ne ladattavaan tiedostoon.
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);
});
Tämän päätepisteen on katettava jokainen taulu, joka sisältää käyttäjädataa. Auditoi skeemasi perusteellisesti. Puuttuva taulu tarkoittaa epätäydellistä vientiä, mikä on vaatimustenmukaisuusvirhe.
3. Oikeus poistoon (oikeus tulla unohdetuksi)
Käyttäjät voivat pyytää kaikkien henkilötietojensa poistamista. Sinun on noudatettava pyyntöä, ellei sinulla ole lakisääteistä velvollisuutta säilyttää dataa (kuten verotietueet tai petostentorjunta).
Mitä rakentaa
Poistopäätepiste, joka poistaa tai anonymisoi käyttäjädatan kaikista tauluista. Tämä on vaikeampaa kuin miltä kuulostaa viiteavainrajoitusten ja muiden järjestelmien riippuvuuksien vuoksi.
app.delete("/api/me/account", authenticate, async (req, res) => {
const userId = req.user.id;
const client = await db.getClient();
try {
await client.query("BEGIN");
// Anonymize data that must be retained for business records
await client.query(
`UPDATE orders
SET customer_name = 'deleted', customer_email = 'deleted'
WHERE user_id = $1`,
[userId]
);
// Delete data that can be fully removed
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]);
// Anonymize the user record instead of deleting
// This preserves referential integrity
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");
// Trigger deletion in external systems
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();
}
});
Keskeiset päätökset:
- Poista vai anonymisoi. Kirjanpitoon tarvittavat tietueet (tilaukset, laskut) pitää anonymisoida. Poista kaikki muu.
- Ulkoiset järjestelmät. Kolmannen osapuolen palveluihin lähetetty data pitää poistaa myös sieltä.
- Ajoitus. GDPR sanoo “ilman aiheetonta viivästystä.” Suorita poisto 30 päivässä. Useimmissa järjestelmissä tee se välittömästi.
4. Datan minimointi
Kerää ja tallenna vain data, jota todella tarvitset ilmoitettuun tarkoitukseen. Jos kysyt puhelinnumeroa mutta et koskaan soita käyttäjille, sinun ei pitäisi kerätä sitä.
Käytännön säännöt
- Auditoi jokainen lomakekenttä. Jokaiselle kentälle kysy: “Mikä tietty ominaisuus rikkoutuu, jos poistamme tämän?” Jos vastaus on ei mikään, poista se.
- Aseta säilytysajat. Älä säilytä dataa ikuisesti. Määritä, kuinka kauan kutakin datatyyppiä tarvitaan, ja poista se automaattisesti.
- Minimoi lokitus. Poista henkilötiedot lokimerkinnöistä. Kirjaa käyttäjätunnuksia, ei nimiä tai sähköpostiosoitteita.
-- Automatic data retention with PostgreSQL
-- Run this as a scheduled job (e.g., 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. Salaus
GDPR vaatii “asianmukaisia teknisiä toimenpiteitä” henkilötietojen suojaamiseksi. Salaus on tärkein.
Levossa
- Salaa tietokantasi levy. Kaikki suuret pilvipalveluntarjoajat tukevat tätä. Ota se käyttöön ja varmista.
- Erittäin arkaluontoisille kentille (henkilötunnukset, terveystiedot) lisää sovellustason salaus päälle.
- Salaa varmuuskopiot. Salaamaton varmuuskopio on tietomurto, joka odottaa tapahtumistaan.
Siirrossa
- TLS kaikkialla. Jokainen yhteys palveluiden, tietokantojen ja käyttäjien välillä. Ei poikkeuksia.
- Pakota HTTPS. Uudelleenohjaa HTTP. Aseta HSTS-otsikot.
- Käytä TLS:ää tietokantayhteyksiin. PostgreSQL tukee tätä natiivisti.
// PostgreSQL connection with 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. Tietomurtoilmoitus
Jos henkilötietoja vaarantuu, sinun on ilmoitettava asianomaiselle tietosuojaviranomaiselle 72 tunnin kuluessa. Jos tietomurto aiheuttaa korkean riskin yksilöille, sinun on myös ilmoitettava asianomaisille käyttäjille.
Mitä rakentaa
- Auditointilokitus. Seuraa jokaista henkilötietojen käyttöä. Kuka pääsi niihin, milloin ja mistä.
- Poikkeamien havaitseminen. Hälytä epätavallisista käyttömalleista (massadataviennit, pääsy uusilta IP-osoitteilta, pääsy työajan ulkopuolella).
- Poikkeamatilannesuunnitelma. Dokumentoi, kuka tekee mitäkin, kun tietomurto havaitaan. Tämä ei ole koodia. Se on tarkistuslista, jota tiimisi harjoittelee.
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. Sisäänrakennettu tietosuoja
GDPR sanoo, että tietosuoja pitäisi rakentaa järjestelmiin alusta alkaen, ei lisätä jälkikäteen. Käytännössä tämä tarkoittaa tietosuojan tekemistä oletukseksi.
- Oletus yksityiseen. Uusien ominaisuuksien pitäisi kerätä minimaalista dataa ja vaatia suostumusta mihin tahansa ydintoiminnon yli menevään.
- Asetukset oletuksena yksityisimpään. Käyttäjillä, jotka eivät koskaan koske asetuksiinsa, pitäisi olla korkein tietosuoja.
- Erota huolenaiheet. Älä sekoita analytiikkadataa toiminnalliseen dataan. Älä käytä uudelleen todennustunnisteita seurantaan.
Anonymisointi vs. pseudonymisointi
Nämä eivät ole sama asia, ja erolla on merkitystä.
- Pseudonymisointi korvaa tunnistavan tiedon palautettavalla tunnisteella. Esimerkki: sähköpostiosoitteiden tiivistäminen. Jos sinulla on tiivistefunktio ja alkuperäinen sähköposti, voit tunnistaa henkilön uudelleen. GDPR soveltuu edelleen, koska uudelleentunnistus on mahdollista.
- Anonymisointi poistaa tunnistetiedot pysyvästi. Esimerkki: koosteanalytiikka (“1 247 käyttäjää vieraili hintasivulla”) ilman tapaa tunnistaa, ketkä käyttäjät. GDPR ei sovellu aidosti anonymisoituun dataan.
Todellinen anonymisointi on vaikeaa. Jos “anonyymi” aineistosi sisältää aikaleiman, kaupungin ja laitetyypin, tuo yhdistelmä saattaa tunnistaa jonkun yksilöllisesti. Ole konservatiivinen.
Evästesuostumus
Jos verkkosivustosi käyttää evästeitä yli välttämättömän, tarvitset suostumuksen ennen niiden asettamista.
Vaatii suostumuksen: analytiikkaevästeet, mainospikselit, sosiaalisen median widgetit, kaikki kolmannen osapuolen seurantaskriptit.
Ei vaadi suostumusta: istuntoevästeet, ostoskorievästeet, CSRF-tunnisteet, itse evästesuostumuksen valintaeväste.
Suostumuspalkkin pitäisi estää ei-välttämättömät evästeet ennen suostumusta, tarjota yksityiskohtaiset valinnat ja tehdä “hylkää kaikki” yhtä helpoksi kuin “hyväksy kaikki”. Älä rakenna tätä alusta. Työkalut kuten Cookiebot hoitavat monimutkaisuuden. Pääsääntö: mitkään seurantaskriptit eivät suoritu ennen kuin suostumus on annettu.
Kolmannen osapuolen tietojenkäsittelijät
Jokainen kolmannen osapuolen palvelu, joka käsittelee käyttäjiesi dataa, on “tietojenkäsittelijä” GDPR:n mukaan. Sinä olet vastuussa heidän vaatimustenmukaisuudestaan.
Mitä tarkistaa
Ennen minkään kolmannen osapuolen palvelun integrointia, joka koskettaa henkilötietoja:
- Onko heillä DPA? Tietojenkäsittelysopimus on pakollinen. Useimmat SaaS-palveluntarjoajat julkaisevat omansa julkisesti.
- Missä he tallentavat dataa? Jos EU:n ulkopuolella, varmista siirron oikeusperusta.
- Mitä dataa he käyttävät? Minimoi lähettämäsi. Jos palvelu tarvitsee vain sähköpostin, älä lähetä koko profiilia.
- Voitko poistaa dataa heidän järjestelmistään? Käyttäjien poistopyyntöjen on leviättävä kaikkialle.
- Miten he käsittelevät tietomurtoja? Heidän DPA:nsa pitäisi määritellä ilmoitusaikataulut.
Yleisiä kolmannen osapuolen käsittelijöitä tarkistettavaksi
- Sähköpostipalvelut (Resend, SendGrid, Mailchimp)
- Analytiikka (Google Analytics, Mixpanel, Amplitude)
- Virheseuranta (Sentry, Bugsnag)
- Maksujen käsittely (Stripe, Adyen)
- Pilvipalvelut (AWS, Google Cloud, Vercel)
- Asiakastukityökalut (Intercom, Zendesk)
- AI API:t (OpenAI, Anthropic, Google AI)
Ylläpidä listaa kaikista käsittelijöistä. Tarkista se neljännesvuosittain.
Datan säilytyskäytännöt
Älä säilytä henkilötietoja pidempään kuin on tarpeen. Määritä säilytysajat jokaiselle datatyypille.
| Datatyyppi | Suositeltu säilytysaika | Syy |
|---|---|---|
| Käyttäjätilin tiedot | Kunnes poistoa pyydetään | Palvelua varten tarvittava |
| Istuntolokit | 90 päivää | Turvallisuus ja virheenkorjaus |
| Käyttäjän toimintalokit | 1-2 vuotta | Tuoteanalytiikka |
| Tukipyynnöt | 3 vuotta | Palvelun laatu |
| Taloustiedot | 7 vuotta | Vero-/lakivelvoitteet |
| Salasanan palautustunnisteet | 24 tuntia | Turvallisuus |
| Epäonnistuneet kirjautumisyritykset | 90 päivää | Turvallisuuden seuranta |
Toteuta automatisoidut siivoustyöt. Älä luota siihen, että joku muistaa suorittaa skriptin.
GDPR-tarkistuslista kehittäjille
Käytä tätä lähtökohtana järjestelmää rakentaessasi tai auditoidessasi.
Datan kerääminen
- Jokaisella lomakekentällä on ilmoitettu tarkoitus
- Tarpeetonta dataa ei kerätä
- Tietosuojakäytäntö on linkitetty jokaisesta datan keräyskohdasta
- Suostumus kerätään ennen käsittelyä (kun vaaditaan)
- Suostumustietueet tallennetaan aikaleimoin
Datan tallennus
- Tietokannan levysalaus on käytössä
- TLS on pakotettu kaikille yhteyksille
- Arkaluontoisilla kentillä on sovellustason salaus
- Varmuuskopiot on salattu
- Pääsy tuotantodataan on rajoitettu ja kirjattu
Käyttäjän oikeudet
- Datavientipäätepiste on olemassa ja kattaa kaikki taulut
- Tilin poistopäätepiste on olemassa ja käsittelee kaiken datan
- Käyttäjät voivat tarkastella ja peruuttaa suostumuksen asetuksissaan
- Poisto leviää kolmannen osapuolen palveluihin
- Kaikkiin käyttäjän oikeuspyyntöihin vastataan 30 päivässä
Evästeet ja seuranta
- Evästesuostumuspalkki on toteutettu
- Ei-välttämättömät evästeet estetään ennen suostumusta
- Suostumusvalinnat ovat yksityiskohtaiset (ei kaikki tai ei mitään)
- “Hylkää kaikki” on yhtä näkyvä kuin “Hyväksy kaikki”
Kolmannet osapuolet
- Kaikki tietojenkäsittelijät on dokumentoitu
- DPA:t on allekirjoitettu jokaisen käsittelijän kanssa
- Kolmansille osapuolille lähetettävä data on minimoitu
- Datan poisto kolmansilta osapuolilta on mahdollista
Turvallisuus
- Auditointilokit seuraavat henkilötietojen käyttöä
- Poikkeamahälytykset on konfiguroitu
- Poikkeamatilannesuunnitelma on dokumentoitu
- Tietomurtoilmoitusprosessi on määritelty (72 tunnin määräaika)
Säilytys
- Säilytysajat on määritelty kaikille datatyypeille
- Automatisoidut siivoustyöt on ajastettu
- Vanhentunutta dataa todella poistetaan (varmista tämä)
Lopputoteamus
GDPR-vaatimustenmukaisuus ei ole kertaluontoinen projekti. Se on joukko käytäntöjä, jotka kudotaan tapaan, jolla rakennat ohjelmistoa. Tekninen työ on suoraviivaista: suostumuksen tallennus, datan vienti, poistopäätepisteet, salaus, auditointilokitus. Perusohjelmistokehitystä.
Vaikea osa on perusteellisuus. On helppo unohtaa se lokitiedosto, se analytiikkatapahtuma tai se kolmannen osapuolen integraatio, joka tallentaa käyttäjien sähköposteja. Auditoi säännöllisesti. Testaa poistopäätepisteesi. Varmista, että vientisi ovat täydellisiä. Rakenna tietosuoja prosessiisi alusta alkaen.
Tarvitsetko apua GDPR-vaatimustenmukaisen ohjelmiston rakentamisessa tai olemassa olevien järjestelmiesi auditoinnissa? Ota yhteyttä. Rakennamme tietosuoja edellä -sovelluksia eurooppalaisille yrityksille ja EU-käyttäjiä palveleville yrityksille.