Tilbake
7.4
Personvern, GDPR og dataetikk

7.4 Personvern, GDPR og dataetikk

Personvernlovgivning, samtykke og databehandling.

55 min
6 oppgaver
GDPRPersonvernSamtykkeDataetikk
Du leser den tradisjonelle versjonen
Din fremgang i kapitlet
0 / 6 oppgaver

Som utvikler har du et stort ansvar når du bygger systemer som håndterer personopplysninger. GDPR (General Data Protection Regulation) er EUs personvernforordning som gir strenge regler for hvordan persondata skal behandles.

I Norge heter loven Personopplysningsloven, som implementerer GDPR. Brudd på loven kan føre til bøter på opptil 4% av global omsetning eller 20 millioner euro - det som er høyest.

Men personvern handler ikke bare om å følge loven. Det handler om å respektere brukernes rettigheter og bygge tillit.

Hva er personopplysninger?

Personopplysninger er all informasjon som kan knyttes til en identifiserbar person:

Direkte identifikasjon:
- Navn, personnummer, fødselsdato
- E-postadresse, telefonnummer
- Foto, fingeravtrykk, stemmeopptak

Indirekte identifikasjon:
- IP-adresse
- Cookie-ID
- Stedsinformasjon
- Kombinasjon av data (alder + bosted + yrke)

Særlige kategorier (ekstra beskyttelse):
- Helse
- Politisk oppfatning
- Religion
- Fagforeningsmedlemskap
- Seksuell orientering
- Genetiske/biometriske data

Grunnprinsipper i GDPR:

1. Lovlighet, rettferdighet og åpenhet
Brukere skal vite hva data brukes til.

2. Formålsbegrensning
Innsamle data kun for spesifikke formål.

3. Dataminimering
Samle inn kun det som er nødvendig.

4. Riktighet
Hold data oppdatert og korrekt.

5. Lagringsbegrensning
Behold data kun så lenge det er nødvendig.

6. Integritet og konfidensialitet
Beskytt data mot uautorisert tilgang.

7. Ansvarplikt
Kunne dokumentere at du følger reglene.

Lovlig behandlingsgrunnlag:

For å behandle personopplysninger må du ha ett av disse grunnlagene:

1. Samtykke: Bruker har gitt eksplisitt tillatelse
2. Avtale: Nødvendig for å oppfylle en avtale
3. Rettslig forpliktelse: Lovpålagt
4. Vitale interesser: Nødvendig for å beskytte liv
5. Offentlig interesse: Utføre offentlig oppgave
6. Legitime interesser: Avveining mot brukers rettigheter

Privacy by Design betyr å bygge personvern inn i systemet fra starten, ikke legge det til etterpå.

7 prinsipper:

1. Proaktiv, ikke reaktiv
Forebygg problemer før de oppstår.

2. Personvern som standardinnstilling
Brukere skal være beskyttet automatisk, uten å måtte konfigurere noe.

# Eksempel: Standard-settings
default_settings = {
    'profile_visibility': 'friends',  # IKKE 'public'
    'data_sharing': False,             # IKKE True
    'notifications': 'minimal'         # IKKE 'all'
}

3. Personvern bygget inn i design
Ikke et tillegg, men en integrert del.

4. Full funksjonalitet
Ikke kompromiss mellom personvern og funksjonalitet - du kan ha begge.

5. Sikkerhet gjennom hele livssyklusen
Fra innsamling til sletting.

6. Synlighet og gjennomsiktighet
Brukere skal kunne se hva som skjer med dataene deres.

7. Respekt for brukerens personvern
Brukervennlig og brukerorientert.

Praktiske tiltak:

Dataminimering i praksis:

# DÅRLIG: Samler unødvendig data
class BrukerRegistrering:
    def __init__(self):
        self.fornavn = ""
        self.etternavn = ""
        self.fodselsdato = ""
        self.personnummer = ""
        self.adresse = ""
        self.postnummer = ""
        self.telefon = ""
        self.epost = ""

# BEDRE: Kun det nødvendige
class BrukerRegistrering:
    def __init__(self):
        self.brukernavn = ""
        self.epost = ""
        # Resten er valgfritt eller hentes når nødvendig

Anonymisering og pseudonymisering:

import hashlib

# Pseudonymisering: Kan reverseres med nøkkel
def pseudonymiser(bruker_id, secret_key):
    return hashlib.sha256(
        f"{bruker_id}{secret_key}".encode()
    ).hexdigest()

# Anonymisering: Kan ikke reverseres
def anonymiser_data(bruker_data):
    return {
        'alder': bruker_data['alder'] // 10 * 10,  # Aldersgruppe
        'postnummer': bruker_data['postnummer'][:2] + '00',  # Område
        'kjonn': bruker_data['kjonn']
        # Fjern navn, personnummer, etc.
    }
Gyldig samtykke må være:

1. Frivillig: Ikke tvunget eller vilkår for tjeneste (hvis ikke nødvendig)
2. Spesifikt: For hvert formål
3. Informert: Bruker vet hva de samtykker til
4. Utvetydig: Aktiv handling, ikke forhåndsavkrysset
5. Tilbaketrekkbart: Lett å trekke tilbake

Dårlige eksempler:

<!-- IKKE GYLDIG: Forhåndsavkrysset -->
<input type="checkbox" name="samtykke" checked>
Jeg godtar vilkårene

<!-- IKKE GYLDIG: Uklart -->
<input type="checkbox" name="samtykke">
Jeg godtar at mine data kan brukes

Gode eksempler:

<!-- GYLDIG: Spesifikt og utvetydig -->
<input type="checkbox" name="nyhetsbrev">
Jeg vil motta nyhetsbrev med produktoppdateringer (valgfritt)

<input type="checkbox" name="markedsforing" required>
Jeg godtar at mine kontaktopplysninger lagres for å kunne kontakte meg om min ordre (nødvendig)

Implementere samtykke:

from datetime import datetime

class Samtykke:
    def __init__(self, bruker_id):
        self.bruker_id = bruker_id
        self.samtykker = {}

    def gi_samtykke(self, formal, beskrivelse):
        self.samtykker[formal] = {
            'gitt': datetime.now(),
            'beskrivelse': beskrivelse,
            'tilbakekalt': None
        }

        # Logg for å dokumentere
        logg_samtykke(self.bruker_id, formal, 'GITT')

    def trekk_tilbake_samtykke(self, formal):
        if formal in self.samtykker:
            self.samtykker[formal]['tilbakekalt'] = datetime.now()
            logg_samtykke(self.bruker_id, formal, 'TILBAKEKALT')

            # Slett data knyttet til dette formålet
            slett_data_for_formal(self.bruker_id, formal)

    def har_samtykke(self, formal):
        if formal not in self.samtykker:
            return False

        samtykke = self.samtykker[formal]
        return samtykke['tilbakekalt'] is None

Informasjonsplikt (personvernerklæring):

Du MÅ informere brukere om:

1. Hvem er behandlingsansvarlig (din bedrift)
2. Hva samler du inn (hvilke data)
3. Hvorfor (formål med behandlingen)
4. Hvordan (behandlingsgrunnlag - samtykke, avtale, etc.)
5. Hvor lenge (lagringstid)
6. Hvem andre får tilgang (databehandlere, tredjeparter)
7. Rettigheter (innsyn, sletting, etc.)

Cookie-samtykke:

<div id="cookie-banner">
    <p>Vi bruker cookies for å forbedre din opplevelse.</p>

    <button onclick="acceptEssential()">Kun nødvendige</button>
    <button onclick="acceptAll()">Aksepter alle</button>
    <button onclick="showSettings()">Innstillinger</button>

    <a href="/personvern">Les mer</a>
</div>

<script>
function acceptEssential() {
    // Lagre kun nødvendige cookies
    setCookie('consent', 'essential', 365);
    hideBanner();
}

function acceptAll() {
    // Lagre alle cookies
    setCookie('consent', 'all', 365);
    // Aktiver sporingsscripts
    enableAnalytics();
    hideBanner();
}
</script>

GDPR gir brukere en rekke rettigheter som du må støtte i systemet ditt:

1. Rett til innsyn
Brukere kan be om kopi av alle data du har om dem.

@app.route('/api/min-data', methods=['GET'])
@krever_autentisering
def eksporter_mine_data():
    bruker_id = request.bruker['id']

    # Samle alle data om bruker
    data = {
        'profil': hent_profil(bruker_id),
        'innlegg': hent_innlegg(bruker_id),
        'kommentarer': hent_kommentarer(bruker_id),
        'aktivitetslogg': hent_aktivitet(bruker_id),
        'samtykker': hent_samtykker(bruker_id)
    }

    # Returner som JSON
    return jsonify(data)

2. Rett til retting
Brukere kan kreve at feil data rettes.

@app.route('/api/profil', methods=['PUT'])
@krever_autentisering
def oppdater_profil():
    bruker_id = request.bruker['id']
    nye_data = request.get_json()

    # Valider og oppdater
    oppdater_bruker(bruker_id, nye_data)

    return jsonify({'message': 'Profil oppdatert'})

3. Rett til sletting ("rett til å bli glemt")
Brukere kan be om at data slettes.

@app.route('/api/slett-konto', methods=['DELETE'])
@krever_autentisering
def slett_konto():
    bruker_id = request.bruker['id']

    # Slett alle data
    slett_profil(bruker_id)
    slett_innlegg(bruker_id)
    slett_kommentarer(bruker_id)
    slett_tokens(bruker_id)

    # Anonymiser data som må beholdes (f.eks. fakturahistorikk)
    anonymiser_fakturaer(bruker_id)

    # Logg sletting
    logg_sletting(bruker_id)

    return jsonify({'message': 'Konto slettet'})

4. Rett til dataportabilitet
Brukere kan få data i maskinlesbart format for å flytte til annen tjeneste.

@app.route('/api/eksporter', methods=['GET'])
@krever_autentisering
def eksporter_data():
    bruker_id = request.bruker['id']

    # Eksporter i standard format (JSON)
    data = hent_alle_data(bruker_id)

    # Returner som nedlastbar fil
    response = make_response(jsonify(data))
    response.headers['Content-Disposition'] = \
        'attachment; filename=mine-data.json'

    return response

5. Rett til innsigelse
Brukere kan protestere mot visse typer behandling.

6. Rett til begrensning
Brukere kan kreve at behandling begrenses mens en sak undersøkes.

✏️Eksempel: GDPR-kompatibel brukersletting

Her er et komplett eksempel på hvordan du implementerer brukersletting i henhold til GDPR:

from datetime import datetime
from flask import Flask, request, jsonify
import sqlite3

app = Flask(__name__)

def logg_hendelse(hendelse_type, bruker_id, detaljer):
    """Logger GDPR-relevante hendelser for dokumentasjon"""
    db = sqlite3.connect('gdpr_logg.db')
    db.execute(
        '''
        INSERT INTO gdpr_logg (tidspunkt, type, bruker_id, detaljer)
        VALUES (?, ?, ?, ?)
        ''',
        (datetime.now(), hendelse_type, bruker_id, detaljer)
    )
    db.commit()
    db.close()

@app.route('/api/slett-konto', methods=['DELETE'])
@krever_autentisering
def slett_konto():
    bruker_id = request.bruker['id']

    # Be om bekreftelse
    bekreftelse = request.json.get('bekreftelse')
    if bekreftelse != 'JEG VIL SLETTE MIN KONTO':
        return jsonify({
            'error': 'Må bekrefte sletting'
        }), 400

    db = sqlite3.connect('app.db')
    cursor = db.cursor()

    try:
        # 1. Slett profil og kontaktinfo
        cursor.execute('DELETE FROM profiler WHERE bruker_id = ?', (bruker_id,))
        logg_hendelse('SLETT', bruker_id, 'Profil slettet')

        # 2. Slett innhold opprettet av bruker
        cursor.execute('DELETE FROM innlegg WHERE bruker_id = ?', (bruker_id,))
        cursor.execute('DELETE FROM kommentarer WHERE bruker_id = ?', (bruker_id,))
        logg_hendelse('SLETT', bruker_id, 'Innhold slettet')

        # 3. Slett filer (profilbilde, opplastinger)
        filer = cursor.execute(
            'SELECT filsti FROM filer WHERE bruker_id = ?',
            (bruker_id,)
        ).fetchall()

        for fil in filer:
            slett_fil_fra_disk(fil[0])

        cursor.execute('DELETE FROM filer WHERE bruker_id = ?', (bruker_id,))
        logg_hendelse('SLETT', bruker_id, f'{len(filer)} filer slettet')

        # 4. Slett autentisering
        cursor.execute('DELETE FROM tokens WHERE bruker_id = ?', (bruker_id,))
        cursor.execute('DELETE FROM sesjoner WHERE bruker_id = ?', (bruker_id,))

        # 5. Trekk tilbake alle samtykker
        cursor.execute(
            '''
            UPDATE samtykker
            SET tilbakekalt = ?
            WHERE bruker_id = ? AND tilbakekalt IS NULL
            ''',
            (datetime.now(), bruker_id)
        )
        logg_hendelse('SAMTYKKE_TRUKKET', bruker_id, 'Alle samtykker trukket')

        # 6. Anonymiser data som må beholdes
        # (f.eks. bestillinger for regnskapsloven - 5 års oppbevaringsplikt)
        cursor.execute(
            '''
            UPDATE bestillinger
            SET navn = 'SLETTET BRUKER',
                epost = 'slettet@example.com',
                adresse = NULL,
                telefon = NULL,
                ip_adresse = NULL
            WHERE bruker_id = ?
            ''',
            (bruker_id,)
        )
        logg_hendelse('ANONYMISER', bruker_id, 'Bestillinger anonymisert')

        # 7. Slett selve brukerkontoen (sist, pga foreign keys)
        cursor.execute('DELETE FROM brukere WHERE id = ?', (bruker_id,))
        logg_hendelse('SLETT', bruker_id, 'Brukerkonto slettet')

        db.commit()

        # 8. Varsle andre systemer (f.eks. nyhetsbrev-tjeneste)
        fjern_fra_nyhetsbrevliste(request.bruker['epost'])

        # 9. Send bekreftelse på e-post (før data slettes!)
        send_sletting_bekreftelse(request.bruker['epost'])

        return jsonify({
            'message': 'Konto og data slettet',
            'tidspunkt': datetime.now().isoformat()
        })

    except Exception as e:
        db.rollback()
        app.logger.error(f"Feil ved sletting av bruker {bruker_id}: {e}")
        return jsonify({'error': 'Kunne ikke slette konto'}), 500

    finally:
        db.close()

@app.route('/api/data-eksport', methods=['GET'])
@krever_autentisering
def data_eksport():
    """Implementerer rett til dataportabilitet"""
    bruker_id = request.bruker['id']

    db = sqlite3.connect('app.db')
    db.row_factory = sqlite3.Row

    # Samle all data
    profil = db.execute(
        'SELECT * FROM profiler WHERE bruker_id = ?',
        (bruker_id,)
    ).fetchone()

    innlegg = db.execute(
        'SELECT * FROM innlegg WHERE bruker_id = ?',
        (bruker_id,)
    ).fetchall()

    kommentarer = db.execute(
        'SELECT * FROM kommentarer WHERE bruker_id = ?',
        (bruker_id,)
    ).fetchall()

    samtykker = db.execute(
        'SELECT * FROM samtykker WHERE bruker_id = ?',
        (bruker_id,)
    ).fetchall()

    db.close()

    # Konverter til JSON-vennlig format
    data = {
        'eksportert': datetime.now().isoformat(),
        'profil': dict(profil) if profil else None,
        'innlegg': [dict(i) for i in innlegg],
        'kommentarer': [dict(k) for k in kommentarer],
        'samtykker': [dict(s) for s in samtykker]
    }

    # Logg eksport
    logg_hendelse('EKSPORT', bruker_id, 'Data eksportert')

    response = make_response(jsonify(data))
    response.headers['Content-Disposition'] = \
        'attachment; filename=mine-data.json'

    return response

Oppsummering

I dette kapittelet har du lært:

- Dataminimering: samle bare det nødvendige.
- Pseudonymisering vs. anonymisering: reverserbar mot ureverserbar.
- GDPR i praksis: standardinnstillinger og brukersletting.
- Dataetikk: ansvarlig bruk av persondata.
- Innebygd personvern: privacy by design.

Noekkelbegreper


BegrepForklaring
DataminimeringSamle bare nødvendige data
PseudonymiseringKan reverseres med nøkkel
AnonymiseringKan ikke reverseres

Dette kapitlet er skrevet av Anthropics toppmodeller (Claude Opus og Claude Fable) og er foreløpig ikke manuelt gjennomgått — kvalitetskontrollen gjøres av uavhengige KI-agenter, og innmeldte feil rettes fortløpende. Funnet en feil? Meld fra, så retter vi den. Les mer om hvordan innholdet lages.