Create whitepaper.md
This commit is contained in:
+799
@@ -0,0 +1,799 @@
|
||||
# Bürgerabstimmung — Whitepaper
|
||||
|
||||
**Digitale Bürgerbeteiligung mit dem Personalausweis. Themen einbringen, abstimmen, gemeinsam prüfen.**
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| Arbeitstitel / Marke | **Bürgerabstimmung** |
|
||||
| Domain (vorgeschlagen) | **buergerabstimmung.de** (Alternativen: buergerabstimmung.eu, abstimmungsportal.de) |
|
||||
| Status | Konzept & technischer Prototyp (Testbetrieb, keine offizielle Seite einer Behörde) |
|
||||
| Sprachen | Deutsch (Standard), Englisch |
|
||||
| Version | 1.0 · August 2026 |
|
||||
|
||||
> **Wichtiger Hinweis:** Bürgerabstimmung ist ein privates Konzept- und Demonstrationsprojekt.
|
||||
> Es ist **keine offizielle Seite der Bundesregierung oder einer Behörde** und erhebt
|
||||
> nicht den Anspruch, staatliche Verfahren rechtlich zu ersetzen. Der Prototyp zeigt,
|
||||
> wie eine solche Plattform funktionieren könnte. Solange der Testbetrieb läuft, zeigt
|
||||
> die Seite dauerhaft ein entsprechendes Hinweisbanner an (im Code über die
|
||||
> Konfigurationsvariable `show_test_banner = true` gesteuert). Eine frische
|
||||
> Installation startet im **Testmodus**; er wird über die Oberfläche beendet und
|
||||
> löscht dabei alle bis dahin entstandenen Testdaten (Kapitel 5.3b).
|
||||
|
||||
---
|
||||
|
||||
## 1. Zusammenfassung
|
||||
|
||||
Bürgerabstimmung ist eine Plattform für direkte, fortlaufende Bürgerbeteiligung. Jede Person
|
||||
mit deutschem Personalausweis kann:
|
||||
|
||||
- **Themen einbringen** — maximal eines pro Tag, mit Ziel, Begründung, Kategorie und
|
||||
räumlicher Ebene (Landkreis/kreisfreie Stadt, Bundesland, Deutschland; die
|
||||
Gemeindeebene folgt in der Ausbaustufe),
|
||||
- **abstimmen** — dafür oder dagegen; wer sich enthält, stimmt schlicht nicht ab,
|
||||
- **rechtswidrige Inhalte melden** — geprüft nicht von einer Redaktion, sondern von
|
||||
einer zufällig ausgelosten **Bürger-Jury** (1 % aller aktiven Ausweis-Pseudonyme),
|
||||
- **seine Gesamtansicht abrufen** — durch Auflegen des Ausweises (NFC) erscheinen alle
|
||||
eigenen Themen, Stimmen und Favoriten.
|
||||
|
||||
Die Identität wird ausschließlich über die **eID-Funktion des Personalausweises**
|
||||
nachgewiesen: Der Chip beweist kryptographisch die Echtheit der Karte (privater
|
||||
Schlüssel im Chip). Die Plattform kennt als Identität nur den **öffentlichen
|
||||
Schlüssel** — keinen Namen, keine Adresse, kein Geburtsdatum, kein abgeleitetes
|
||||
Pseudonym. Eine Karte = ein Konto. Das persönliche Profil wird an diesen
|
||||
öffentlichen Schlüssel **verschlüsselt** und vom Server **signiert**
|
||||
(manipulationssicher); die Stimmen werden **unverkettbar** gespeichert, sodass
|
||||
niemand rückschließen kann, wer wie gestimmt hat.
|
||||
|
||||
Die Plattform ist bewusst **schlicht und amtlich-neutral** gestaltet, funktioniert
|
||||
gleichwertig auf Smartphone und PC, passt sich hellem und dunklem Systemdesign an und
|
||||
ist auch an öffentlichen Geräten (z. B. in Gemeindebüros oder Bibliotheken) nutzbar —
|
||||
für Menschen ohne eigenes Gerät.
|
||||
|
||||
---
|
||||
|
||||
## 2. Marke, Domain, Gestaltung
|
||||
|
||||
### 2.1 Name
|
||||
|
||||
**Bürgerabstimmung** — bewusst **kein Kunstwort und keine Marke**, sondern die
|
||||
schlichte Sachbezeichnung: Bürgerinnen und Bürger stimmen ab. So würde eine
|
||||
Verwaltung die Sache benennen, und genau das ist der Zweck des Namens — er
|
||||
verspricht nichts, was er nicht ist.
|
||||
|
||||
Bewusst **nicht** gewählt wurden „Wahl…“ und „Bürgerentscheid“: Beides sind
|
||||
rechtlich belegte Begriffe für verbindliche Verfahren nach Wahl- und
|
||||
Gemeinderecht. Diese Plattform ist ein Meinungsbildungs-Kanal **ohne
|
||||
Rechtsverbindlichkeit**; ein Name aus dem Wahlrecht würde eine Wirkung
|
||||
suggerieren, die sie nicht hat.
|
||||
|
||||
Zugleich ist der Name **nicht mit staatlichen Kennzeichen verwechselbar**: kein
|
||||
Bundesadler, keine Bundesfarben-Imitation, kein „bund.de“-Look. Vor einem echten
|
||||
Betrieb sind Marken- und Domainrecherche erforderlich — die reine
|
||||
Sachbezeichnung ist als Wortmarke voraussichtlich nicht schutzfähig, was für
|
||||
diesen Zweck kein Nachteil ist.
|
||||
|
||||
### 2.2 Domain
|
||||
|
||||
Vorschlag: **buergerabstimmung.de** (Sachbezeichnung, aussprechbar, .de passt
|
||||
zum Zweck). Ausweichoptionen: buergerabstimmung.eu, buerger-abstimmung.de,
|
||||
abstimmungsportal.de. Im Auslieferungszustand ist in der Konfiguration **keine
|
||||
Domain eingetragen** — sie wird erst beim Aufsetzen gesetzt.
|
||||
|
||||
### 2.3 Gestaltungsprinzipien
|
||||
|
||||
1. **Schlicht wie eine App:** ruhige graue Fläche, weiße Karten mit weichen
|
||||
Ecken, Haarlinien statt Rahmen, Systemschrift, **ein** blauer Akzent —
|
||||
die Formensprache verbreiteter Messenger-/Systemoberflächen (iOS, Signal).
|
||||
Keine Verläufe, keine Deko-Effekte, keine „KI-Regenbogen“-Ästhetik; Rot
|
||||
bleibt destruktiven Aktionen (Löschen) vorbehalten, Gelb allein dem
|
||||
Testbetrieb-Banner.
|
||||
2. **Keine KI-Hinweistexte** auf der Seite. Die Seite spricht als Produkt, nüchtern
|
||||
und in Sie-Form. Es steht nur Text da, der eine Entscheidung trägt:
|
||||
Erklärsätze unter selbsterklärenden Überschriften, Wiederholungen von Zahlen
|
||||
und Beschriftungen wie „Eingebracht am“ entfallen.
|
||||
3. **Hell/Dunkel automatisch:** Das Design folgt ausschließlich der
|
||||
Systemeinstellung (`prefers-color-scheme`) — es wird bewusst nichts im
|
||||
Browser gespeichert, auch keine Design-Präferenz.
|
||||
4. **Symbolhafter Einstieg:** Beim Sitzungsbeginn nur der Schriftzug und die
|
||||
Sprachwahl — **Deutsch/English als Knöpfe mit Flagge**, ohne Bildmarke; die
|
||||
Anmeldung führt ein Ausweis-Piktogramm mit NFC-Wellen an, Text bleibt
|
||||
minimal. Die Kopfzeile der Seite trägt weder Wortmarke noch Anmeldestatus,
|
||||
sondern nur die nötigen Bedienelemente; die Fußzeile nur Impressum und
|
||||
Datenschutz. Das Impressum trägt im Prototyp bewusst nur einen Platzhalter
|
||||
(ein `*` als Überschrift und als Text) — es ist vor einem echten Betrieb mit
|
||||
den Pflichtangaben des Betreibers zu füllen, die Datenschutzerklärung ist an
|
||||
den tatsächlichen Betrieb anzupassen.
|
||||
|
||||
**Bildmarke (Tab-/App-Icon):** ein **Häkchen im Feld** — scharfe Kanten,
|
||||
keine abgerundeten Ecken, keine Farbe. Als SVG folgt es der
|
||||
Systemeinstellung (schwarze Fläche mit weißem Kreuz im Hellmodus, weiße
|
||||
Fläche mit schwarzem Kreuz im Dunkelmodus); PNG und ICO für Safari/iOS
|
||||
liefern dieselbe Marke als geschlossene dunkle Kachel.
|
||||
5. **Responsiv:** eine Codebasis für Smartphone, Tablet, PC und Terminals. Die
|
||||
**tragenden** Funktionen — anmelden, Thema einbringen, abstimmen, melden,
|
||||
Jury — laufen ohne JavaScript; alle Fenster sind `:target`-Dialoge, alle
|
||||
Eingaben normale Formulare. JavaScript ergänzt: Countdown, NFC-Auslösung,
|
||||
die stufige Geltungsbereichs-Auswahl, die Live-Zahlen und den Hinweis auf
|
||||
ähnliche Themen. **Eine Ausnahme:** die `profil.yaml` wird ausschließlich per
|
||||
`fetch` geladen — ohne JavaScript gibt es keine Selbstauskunft. Das ist vor
|
||||
einem Echtbetrieb zu ergänzen.
|
||||
6. **Testbetrieb-Banner:** Solange die Konfigurationsvariable
|
||||
`show_test_banner` auf `true` steht (Auslieferungszustand), zeigt jede Seite oben
|
||||
ein deutliches Banner: *„Testbetrieb — keine offizielle Seite der
|
||||
Bundesregierung oder einer Behörde.“* Der **Testmodus** selbst ist keine
|
||||
Variable, sondern ein Zustand der Installation (Kapitel 5.3b).
|
||||
7. **Barrierearmut:** semantisches HTML, Tastaturbedienung, ausreichende Kontraste.
|
||||
Die Abstimmungsbalken nutzen **Akzentblau gegen Neutralgrau** — auf
|
||||
Farbfehlsichtigkeit geprüft (CVD-Abstand ΔE 18,3 hell / 16,6 dunkel) — und
|
||||
tragen immer Beschriftung samt Prozentwert; Bedeutung hängt nie an Farbe
|
||||
allein. Vollständige BITV-Konformität ist Ziel der Ausbaustufe.
|
||||
|
||||
---
|
||||
|
||||
## 3. Leitidee und Einordnung
|
||||
|
||||
Bürgerabstimmung versteht sich als **ständiger Meinungsbildungs-Kanal**: Statt alle vier
|
||||
Jahre ein Kreuz zu machen, können Bürgerinnen und Bürger laufend Anliegen einbringen
|
||||
und gewichten — von der Radweg-Frage in der Gemeinde bis zur bundespolitischen
|
||||
Grundsatzfrage. Die Ergebnisse sind ein präzises, manipulationsarmes Stimmungsbild,
|
||||
das Politik auf allen Ebenen nutzen kann.
|
||||
|
||||
Bewusste Abgrenzung:
|
||||
|
||||
- Bürgerabstimmung **ersetzt keine rechtlich bindenden Verfahren** (Wahlen, Volksentscheide).
|
||||
Ergebnisse sind Meinungsbilder; eine rechtliche Bindung wäre ein politischer
|
||||
Folgeschritt, kein technischer.
|
||||
- Die Plattform ist **strikt neutral**: Zum Start existieren ausschließlich
|
||||
Kategorien über das gesamte politische Spektrum, keine vorbefüllten Themen
|
||||
(siehe 6.3); die Moderation erfolgt durch geloste Jurys nach
|
||||
strafrechtlichen — nicht politischen — Kriterien.
|
||||
|
||||
---
|
||||
|
||||
## 4. Zugänge und Zielgruppen
|
||||
|
||||
- **Smartphone:** Ausweis per NFC ans Gerät halten, PIN in der eID-App eingeben,
|
||||
fertig. Der Browser selbst berührt die Karte nie.
|
||||
- **PC:** eID-Client (z. B. AusweisApp) mit USB-Kartenleser oder gekoppeltem
|
||||
Smartphone als Leser.
|
||||
- **Öffentliche Geräte:** Gemeinden, Bürgerbüros und Bibliotheken können Terminals
|
||||
bereitstellen. Dafür ausgelegt: kurze Sitzungen, automatische Abmeldung nach
|
||||
Inaktivität, keine lokalen Datenspuren, prominenter Abmelden-Knopf.
|
||||
- **Fremde Geräte:** Da die Anmeldung nur mit physischer Karte + PIN funktioniert und
|
||||
keine Passwörter existieren, kann bedenkenlos das Gerät einer anderen Person
|
||||
genutzt werden.
|
||||
|
||||
Sprachen: **Deutsch und Englisch**. Die Wahl erfolgt beim Sitzungsbeginn,
|
||||
gilt für die Sitzung und wird **nirgends gespeichert** — weder im Browser noch
|
||||
am Konto. Ohne aufgelegten Ausweis ist die Seite nicht sichtbar (nur Anmeldung
|
||||
und Rechtliches sind offen).
|
||||
|
||||
---
|
||||
|
||||
## 5. Identität: die eID des Personalausweises
|
||||
|
||||
### 5.1 Prinzip
|
||||
|
||||
Jeder deutsche Personalausweis (seit 2010) enthält einen Chip mit
|
||||
Online-Ausweisfunktion (eID). Die Echtheit beweist der Chip kryptographisch: Er
|
||||
besitzt **private Schlüssel, die das Chipmaterial nie verlassen**, und die Gegenseite
|
||||
prüft die zugehörigen Zertifikate gegen die **staatliche Zertifikatskette** (Country
|
||||
Verifying CA / Document Verifier, BSI-Standards TR-03110, TR-03130). Kopierte oder
|
||||
gefälschte Karten fallen bei dieser Prüfung durch.
|
||||
|
||||
Für Bürgerabstimmung entscheidend ist die Funktion **„dienstespezifisches Kennzeichen“
|
||||
(Restricted Identification)**: Der Chip errechnet pro Dienst ein stabiles Pseudonym.
|
||||
|
||||
- Dasselbe Pseudonym bei jedem Anhalten derselben Karte bei Bürgerabstimmung → **ein
|
||||
Konto pro Karte**, Wiedererkennung ohne Klarnamen.
|
||||
- Ein anderes Pseudonym bei jedem anderen Dienst → **keine Verkettbarkeit** über
|
||||
Dienste hinweg.
|
||||
- Bürgerabstimmung fragt **keine** Klardaten ab (kein Name, keine Anschrift, kein
|
||||
Geburtsdatum). Es wird auch **kein eigenes Pseudonym erzeugt oder
|
||||
zugeordnet**: Identität ist unmittelbar der öffentliche Schlüssel („on
|
||||
the go“); Stimmen werden auf dem Server direkt für diesen Schlüssel
|
||||
eingetragen.
|
||||
|
||||
### 5.2 Ablauf (Produktion)
|
||||
|
||||
1. Nutzer wählt „Ausweis auflegen“. Die Plattform startet über den eID-Client
|
||||
(AusweisApp, Schnittstelle nach TR-03124) eine Authentisierung beim zugelassenen
|
||||
**eID-Server** (TR-03130).
|
||||
2. Nutzer hält die Karte an das NFC-Smartphone bzw. den Kartenleser und gibt die
|
||||
sechsstellige **Ausweis-PIN** ein.
|
||||
3. Chip und eID-Server authentisieren sich gegenseitig (PACE, Terminal- und
|
||||
Chip-Authentisierung); der eID-Server prüft Echtheit und Sperrliste und übermittelt
|
||||
Bürgerabstimmung **nur das Pseudonym**.
|
||||
4. Bürgerabstimmung nimmt den geprüften öffentlichen Schlüssel unmittelbar als Kennung und meldet die Sitzung an.
|
||||
|
||||
Voraussetzung für den Echtbetrieb ist ein **Berechtigungszertifikat** der
|
||||
Vergabestelle für Berechtigungszertifikate (Bundesverwaltungsamt) mit dem
|
||||
Berechtigungsumfang „pseudonymer Zugang“ sowie ein zertifizierter eID-Server
|
||||
(eigenbetrieben oder als Dienstleistung).
|
||||
|
||||
### 5.3 Prototyp (dieses Repository)
|
||||
|
||||
Der Prototyp bildet das Verfahren originalgetreu nach: Eine simulierte
|
||||
Testkarte im Browser übernimmt die Rolle des Chips und hält ein echtes
|
||||
Ed25519-Schlüsselpaar (libsodium). Beim „Ausweis auflegen“ signiert der
|
||||
private Schlüssel eine Zufallsnachricht; der Server prüft die Signatur
|
||||
gegen den öffentlichen Schlüssel und leitet daraus das Pseudonym ab.
|
||||
**Zwei getrennte Vorgänge:**
|
||||
|
||||
1. **Profil laden (initiales Anhalten):** Die statische Challenge ist der
|
||||
öffentliche Schlüssel selbst, zeitgebunden versiegelt. Der Server öffnet
|
||||
den Nachweis mit dem öffentlichen Schlüssel und liefert die
|
||||
**profil.yaml** (alle eigenen Stimmen, Themen, Favoriten, Jury-Status)
|
||||
in den Browser; der Abmelde-Knopf löscht sie dort wieder. Der Nachweis
|
||||
ist **TOTP-artig zeitbegrenzt** (5-Minuten-Fenster, Anmeldung gilt
|
||||
höchstens zwei Fenster) — danach ist erneutes Anhalten nötig.
|
||||
2. **Stimmabgabe und jede andere Änderung (unabhängig davon):** Die Karte
|
||||
erstellt je Vorgang einen **versiegelten Umschlag** (kombinierte
|
||||
Signatur über Aktion + Zeitfenster + Zufallswert); der Server
|
||||
**öffnet ihn mit dem öffentlichen Schlüssel** und trägt die Stimme für
|
||||
genau diesen Schlüssel ein. Derselbe Vorgang ergibt zu anderer Zeit
|
||||
einen anderen Umschlag; alte Umschläge verfallen.
|
||||
|
||||
Zusätzlich trägt jedes Formular ein **Einmal-Token** (beim Einlösen
|
||||
verbraucht — Wiederholungen laufen ins Leere), und im Browser liegt außer
|
||||
der Sitzungs-ID nur die bewusst geladene profil.yaml. Am Smartphone ist
|
||||
der NFC-Leser auf der Anmeldeseite automatisch scharf: Das Auflegen des
|
||||
(echten) Personalausweises löst die Anmeldung direkt aus (Web NFC; der
|
||||
Knopf bleibt Rückfall und Berechtigungsgeste).
|
||||
|
||||
### 5.3b Testmodus als Zustand, nicht als Variable
|
||||
|
||||
Eine frische Installation startet **im Testmodus**. Er ist kein Schalter in
|
||||
der Konfigurationsdatei, sondern ein Zustand in der Datenbank
|
||||
(`schema_info.test_mode`), damit eine Vorführung ohne Codeänderung möglich
|
||||
ist und der Übergang in den Echtbetrieb protokolliert wird.
|
||||
|
||||
- **Im Testmodus** zeigt die Anmeldeseite **genau einen Knopf**. Er erzeugt
|
||||
eine zufällige, als gültig behandelte Sitzung; Ausweis-Aufforderungen bei
|
||||
Änderungen entfallen. Das Banner bleibt unabhängig davon sichtbar.
|
||||
- **Beendet wird er über die Oberfläche**: Der Chip „Testmodus“ in der
|
||||
Kopfzeile führt auf die Seite **„Echtbetrieb einrichten“** (Kapitel 5.3c).
|
||||
Dort wird der Zugang für den Echtbetrieb festgelegt, geprüft und
|
||||
umgeschaltet. Das Umschalten **löscht alle im Testbetrieb entstandenen
|
||||
Daten** — Themen, Stimmen, Merkzettel, Meldungen, Jury-Sitze, Konten und die
|
||||
im Testmodus erzeugten Ausweis-Schlüssel. Kategorien, System-Konto und eine
|
||||
echte Freigabeliste bleiben. Der Schritt ist bewusst nicht umkehrbar.
|
||||
- **Danach** existiert kein Weg mehr in die Anwendung, der ohne Ausweis
|
||||
auskommt: Die Anmeldeseite bietet nur noch die Ausweis-Apps an, und die
|
||||
Einrichtungsseite ist geschlossen.
|
||||
|
||||
### 5.3c Einrichtung des Echtbetriebs aus der Anwendung heraus
|
||||
|
||||
Der Übergang vom Testbetrieb zum Echtbetrieb ist kein Eingriff in den
|
||||
Quelltext, sondern ein geführter Schritt in der Oberfläche. Die Seite
|
||||
„Echtbetrieb einrichten“ leistet dreierlei:
|
||||
|
||||
1. **Voraussetzungen prüfen.** Sie zeigt, ob das Datenverzeichnis beschreibbar
|
||||
ist, HTTPS anliegt, die Kryptographie-Erweiterung vorhanden ist, der
|
||||
Zugriffsschutz greift und wie viele Ausweis-Schlüssel freigegeben sind.
|
||||
2. **Zugang festlegen.** Zur Wahl stehen der **eigene eID-Server** (Anmeldung
|
||||
über die Ausweis-App; setzt Berechtigungszertifikat und einen Server nach
|
||||
TR-03130 voraus) und die **eigene Trust-Liste** (Anmeldung nur mit
|
||||
Schlüsseln aus der Freigabeliste, befüllt über eine Abgleich-Adresse oder
|
||||
`issue-card`). Erfasst werden SOAP-Adresse, Client-Zertifikat und
|
||||
-Schlüssel, die Aktivierungsadresse der Ausweis-App, die Abgleich-Adresse
|
||||
der Freigabeliste und die Startadresse von Nect. Ein Knopf **prüft die
|
||||
Verbindung** zum eID-Server, bevor irgendetwas verändert wird.
|
||||
3. **Umschalten.** Erst wenn die Eingaben gültig sind, der eID-Server
|
||||
antwortet und der **Einrichtungsschlüssel** stimmt, werden die Einstellungen
|
||||
nach `data/config.yaml` (Rechte 0600, vom Web nicht erreichbar)
|
||||
geschrieben, die Testdaten gelöscht und der Echtbetrieb dauerhaft
|
||||
aktiviert.
|
||||
|
||||
Der **Einrichtungsschlüssel** steht in `data/setup.token` und ist nur über
|
||||
Dateizugriff oder `php index.php setup-token` lesbar. Damit kann das
|
||||
Umschalten nur, wer den Server betreibt — nicht jeder, der sich im Testbetrieb
|
||||
per Knopfdruck eine Sitzung erzeugen kann. Nach dem Umschalten wird die Datei
|
||||
gelöscht.
|
||||
|
||||
Die Einstellungen aus `config.yaml` überlagern beim Start die Vorgaben im
|
||||
Quelltext; übernommen wird ausschließlich eine feste Liste erlaubter
|
||||
Schlüssel. `php index.php config` zeigt den wirksamen Stand.
|
||||
|
||||
Der Wechsel auf einen echten eID-Server ersetzt nur den Karten-Block; Regeln
|
||||
und Abläufe bleiben identisch.
|
||||
|
||||
### 5.3d Anbindung der AusweisApp (TR-03124/TR-03130)
|
||||
|
||||
Die Anmeldung mit der AusweisApp ist direkt eingebaut und braucht auf der
|
||||
Serverseite nichts als den Webserver und diese Datei:
|
||||
|
||||
1. Der Knopf „Mit AusweisApp anmelden“ leitet den Browser auf die
|
||||
**Aktivierungsadresse des eID-Clients** nach TR-03124:
|
||||
`http://127.0.0.1:24727/eID-Client?tcTokenURL=…`. Die AusweisApp — am PC wie
|
||||
am Smartphone — fängt diese Adresse ab.
|
||||
2. Die App holt das **tcToken** unter `/eid/tctoken` ab. Sie tut das als
|
||||
eigener HTTP-Client **ohne Browser-Cookie**; deshalb trägt die tcTokenURL
|
||||
einen **Einmal-Nonce** (10 Minuten gültig), der Browsersitzung und
|
||||
Ausweis-Vorgang verbindet.
|
||||
3. Mit hinterlegtem **eID-Server** (TR-03130, `eid_server_url`) fordert der
|
||||
Server dort per `useID` eine Sitzung an und liefert der App ServerAddress,
|
||||
SessionIdentifier und RefreshAddress. Die App liest den Chip PIN-geschützt
|
||||
aus und schickt den Browser zurück auf `/eid/callback`.
|
||||
4. **Ohne** eID-Server liefert das tcToken bewusst nur eine
|
||||
`CommunicationErrorAddress`. Die AusweisApp bricht sauber ab, der Browser
|
||||
kehrt zurück — **angemeldet wird niemand**. Das ist die ehrliche Grenze:
|
||||
Einen eID-Server darf nur betreiben, wer ein **Berechtigungszertifikat des
|
||||
BVA** besitzt (Kapitel 5.3e).
|
||||
|
||||
### 5.3e Autorisierte Schlüssel (Freigabeliste) und ehrliche Grenzen der eID
|
||||
|
||||
Anmelden kann sich ausschließlich, wessen **öffentlicher Schlüssel in einer
|
||||
serverseitigen Allowlist** steht (`data/authorized_keys.yaml`) und wer den
|
||||
passenden **privaten Schlüssel** besitzt (zeitgebundene Signatur-Challenge).
|
||||
Damit ist ausgeschlossen, dass ein Knopfdruck ohne Ausweis oder mit einem
|
||||
fremden/gefälschten Schlüssel Zugang gewährt (fail-closed).
|
||||
|
||||
Ehrliche Einordnung zur oft gewünschten „Liste aller Ausweis-Schlüssel“:
|
||||
Eine solche staatliche Liste **existiert nicht** und wäre auch nicht
|
||||
wünschenswert (sie wäre ein Register der kryptographischen Identität aller
|
||||
Bürgerinnen und Bürger). Der Personalausweis weist sich stattdessen über die
|
||||
**BSI-Zertifikatskette** (TR-03110: Chip-Authentisierung gegen CVCA/DV) aus,
|
||||
geprüft durch einen zertifizierten **eID-Server** (TR-03130); das Auslesen des
|
||||
Chips erfolgt PIN-geschützt ausschließlich über die **AusweisApp** (ein Browser
|
||||
kann den Chip nicht lesen). Im Prototyp ist die Allowlist deshalb der
|
||||
Platzhalter für genau diese Vertrauensprüfung: Der Modus `eid` übergibt an den
|
||||
eID-Server/die AusweisApp; der Modus `demo` nutzt per `issue-card` ausgegebene,
|
||||
autorisierte Test-Ausweise. Die Funktion `sync-keys` ist der Anschlusspunkt für
|
||||
eine eigene Trust-Liste bzw. eID-Server-Anbindung – kein Zugriff auf ein
|
||||
Behördenregister.
|
||||
|
||||
### 5.4 Grenzen und Missbrauchsszenarien
|
||||
|
||||
- **Karte ≠ Person am Gerät:** Wie bei jeder eID-Nutzung kann eine Person freiwillig
|
||||
ihre Karte + PIN einer anderen überlassen. Das ist rechtswidrig, skaliert aber
|
||||
schlecht (physische Karte nötig) — genau dadurch werden Bot-Netze und
|
||||
Massen-Manipulation wirksam verhindert.
|
||||
- **Verlorene/gesperrte Ausweise** fallen über die Sperrlistenprüfung des eID-Servers
|
||||
heraus.
|
||||
- **Alters-/Staatsangehörigkeitsfragen:** Die eID steht auch Unionsbürgern (eAT,
|
||||
eID-Karte) offen; ob deren Teilnahme gewünscht ist, ist eine politische
|
||||
Konfigurationsentscheidung (Berechtigungszertifikat kann die Kartentypen
|
||||
einschränken). Der Prototyp behandelt alle Karten gleich.
|
||||
|
||||
---
|
||||
|
||||
## 6. Funktionen im Einzelnen
|
||||
|
||||
### 6.1 Themen einbringen — „1 Thema pro Tag“
|
||||
|
||||
- Jedes Pseudonym kann **ein Thema pro Kalendertag** (Zeitzone Europe/Berlin)
|
||||
erstellen; um **00:00 Uhr** beginnt der nächste Tag. Die Regel ist zusätzlich zur
|
||||
Anwendungslogik als **Datenbank-Constraint** verankert (UNIQUE über Autor +
|
||||
Erstelldatum) — sie kann also auch durch Programmierfehler nicht umgangen werden.
|
||||
- Pflichtfelder beim Erstellen:
|
||||
- **Titel** (kurz, prägnant),
|
||||
- **Ziel** — was soll konkret erreicht werden?
|
||||
- **Begründung** — warum?
|
||||
- **Kategorie** (siehe 6.3),
|
||||
- **Geltungsbereich** — eine hierarchische **Auswahl statt Freitext**,
|
||||
wie auf Behördenseiten: Deutschland → Bundesland → Landkreis/kreisfreie
|
||||
Stadt (eingebaute Gebietsliste mit allen 16 Ländern und rund 400
|
||||
Kreisen; die Gemeindeebene folgt in der Ausbaustufe über das amtliche
|
||||
Gemeindeverzeichnis, ARS/Destatis).
|
||||
- **Themen sind nach Veröffentlichung unveränderlich.** Es gibt keinen
|
||||
Bearbeiten-Weg — weder in der Oberfläche noch als Route. Damit ist die stille
|
||||
Umdeutung einer laufenden Abstimmung ausgeschlossen: Woran abgestimmt wurde,
|
||||
steht fest. Wer sich vertan hat, archiviert das Thema (solange noch keine
|
||||
Stimme abgegeben ist) und bringt es neu ein. Eine spätere Ausbaustufe könnte
|
||||
Korrekturen mit sichtbarer Versionsanzeige erlauben.
|
||||
|
||||
### 6.2 Abstimmen
|
||||
|
||||
- Pro Thema und Ausweis genau eine Stimme: **dafür** oder **dagegen**.
|
||||
- **Neutral = nicht abstimmen.** Enthaltung wird nicht als eigene Stimmart gezählt.
|
||||
- Die eigene Stimme ist **24 Stunden lang** änderbar oder zurückziehbar; danach
|
||||
ist sie fest (auf der Hauptseite als eigene Gruppe „kürzlich abgestimmt,
|
||||
noch änderbar“ sichtbar).
|
||||
- **Stimmen sind unverkettbar gespeichert:** In der Datenbank steht kein
|
||||
Ausweis-Bezug, sondern nur ein HMAC aus Thema + öffentlichem Schlüssel mit
|
||||
serverseitigem Geheimnis. Doppelstimmen sind ausgeschlossen, doch ohne das
|
||||
Geheimnis lässt sich nicht rückschließen, welcher Ausweis wie gestimmt hat.
|
||||
- **Abstimmungsende je Thema — Datum, Zielwert oder beides:** Beim Einbringen
|
||||
sind zwei Bedingungen ankreuzbar: ein **Enddatum** und ein **Zielwert**
|
||||
(Einheit „X Stimmen“ für eine feste Zahl oder „% Stimmen“ für einen Anteil
|
||||
der registrierten Ausweise).
|
||||
Gesetzt werden darf eine von beiden **oder beide zugleich** — dann endet die
|
||||
Abstimmung, **was zuerst eintritt**. Prozentangaben werden beim Anlegen in
|
||||
eine absolute Zahl umgerechnet, damit das Ziel im Verlauf nicht mit der
|
||||
Nutzerzahl wandert. Für **jeden** Zielwert gilt zusätzlich eine Untergrenze
|
||||
von 10 Stimmen — auch ein ausdrücklich kleinerer Wert wird stillschweigend
|
||||
darauf angehoben. Danach ist das Thema beendet.
|
||||
- **Themen werden nie gelöscht.** Es gibt keinen Löschweg für Verfasser. Ein
|
||||
Thema, zu dem **noch niemand abgestimmt** hat, lässt sich **archivieren**:
|
||||
Es verschwindet aus Listen, Suche und Ähnlichkeitsabgleich, ist nicht mehr
|
||||
wählbar und nicht mehr meldbar, bleibt aber unter
|
||||
seiner Adresse erhalten und trägt dort die Kennzeichnung „Archiviert“.
|
||||
- **Abgestimmte Themen bleiben unverändert bestehen.** Sobald die erste Stimme
|
||||
abgegeben ist, entfällt auch das Archivieren — der Knopf ist dann schlicht
|
||||
nicht mehr da. Damit bleibt jedes Thema, über das abgestimmt wurde, dauerhaft
|
||||
nachvollziehbar. (Davon unberührt ist die Entfernung durch eine Bürger-Jury
|
||||
nach festgestelltem Gesetzesverstoß, Kapitel 7.)
|
||||
- **Gleiche Titel sind erlaubt, aber sichtbar.** Beim Einbringen zeigt das
|
||||
Formular schon während des Tippens, ob es bereits ähnliche Themen gibt, und
|
||||
verlinkt sie; einbringen lässt sich das Thema trotzdem. Auf der Themenseite
|
||||
steht dieselbe Liste unter „Ähnliche Themen“. Der Abgleich vergleicht die
|
||||
bedeutungstragenden Wörter des Titels, nicht die Zeichenkette.
|
||||
- **Ergebnisse aktualisieren sich ohne Neuladen.** Ein schlanker JSON-Endpunkt
|
||||
liefert Stimmenstände; Liste und Themenseite schreiben Balken, Zahlen und
|
||||
Anteile im Hintergrund fort (alle zwölf Sekunden und beim Zurückkehren auf
|
||||
den Tab). Ohne JavaScript bleibt der beim Aufruf gerenderte Stand stehen —
|
||||
die Seite funktioniert weiterhin vollständig.
|
||||
- Die Darstellung ist überall dieselbe und bewusst knapp: ein Balken, darunter
|
||||
„Dafür n / x %“ und „Dagegen n / y %“ — in der Liste als Haarlinie, auf der
|
||||
Themenseite kräftiger.
|
||||
- **Drei Symbole oben rechts am Thema**, auf einer Höhe mit den Schildern für
|
||||
Kategorie und Gebiet: ein **Lesezeichen** zum Merken (Thema, Kategorie,
|
||||
Gebiet), eine **Archivbox** für den Verfasser eines Themas ohne Stimmen und
|
||||
eine **rote Flagge** zum Melden. Die Flagge fehlt beim eigenen Thema und bei
|
||||
beendeten Abstimmungen; läuft bereits eine Meldung, steht sie unterlegt und
|
||||
ohne Funktion da. Beschriftungen tragen die Symbole nur als `title` und
|
||||
`aria-label`.
|
||||
- **Auf der Themenseite steht der eigene Stand in den Knöpfen, nicht in einem
|
||||
Satz.** Dort gibt es keinen erklärenden Text zur eigenen Stimme; ihr Zustand
|
||||
ist an den beiden Knöpfen ablesbar: beide grau, solange nicht gewählt wurde; die gewählte Seite
|
||||
blau, solange sie sich noch ändern lässt; nach Ablauf der 24 Stunden und bei
|
||||
beendeter Abstimmung die gewählte Seite blass-blau, die andere abgedunkelt,
|
||||
beide nicht mehr bedienbar. Serverseitig wird eine dann noch abgesetzte
|
||||
Stimme unabhängig davon abgewiesen. In der **Themenliste** und in der Gruppe
|
||||
„kürzlich abgestimmt“ steht die eigene Stimme dagegen weiterhin als Text
|
||||
(„Ihre Stimme: Dafür“, dort mit Frist) — Knöpfe, an denen man sie ablesen
|
||||
könnte, gibt es dort nicht.
|
||||
|
||||
### 6.3 Kategorien — Neutralität durch Breite, keine vorbefüllten Themen
|
||||
|
||||
Damit die Plattform von Beginn an nicht als politisch gefärbt wahrgenommen wird,
|
||||
gilt das **Breitenprinzip auf Kategorien-Ebene**: Zum Start existieren
|
||||
ausschließlich die Kategorien — bewusst viele, quer über das gesamte politische
|
||||
Spektrum. **Themen werden nicht vorbefüllt**; jeder einzelne Inhalt der
|
||||
Plattform stammt aus der Bürgerschaft. So kann keine Startauswahl als
|
||||
redaktionelle oder politische Setzung gelesen werden.
|
||||
|
||||
Kategorien (Start-Satz, erweiterbar):
|
||||
|
||||
Umwelt & Klima · Energie · Wirtschaft & Mittelstand · Arbeit & Soziales · Rente &
|
||||
Alterssicherung · Gesundheit & Pflege · Bildung & Forschung · Familie & Jugend ·
|
||||
Migration & Integration · Innere Sicherheit · Justiz & Bürgerrechte · Digitales &
|
||||
Verwaltung · Verkehr & Infrastruktur · Wohnen & Mieten · Landwirtschaft & Ernährung ·
|
||||
Finanzen & Steuern · Europa & Außenpolitik · Verteidigung · Kultur, Medien & Sport ·
|
||||
Verbraucherschutz · Kommunales & Ehrenamt · Demokratie & Beteiligung
|
||||
|
||||
### 6.4 Merkzettel und eigener Stand
|
||||
|
||||
- **Einzelne Themen, Kategorien und Gebiete lassen sich merken**: Am Thema
|
||||
steht dafür ein **Lesezeichen-Symbol**, das ein kleines Auswahlfeld mit drei
|
||||
Einträgen öffnet — dieses Thema, seine Kategorie, sein Gebiet. Gemerktes ist
|
||||
im Feld hervorgehoben und wird durch erneutes Antippen wieder entfernt.
|
||||
Gemerkte Themen führen direkt zurück zum Thema, gemerkte Kategorien und
|
||||
Gebiete filtern die Themenliste; alles ist am Schlüssel gespeichert und steht
|
||||
auf jedem Gerät bereit.
|
||||
- **Alles auf einer Seite.** Es gibt keine getrennte Unterseite „Meine
|
||||
Übersicht“ mehr; `/me` und `/topics` führen auf dieselbe Hauptseite. Dort
|
||||
stehen übereinander: Merkzettel-Chips, die Gruppe „kürzlich abgestimmt (noch
|
||||
änderbar)“ mit der eigenen Stimme und der Frist, und die Themenliste. Eine
|
||||
anstehende Jury-Aufgabe wird über einen Hinweis in der Kopfzeile und eine
|
||||
Weiterleitung auf `/jury` erzwungen.
|
||||
- Der vollständige eigene Stand — Stimmen, eingebrachte Themen, Merkzettel,
|
||||
Meldungen, Jury-Zuteilungen — wird zusätzlich als **profil.yaml** ausgeliefert
|
||||
(Kapitel 5.3), verschlüsselt an den eigenen Ausweis-Schlüssel.
|
||||
|
||||
### 6.5 Sprache
|
||||
|
||||
Deutsch ist Standard; Englisch vollwertig verfügbar. Die Wahl wird in der Sitzung
|
||||
und — bei angemeldeten Nutzern — **am Pseudonym** gespeichert.
|
||||
|
||||
---
|
||||
|
||||
## 7. Meldung rechtswidriger Inhalte und Bürger-Jury
|
||||
|
||||
### 7.1 Grundsatz: Recht statt Richtung
|
||||
|
||||
Gemeldet werden können **mutmaßlich rechtswidrige Inhalte** — nicht politische
|
||||
Meinungen. Zur Einordnung, weil danach oft gefragt wird: Auch extreme politische
|
||||
Auffassungen sind in Deutschland **nicht als solche strafbar**; die
|
||||
Meinungsfreiheit (Art. 5 GG) schützt auch scharfe und radikale Positionen. Strafbar
|
||||
sind konkrete Delikte — und nur an diesen wird gemessen.
|
||||
|
||||
Eine Meldung besteht deshalb aus genau **einem Grund: dem Verstoß gegen ein
|
||||
Gesetz**. Es gibt **keinen Auffangtatbestand** und **keinen Freitext** — es
|
||||
wird ausschließlich am zitierten Gesetz bewertet. Beim Melden führt ein Suchfeld
|
||||
(Schlagwort oder Paragraphennummer) zum eingebauten Register; der gewählte
|
||||
Paragraph wird **wortgleich (1:1) zitiert** und der Jury unverändert vorgelegt.
|
||||
|
||||
Das Register umfasst im Prototyp **neun Tatbestände** des Strafgesetzbuchs:
|
||||
|
||||
| Norm | Tatbestand |
|
||||
|---|---|
|
||||
| § 130 Abs. 1 StGB | Volksverhetzung |
|
||||
| § 86a Abs. 1 StGB | Verwenden von Kennzeichen verfassungswidriger und terroristischer Organisationen |
|
||||
| § 111 Abs. 1 StGB | Öffentliche Aufforderung zu Straftaten |
|
||||
| § 185 StGB | Beleidigung |
|
||||
| § 186 StGB | Üble Nachrede |
|
||||
| § 187 StGB | Verleumdung |
|
||||
| § 240 Abs. 1 StGB | Nötigung |
|
||||
| § 241 Abs. 1 StGB | Bedrohung |
|
||||
| § 126a Abs. 1 StGB | Gefährdendes Verbreiten personenbezogener Daten |
|
||||
|
||||
Das Register ist erweiterbar; die hinterlegten Volltexte sind vor einem
|
||||
Echtbetrieb wortgleich gegen gesetze-im-internet.de abzugleichen.
|
||||
|
||||
### 7.2 Bürger-Jury statt Redaktionsmoderation
|
||||
|
||||
Über die Meldung entscheidet keine Redaktion, sondern eine **zufällig geloste Jury
|
||||
aus der Nutzerschaft** — das Losverfahren (wie beim Schöffenamt) macht gezielte
|
||||
Beeinflussung praktisch unmöglich.
|
||||
|
||||
**Auswahl:**
|
||||
|
||||
- **1 % aller bereits auf der Plattform verwendeten Ausweis-Pseudonyme** wird per
|
||||
kryptographisch sicherem Zufall (CSPRNG) gezogen. Die Mindestgröße
|
||||
(Standard: 5) ist ein **Zielwert, keine Untergrenze**: Sind weniger geeignete
|
||||
Personen verfügbar, besteht die Jury eben aus weniger — notfalls aus zweien.
|
||||
Ebenso kann das Quorum unter den Standardwert 3 fallen, weil es auf die
|
||||
tatsächliche Jurygröße gedeckelt wird. Bei kleiner Nutzerschaft entscheiden
|
||||
also sehr wenige; das ist eine bewusste Abwägung zugunsten der
|
||||
Funktionsfähigkeit und vor einem Echtbetrieb zu überdenken.
|
||||
- **Ausgeschlossen** sind: Pseudonyme, die bereits einer **laufenden** Meldung als
|
||||
Jury zugeteilt sind; die meldende Person; die Autorin/der Autor des gemeldeten
|
||||
Themas; sowie Pseudonyme in der **Karenzzeit** — wer eine abgeschlossene
|
||||
Jury-Runde hinter sich hat, ist erst **nach 3 Tagen** wieder losbar.
|
||||
|
||||
**Ablauf und Fristen (alle Zeiten Europe/Berlin):**
|
||||
|
||||
1. Meldung wird erstellt → Jury wird sofort gelost, die Abstimmung **startet zur
|
||||
nächsten Mitternacht (00:00)**.
|
||||
2. Ab Start läuft die reguläre Abstimmungsfrist von **24 Stunden**.
|
||||
3. Nach Ablauf der 24 Stunden wird entschieden, **sofern mindestens 0,5 %** (bezogen
|
||||
auf die Nutzerschaft, d. h. die Hälfte der Jury; Mindestquorum konfigurierbar)
|
||||
ihre Stimme abgegeben haben.
|
||||
4. Ist das Quorum nicht erreicht, **läuft die Meldung weiter**, bis es erreicht ist;
|
||||
dann wird unmittelbar entschieden.
|
||||
|
||||
**Stimmoptionen der Jury:** *bestätigen* (Inhalt verstößt), *ablehnen* (kein
|
||||
Verstoß), *Enthaltung* (zählt für das Quorum, nicht für die Mehrheit).
|
||||
**Entscheidung:** einfache Mehrheit bestätigen > ablehnen → Inhalt wird entfernt
|
||||
(Platzhalterseite „nach Gemeinschaftsprüfung entfernt“); sonst bleibt er stehen.
|
||||
Bei Gleichstand bleibt der Inhalt stehen (im Zweifel für die Meinungsfreiheit).
|
||||
|
||||
**Mitwirkungspflicht:** Wer ausgelost wurde und noch nicht abgestimmt hat, wird beim
|
||||
**nächsten Anhalten des Ausweises** (Sitzungsbeginn) zuerst zur Jury-Entscheidung
|
||||
geführt und kann die übrigen Funktionen erst danach nutzen — oder wartet, bis die
|
||||
Meldung abgeschlossen ist. Enthaltung ist ausdrücklich zulässig; niemand wird zu
|
||||
einem inhaltlichen Urteil gezwungen.
|
||||
|
||||
**Schutz vor Melde-Missbrauch:** je Pseudonym maximal 3 Meldungen pro Tag; je Thema
|
||||
höchstens **eine offene** Meldung (weitere Meldungen desselben Themas werden auf die
|
||||
laufende Prüfung verwiesen); dasselbe Pseudonym kann dasselbe Thema nur einmal
|
||||
melden. Alle Grenzwerte sind serverseitig durchgesetzt.
|
||||
|
||||
### 7.3 Grenzen des Verfahrens
|
||||
|
||||
Die Bürger-Jury ist eine **Plattform-Moderation**, kein Strafverfahren. Offenkundig
|
||||
strafbare Inhalte können unabhängig vom Juryergebnis zusätzlich den
|
||||
Strafverfolgungsbehörden gemeldet werden; gesetzliche Melde- und Löschpflichten
|
||||
(insb. **Digital Services Act**, ggf. NetzDG-Nachfolgeregeln) gelten neben dem
|
||||
Juryverfahren und erfordern im Echtbetrieb einen benannten Zustellungsbevollmächtigten
|
||||
und Meldewege für Behörden. Das ist im Betriebskonzept der Ausbaustufe zu verankern.
|
||||
|
||||
---
|
||||
|
||||
## 8. Sicherheitsarchitektur
|
||||
|
||||
Bürgerabstimmung wäre im Echtbetrieb ein **hochwertiges Angriffsziel** (politische
|
||||
Stimmungsbilder, staatsnahe Wahrnehmung). Der Prototyp ist deshalb von Grund auf
|
||||
konservativ gebaut: wenig Code, wenig Abhängigkeiten, restriktive Standardwerte.
|
||||
|
||||
### 8.1 Prinzipien
|
||||
|
||||
- **Datenminimierung als Verteidigung:** Was nicht gespeichert ist, kann nicht
|
||||
gestohlen werden. Keine Namen, keine E-Mail-Adressen, keine Passwörter, keine
|
||||
Klar-IP-Adressen in der Datenbank.
|
||||
- **Keine fremden Laufzeit-Abhängigkeiten:** Der Prototyp nutzt ausschließlich
|
||||
PHP-Bordmittel (kein Framework, kein Composer-Paket, kein CDN, keine externen
|
||||
Fonts/Skripte). Das eliminiert Lieferketten-Risiken und macht den gesamten Code
|
||||
in einem Durchgang auditierbar.
|
||||
- **Sichere Standardwerte:** Testbanner an, Mock-eID nur explizit, restriktivste
|
||||
HTTP-Header, alle Grenzwerte serverseitig.
|
||||
- **Tiefenstaffelung:** Kernregeln (1 Thema/Tag, eine Stimme pro Thema, eine offene
|
||||
Meldung pro Thema, ein Juror nur einmal je Meldung) sind zusätzlich zur
|
||||
Anwendungslogik als **Datenbank-Constraints** erzwungen.
|
||||
|
||||
### 8.2 Maßnahmen im Code (Prototyp)
|
||||
|
||||
| Bereich | Maßnahme |
|
||||
|---|---|
|
||||
| SQL | Ausschließlich PDO-**Prepared Statements**, kein String-SQL mit Nutzerdaten |
|
||||
| XSS | Konsequentes Output-Escaping (`htmlspecialchars`, ENT_QUOTES) in allen Templates; CSS und JavaScript werden als eigene Routen ausgeliefert. Ausnahmen ohne CSP-Bezug: das Icon-SVG trägt einen eigenen `<style>`-Block, die beiden Notfallseiten vor dem Start nutzen Inline-Styles |
|
||||
| CSP | `default-src 'none'` + explizite Freigaben nur für eigene Skripte/Styles/Bilder; `frame-ancestors 'none'`, `base-uri 'none'`, `form-action 'self'` |
|
||||
| Clickjacking | `X-Frame-Options: DENY` + CSP frame-ancestors |
|
||||
| Weitere Header | `X-Content-Type-Options: nosniff`, `Referrer-Policy: no-referrer`, restriktive `Permissions-Policy`, COOP/CORP; HSTS im HTTPS-Betrieb |
|
||||
| CSRF/Replay | **Einmal-Token** auf jedem POST-Formular: beim Einlösen verbraucht — jede Aktion ist genau einmal gültig |
|
||||
| Sessions | HttpOnly, SameSite, Secure (bei HTTPS), ID-Rotation bei An-/Abmeldung, Inaktivitäts- (30 min) und absolutes Timeout (8 h) — wichtig für öffentliche Terminals |
|
||||
| Identität | Der öffentliche Ausweis-Schlüssel selbst ist die Kennung — kein abgeleitetes Pseudonym. Das Server-Geheimnis (`data/secret.key`, 0600) wird beim ersten Start erzeugt und nur für die Stimmen-Marker und die Ratenbegrenzung verwendet |
|
||||
| Zufall | Jury-Losverfahren mit CSPRNG (`random_int`, Fisher-Yates), nicht mit SQL-`RANDOM()` |
|
||||
| Rate-Limits | Serverseitig je Pseudonym bzw. gehashter IP: Anmeldeversuche, Stimmen, Meldungen, Formular-POSTs |
|
||||
| Eingaben | Whitelist-Validierung (Enums, Längen, UTF-8-Prüfung, Kontrollzeichen-Filter); keine Datei-Uploads |
|
||||
| Fehlerbilder | Keine Stacktraces oder Pfade nach außen; generische Fehlerseiten; Sicherheitsereignisse werden ohne personenbezogene Daten protokolliert |
|
||||
| Struktur | Eine Datei im Webroot; Datenbank, Geheimnisse und Logs liegen in `data/` **innerhalb** des Webroots und sind über eine eigene `.htaccess` sowie eine 404-Regel in der Anwendung gesperrt. Ein Verzeichnis außerhalb des Webroots wäre stärker und ist für den Echtbetrieb zu empfehlen |
|
||||
| Betrieb | Selbsttest (`php index.php selftest`, 122 Prüfungen) deckt die Kernregeln automatisiert ab: Tagesgrenze, Abstimmungsende, Jury-Ausschlüsse, Quorum, Fristen, Karenz, Freigabeliste, Dauerhaftigkeit abgestimmter Themen, Archivierung, Ähnlichkeitssuche, Einrichtung des Echtbetriebs, Sprachtabellen |
|
||||
|
||||
### 8.3 Bedrohungsmodell (Auszug)
|
||||
|
||||
| Bedrohung | Antwort |
|
||||
|---|---|
|
||||
| Bot-/Sockenpuppen-Armeen | eID: eine physische Karte = ein Konto; ohne Karte keine Stimme |
|
||||
| Stimmenkauf/-zwang im großen Stil | Physische Karte + PIN nötig; skaliert schlecht; rechtlich sanktioniert |
|
||||
| Manipulation der Jury-Auswahl | CSPRNG-Losung serverseitig; Ausschlusslisten; keine Selbstmeldung zur Jury möglich |
|
||||
| Melde-Spam zur Zensur | Tageslimit, eine offene Meldung je Thema, Quorum + Mehrheit nötig, Gleichstand erhält Inhalt |
|
||||
| SQL-Injection / XSS / CSRF | Siehe 8.2 — durchgängig parametrisiert, escaped, tokenisiert |
|
||||
| Session-Diebstahl am Terminal | Kurze Timeouts, Abmelde-Knopf, HttpOnly-Cookies. Im Browser liegt außer dem Sitzungs-Cookie nur die `profil.yaml` im `sessionStorage`; „Abmelden“ löscht sie |
|
||||
| Datenbank-Diebstahl | Enthält öffentliche Ausweis-Schlüssel, Themen und Stimmen — keine Klaridentitäten. Die Stimmen sind ohne das Server-Geheimnis nicht zuordenbar; wer Datenbank **und** `secret.key` erbeutet, kann die Zuordnung berechnen |
|
||||
| Lieferkette (Pakete/CDN) | Keine externen Abhängigkeiten im Prototyp |
|
||||
| DDoS / Lastspitzen | Ausbaustufe: CDN/Anycast vor statischen Assets, horizontale Skalierung, siehe 10.3 |
|
||||
|
||||
### 8.4 Echtbetrieb zusätzlich (Pflichtprogramm)
|
||||
|
||||
TLS ausschließlich (HSTS + Preload), getrennte Umgebungen, Härtung nach
|
||||
BSI-IT-Grundschutz, externe Penetrationstests **vor** Start, laufendes
|
||||
Schwachstellen-Management + Bug-Bounty, signierte Deployments, Backups mit
|
||||
Wiederanlaufübungen, 24/7-Monitoring, DDoS-Schutz, und ein unabhängiges
|
||||
Sicherheits-Audit des Jury-Losverfahrens (nachvollziehbare, aber nicht
|
||||
vorhersagbare Ziehung — z. B. via veröffentlichtem Ziehungs-Commitment).
|
||||
|
||||
---
|
||||
|
||||
## 9. Datenschutz (DSGVO)
|
||||
|
||||
- **Datenminimierung:** gespeichert werden nur: der öffentliche Ausweis-Schlüssel
|
||||
als Kennung, Zeitstempel, eigene Themen, Merkzettel, Meldungen und
|
||||
Jury-Zuteilungen. Stimmen liegen **ohne Bezug zum Ausweis** (HMAC-Marker).
|
||||
Die gewählte **Sprache wird nicht gespeichert** — sie gilt nur für die
|
||||
laufende Sitzung; die Spalte in der Kontozeile trägt lediglich den Standardwert
|
||||
aus der Anlage. Keine Klaridentität, keine IP-Adressen im Klartext (nur
|
||||
kurzlebige Hashes für Rate-Limits), keine Tracker, keine Cookies außer dem
|
||||
Sitzungs-Cookie.
|
||||
- **Rechtsgrundlage** (Echtbetrieb): Art. 6 Abs. 1 lit. a/e DSGVO je nach
|
||||
Trägerschaft; eID-Nutzung nach eIDAS/PAuswG mit Berechtigungszertifikat.
|
||||
- **Betroffenenrechte — Stand im Prototyp, ehrlich:** Die *Auskunft* ist
|
||||
umgesetzt: die **profil.yaml** enthält den vollständigen eigenen Stand, an den
|
||||
eigenen Ausweis-Schlüssel verschlüsselt. Sie wird allerdings **nur per
|
||||
JavaScript** abgerufen — ohne JavaScript gibt es keine Selbstauskunft.
|
||||
Die *Löschung* ist als Routine vorhanden und automatisiert geprüft
|
||||
(`account_delete` löscht die Kontozeile, wodurch Merkzettel, Meldungen und
|
||||
Jury-Sitze per Fremdschlüssel mit entfernt werden, und hängt eingebrachte
|
||||
Themen an ein System-Konto um; **abgegebene Stimmen bleiben erhalten**, weil
|
||||
sie keinen Bezug zum Ausweis tragen und nach dem Löschen niemandem mehr
|
||||
zuzuordnen sind). Sie hat in dieser Fassung **keine Schaltfläche** in der
|
||||
Oberfläche — der Löschbereich wurde entfernt. **Vor einem Echtbetrieb ist
|
||||
dafür zwingend ein Weg in der Oberfläche zu ergänzen**, sonst ist Art. 17
|
||||
DSGVO nicht erfüllt.
|
||||
- **Speicherbegrenzung:** Rate-Limit-Einträge verfallen automatisch;
|
||||
Sicherheitslogs ohne Personenbezug.
|
||||
- Für den Echtbetrieb: Datenschutz-Folgenabschätzung (Art. 35 DSGVO) zwingend,
|
||||
benannte(r) DSB, Verzeichnis von Verarbeitungstätigkeiten.
|
||||
|
||||
---
|
||||
|
||||
## 10. Technik
|
||||
|
||||
### 10.1 Prototyp-Stack
|
||||
|
||||
- **PHP ≥ 8.0** (strict types, harte Versionssperre beim Start), keine externen Pakete.
|
||||
- **SQLite** (WAL-Modus) als Prototyp-Datenbank — eine Datei, einfach zu prüfen;
|
||||
die Datenzugriffsschicht ist so geschrieben, dass PostgreSQL in der Ausbaustufe
|
||||
ein Austausch der Verbindung ist.
|
||||
- **Server-gerendertes HTML**, genau eine CSS- und eine JS-Datei, dazu das
|
||||
Icon — alles aus derselben Datei ausgeliefert. Hell/Dunkel ist reines CSS,
|
||||
dafür gibt es kein Skript.
|
||||
- Betrieb hinter Apache/nginx mit gesperrtem `data/` oder für Demos mit
|
||||
dem eingebauten PHP-Server.
|
||||
|
||||
### 10.2 Hintergrundläufe
|
||||
|
||||
Zustandswechsel (Meldung „wartet“ → „läuft“ um 00:00, Entscheidung nach 24 h +
|
||||
Quorum, Karenzzeiten) verarbeitet ein idempotenter **Maintenance-Tick**: er läuft
|
||||
per Cron (`php index.php cron`) **und** zusätzlich beiläufig bei Seitenaufrufen (auf 30 Sekunden gedrosselt),
|
||||
sodass der Prototyp auch ohne Cron korrekt bleibt.
|
||||
|
||||
### 10.3 Skalierungspfad
|
||||
|
||||
PostgreSQL + Read-Replicas → zustandslose PHP-Knoten hinter Load-Balancer →
|
||||
CDN für Assets → Warteschlange für Jury-Benachrichtigungen → mandantenfähige
|
||||
Gebietsdaten (amtliche Gemeindeschlüssel AGS/ARS statt Freitext-Gebieten).
|
||||
|
||||
---
|
||||
|
||||
## 11. Parameter (konfigurierbar)
|
||||
|
||||
| Parameter | Standard | Bedeutung |
|
||||
|---|---|---|
|
||||
| `show_test_banner` | **true** | Testbetrieb-Banner auf jeder Seite |
|
||||
| `eid_mode` | `demo` | `demo` (ausgegebene Test-Ausweise) oder `eid` (nur Ausweis-Apps) |
|
||||
| `eid_client_url` | `http://127.0.0.1:24727/eID-Client` | Aktivierungsadresse des eID-Clients (TR-03124) |
|
||||
| `eid_server_url` | leer | SOAP-Endpunkt des eigenen eID-Servers (TR-03130); leer = fail-closed |
|
||||
| `data/config.yaml` | fehlt | von der Einrichtungsseite geschriebene Überlagerung der Vorgaben |
|
||||
| `default_lang` | `de` | Standardsprache |
|
||||
| `jury_share` | 1 % | Anteil der Nutzerschaft je Jury |
|
||||
| `jury_min` | 5 | Mindest-Jurygröße |
|
||||
| `quorum_share` | 0,5 % | Quorum als Anteil der Nutzerschaft |
|
||||
| `quorum_min` | 3 | Mindest-Quorum |
|
||||
| `report_vote_hours` | 24 | Reguläre Jury-Abstimmungsdauer |
|
||||
| `jury_cooldown_days` | 3 | Karenz nach abgeschlossener Jury-Runde |
|
||||
| `reports_per_day` | 3 | Meldungen je Pseudonym und Tag |
|
||||
| `timezone` | Europe/Berlin | Bezugszeitzone aller Tagesgrenzen |
|
||||
|
||||
---
|
||||
|
||||
## 12. Roadmap
|
||||
|
||||
1. **Prototyp (dieses Repository):** vollständige Fachlogik mit Mock-eID,
|
||||
Zwei-Sprachen-UI, Jury-Verfahren, Selbsttests.
|
||||
2. **Pilot:** Anbindung echter eID-Server (Berechtigungszertifikat, AusweisApp-Flow),
|
||||
externes Sicherheits-Audit + Pentest, DSFA, Barrierefreiheit nach BITV,
|
||||
PostgreSQL.
|
||||
3. **Kommunal-Pilotgemeinden:** Terminals in Bürgerbüros, amtliche Gebietsschlüssel,
|
||||
Auswertungs-Exporte für Räte und Verwaltungen.
|
||||
4. **Ausbau:** Delegations-/Sachverständigen-Funktionen, strukturierte
|
||||
Ergebnisberichte an Parlamente, offene Schnittstellen (Open Data) mit
|
||||
Differential-Privacy-Schutz kleiner Gebiete.
|
||||
|
||||
---
|
||||
|
||||
## 13. Offene Punkte
|
||||
|
||||
- Marken-/Domainrecherche „Bürgerabstimmung“ und finale Namensentscheidung.
|
||||
- Trägerschaft und Finanzierung (Verein/Stiftung empfohlen: neutralitätssichernd).
|
||||
- Rechtsgutachten: eID-Berechtigungsumfang, DSA-Pflichtenkatalog, Jugendliche
|
||||
(Ausweispflicht ab 16 — Teilnahmealter ist Konfigurationsfrage).
|
||||
- Verifizierbare Jury-Ziehung (öffentliches Commitment-Verfahren) — Konzept in 8.4
|
||||
skizziert, Umsetzung in der Pilotphase.
|
||||
|
||||
---
|
||||
|
||||
## Anhang: Installation und Betrieb
|
||||
|
||||
Der technische Prototyp ist **eine einzige Datei**. Es genügt ein Webserver
|
||||
mit PHP — kein Framework, kein Paketmanager, keine externen Dienste.
|
||||
|
||||
1. `index.php` in das Webverzeichnis legen (Hauptverzeichnis oder Unterordner;
|
||||
der Basispfad wird erkannt).
|
||||
2. PHP **8.0 oder neuer** mit `pdo_sqlite`, `mbstring` und `sodium` — alle drei
|
||||
gehören zur Standardausstattung.
|
||||
3. Seite aufrufen. Beim ersten Aufruf legt die Datei selbst an: `data/`
|
||||
(SQLite-Datenbank, Server-Geheimnis, Protokolle, Zugriffssperre),
|
||||
`.htaccess` (saubere Adressen und Schutz interner Dateien) und `robots.txt`.
|
||||
|
||||
Meldet die Seite „Fast geschafft“, fehlen dem Verzeichnis Schreibrechte
|
||||
(755/775 setzen, neu laden). Ohne `.htaccess`-Unterstützung — etwa unter nginx —
|
||||
arbeitet die Anwendung über automatisch erzeugte `/index.php/…`-Adressen
|
||||
weiter; eine gleichwertige `try_files`-Regel stellt die sauberen Adressen her.
|
||||
Dort ist zusätzlich `/data/` zu sperren — die Anwendung selbst beantwortet
|
||||
jede Anfrage auf diesen Pfad mit 404, ausgeliefert würde sie sonst am
|
||||
PHP-Prozess vorbei.
|
||||
|
||||
Der Auslieferungszustand ist der **Testmodus** (Kapitel 5.3b): ein Knopf meldet
|
||||
ohne Ausweis an, damit sich die Plattform vorführen lässt. Über den Chip
|
||||
„Testmodus“ führt die Seite **„Echtbetrieb einrichten“** (Kapitel 5.3c) durch
|
||||
Prüfung, Zugangswahl und Umschaltung; sie schreibt die Einstellungen nach
|
||||
`data/config.yaml`, löscht alle Testdaten und aktiviert dauerhaft die strenge
|
||||
Ausweisprüfung. Der dafür nötige Einrichtungsschlüssel steht in
|
||||
`data/setup.token`.
|
||||
|
||||
Wartung und Prüfung laufen über dieselbe Datei auf der Kommandozeile:
|
||||
|
||||
| Aufruf | Zweck |
|
||||
|---|---|
|
||||
| `php index.php selftest` | 122 automatisierte Prüfungen der Fachregeln |
|
||||
| `php index.php cron` | Wartungslauf (sonst beiläufig bei Seitenaufrufen) |
|
||||
| `php index.php seed 400` | Demo-Stimmen, anonym wie im Echtbetrieb |
|
||||
| `php index.php jurysim` | Demo-Jury stimmt in laufenden Prüfungen ab |
|
||||
| `php index.php issue-card 3` | autorisierte Demo-Ausweise samt Abhol-Verweis |
|
||||
| `php index.php sync-keys` | Freigabeliste aus der konfigurierten Trust-Liste |
|
||||
| `php index.php setup-token` | Einrichtungsschlüssel für die Umschaltung anzeigen |
|
||||
| `php index.php config` | wirksame Einstellungen aus `data/config.yaml` anzeigen |
|
||||
| `php -S 127.0.0.1:8080 index.php` | lokale Vorführung ohne Webserver |
|
||||
Reference in New Issue
Block a user