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 utviklar har du eit stort ansvar når du byggjer system som handterer personopplysningar. GDPR (General Data Protection Regulation) er EU si personvernforordning som gir strenge reglar for korleis persondata skal handsamast.

I Noreg heiter lova Personopplysningslova, som implementerer GDPR. Brot på lova kan føre til bøter på opptil 4% av global omsetning eller 20 millionar euro - det som er høgast.

Men personvern handlar ikkje berre om å følgje lova. Det handlar om å respektere rettane til brukarane og byggje tillit.

Kva er personopplysningar?

Personopplysningar er all informasjon som kan knytast til ein identifiserbar person:

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

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

Særlege kategoriar (ekstra vern):
- Helse
- Politisk oppfatning
- Religion
- Fagforeiningsmedlemskap
- Seksuell orientering
- Genetiske/biometriske data

Grunnprinsipp i GDPR:

1. Lovlegheit, rettferd og openheit
Brukarar skal vite kva data blir brukt til.

2. Formålsavgrensing
Samle inn data kun for spesifikke formål.

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

4. Rettleik
Hald data oppdatert og korrekt.

5. Lagringsavgrensing
Behald data kun så lenge det er nødvendig.

6. Integritet og konfidensialitet
Vern data mot uautorisert tilgang.

7. Ansvarsplikt
Kunne dokumentere at du følgjer reglane.

Lovleg handsamingsgrunnlag:

For å handsame personopplysningar må du ha eitt av desse grunnlaga:

1. Samtykke: Brukar har gitt eksplisitt løyve
2. Avtale: Nødvendig for å oppfylle ei avtale
3. Rettsleg plikt: Lovpålagt
4. Vitale interesser: Nødvendig for å verne liv
5. Offentleg interesse: Utføre offentleg oppgåve
6. Legitime interesser: Avveging mot rettane til brukaren

Privacy by Design tyder å byggje personvern inn i systemet frå starten, ikkje leggje det til etterpå.

7 prinsipp:

1. Proaktiv, ikkje reaktiv
Førebygg problem før dei oppstår.

2. Personvern som standardinnstilling
Brukarar skal vere verna automatisk, utan å måtte konfigurere noko.

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

3. Personvern bygd inn i design
Ikkje eit tillegg, men ein integrert del.

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

5. Tryggleik gjennom heile livssyklusen
Frå innsamling til sletting.

6. Synlegheit og gjennomsikt
Brukarar skal kunne sjå kva som skjer med dataa deira.

7. Respekt for personvernet til brukaren
Brukarvennleg og brukarorientert.

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å vere:

1. Frivillig: Ikkje tvinga eller vilkår for teneste (hvis ikkje nødvendig)
2. Spesifikt: For kvart formål
3. Informert: Brukar veit kva dei samtykkjer til
4. Utvetydig: Aktiv handling, ikkje førehandsavkryssa
5. Tilbaketrekkbart: Lett å trekkje tilbake

Dårlege eksempel:

<!-- 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 eksempel:

<!-- 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 brukarar om:

1. Kven er handsamingsansvarleg (di bedrift)
2. Kva samlar du inn (kva for data)
3. Kvifor (formål med handsaminga)
4. Korleis (handsamingsgrunnlag - samtykke, avtale, etc.)
5. Kor lenge (lagringstid)
6. Kven andre får tilgang (databehandlarar, tredjepartar)
7. Rettar (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 brukarar ei rekkje rettar som du må støtte i systemet ditt:

1. Rett til innsyn
Brukarar kan be om kopi av alle data du har om dei.

@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
Brukarar kan krevje at feil data blir retta.

@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 gløymd")
Brukarar kan be om at data blir sletta.

@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
Brukarar kan få data i maskinlesbart format for å flytte til ei anna teneste.

@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
Brukarar kan protestere mot visse typar handsaming.

6. Rett til avgrensing
Brukarar kan krevje at handsaming blir avgrensa medan ei sak blir undersøkt.

✏️Eksempel: GDPR-kompatibel brukarsletting

Her er eit komplett eksempel på korleis du implementerer brukarsletting i samsvar med 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 berre det nødvendige.
- Pseudonymisering vs. anonymisering: reverserbar mot ureverserbar.
- GDPR i praksis: standardinnstillingar og brukarsletting.
- Dataetikk: ansvarleg bruk av persondata.
- Innebygd personvern: privacy by design.

Nøkkelomgrep


OmgrepForklaring
DataminimeringSamle berre nødvendige data
PseudonymiseringKan reverserast med nøkkel
AnonymiseringKan ikkje reverserast

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.