C3MAWiki:Zugriffsschutz

Aus C3MAWiki
Version vom 22. Januar 2013, 17:25 Uhr von Frubi (Diskussion | Beiträge) (→‎c3mapublic.sh: Prüft, ob das Skript bereits läuft)
(Unterschied) ← Nächstältere Version | Aktuelle Version (Unterschied) | Nächstjüngere Version → (Unterschied)
Dieses Projekt ist erfolgreich abgeschlossen und wird hier dokumentiert. Falls du weitere Fragen dazu hast, wende dich an Scytale.


MediaWiki (die Software, auf der diese Website basiert), wurde ursprünglich für die Wikipedia entwickelt und hat folglich kein besonders ausgeklügeltes System, um einzelne Seiten vor der Betrachtung von Unbefugten zu schützen. Scytale hat trotzdem eins erfunden. Es wird auf dieser Seite erst für Chaostreff-Mitglieder erklärt (wie mache ich Seiten öffentlich oder vertraulich?), weiter unten dann die technische Realisation (falls jemand anderes ebenfalls ein solches System haben will).

Wie benutze ich den Zugriffsschutz?

Grundprinzip

Wenn du eine Seite der Öffentlichkeit zugänglich machen willst, füge ans Ende folgende Zeile ein:

[[Kategorie:öffentlich]]

Alle Seiten sind, sofern nichts anderes angegeben ist, vertraulich. Sie müssen also explizit veröffentlicht werden. Allerdings machen gewisse Vorlagen die Seite automatisch öffentlich. Dazu gehören Vorlage:Event und die darauf basierenden Vorlage:Treffen und Vorlage:Seminar. Aus diesen Seiten lässt sich die Kategorie "öffentlich" auch nicht entfernen.

Trotzdem kannst du die Seite vertraulich machen. Füge dazu einfach ans Ende folgende Zeile ein:

[[Kategorie:vertraulich]]

Die Kategorie "vertraulich" hat immer Vorrang gegenüber der Kategorie "öffentlich". Sollten einer Seite also beide Kategorien zugewiesen sein, ist die Seite vertraulich.

Welche Seiten sollten öffentlich, welche vertraulich sein?

Zuallererst: Jede Seite, auf die eins oder mehrere der Kriterien unter Vertraulichkeit zutrifft, sollte unbedingt eine "vertraulich"-Markierung erhalten. Wenn du dir nicht sicher bist, ob eine Seite vertraulich sein sollte, markiere sie als vertraulich und frage dann nach. Die "vertraulich"-Einstufung lässt sich jederzeit wieder entfernen. Keinesfalls solltest du die Seite erst mal öffentlich lassen, wenn du dir unsicher bist.

Ansonsten ist es nicht falsch, einer Seite überhaupt keine Markierung zu geben. Sie ist dann automatisch vertraulich. Wir sind zwar eine dem CCC nahe stehende Gruppierung und als solche für Informationsfreiheit, aber es sind bereits große Teile des Wikis für die Öffentlichkeit lesbar (z.B. fast alle Events und Termine). Nur dann, wenn eine Seite wirklich Informationen beinhaltet, die für die Öffentlichkeit nützlich sein könnten (und sie nicht aus irgendeinem Grund vertraulich sein muss), solltest du sie als öffentlich markieren.

Status prüfen

Ob eine Seite öffentlich sein wird oder nicht kannst du auch schon vor dem Speichern prüfen. Klicke dafür auf den "Vorschau"-Button. Die Vorschau wird generiert. Und wenn du jezt ganz nach unten scrollst, siehst du auch die auf dieser Seite aktiven Kategorien.

  • Steht dort vertraulich, dann wird sie vertraulich sein (selbst dann, wenn auch öffentlich dasteht).
  • Steht dort nur öffentlich (und nicht auch vertraulich), dann (und nur dann) wird sie öffentlich sein.

Fragen und Antworten

Falls du eine Frage hast, die hier nicht beantwortet ist, füge sie einfach hinzu. Sofern du keine Schreibrechte für das Wiki hast, wende dich an Yorn.

Ich habe eine Seite als "öffentlich" markiert, trotzdem ist sie nicht lesbar, wenn ich mich auslogge.
Es kann bis zu einer Minute dauern, bis als "öffentlich" markierte Seiten wirklich für die Öffentlichkeit zugänglich sind. Falls es länger dauert, kontaktiere bitte Frubi.

Technische Realisation

Das Problem

MediaWiki besitzt keine Möglichkeit, einzelne Seiten vor Zugriff durch bestimmte Benutzer (nicht angemeldet oder nicht in einer bestimmten Benutzergruppe) zu schützen. Es gibt zwar diverse Extensions, die so etwas realisieren wollen (z.B. durch Einfügen eines bestimmten magischen Wortes in den Quelltext der Seite, durch einen zusätzlichen "versteckten" Namespace etc.), aber die meisten werden nicht mehr weiterentwickelt, bieten nicht die Features, die wir brauchen, oder sind aus anderen Gründen unbrauchbar. Eine solche Extension zu schreiben ist alles andere als trivial, da Seiten ja nicht nur direkt aufgerufen werden können, sondern auch bei den letzten Änderungen auftauchen, mittels Vorlagen eingebunden werden können ({{:geheime Seite}}) etc.

Grundgedanken

Es gibt diverse Grundsätze, die für die Sicherheit eines solchen Zugriffsschutzes unerlässlich sind:

  1. Mittels Vorlagentransklusion kann man so ziemlich alle Sicherheitsmaßnahmen außer Kraft setzen. Also muss man entweder enormen Aufwand betreiben, um die Transklusion zu sichern, oder aber man sorgt dafür, dass Unbefugte gar nicht transkludieren können.
    • Lösung: Unbefugte dürfen nicht schreiben.
  2. Menschen sind vergesslich. Es ist nicht unwahrscheinlich, dass öfter mal vergessen wird, eine Seite vor unbefugtem Zugriff zu schützen, wenn man dies bei jeder Seite manuell machen muss.
    • Lösung: Alle Seiten sind standardmäßig vertraulich.
  3. Die Information, ob eine Seite vertraulich ist oder nicht, sollte direkt bei der Seite gespeichert werden (z.B. nicht in einer extra Liste "öffentliche Seiten") und auch zusammen mit der Seite editierbar sein.
    • Lösung: Wir verwenden Kategorien, um die Seiten zu "taggen".
  4. Es sollte möglich sein, Seiten, die gewisse Kriterien erfüllen, automatisch als öffentlich zu markieren.
    • Lösung: Die Kategorie "öffentlich" kann ohne Probleme auch in Vorlagen gesetzt werden (mit <includeonly> sogar ohne die Vorlage öffentlich zu machen). Diesen Ansatz benutzen wir z.B. in der gemeinsamen Vorlage:Event, die in allen Eventseiten benutzt wird.
  5. Für diese automatisch markierten Seiten sollten Ausnahmen definierbar sein.
    • Lösung: Eine zweite Kategorie namens "vertraulich", die immer Vorrang hat, selbst wenn die Seite auch als "öffentlich" markiert ist.
  6. Herumpatchen an MediaWiki ist unübersichtlich, kompliziert und risikobehaftet.
    • Lösung: Es wird ein Standalone-Bash-Script benutzt. An MediaWiki müssen keine Änderungen durchgeführt werden, es muss nur eine zusätzliche Konfigurationsdatei in der LocalSettings.php inkludiert werden.
  7. Als "öffentlich" markierte Seiten sollte sofort öffentlich verfügbar sein.
    • Ist momentan noch nicht gelöst. Stattdessen wird in regelmäßigen Abständen (eine Minute) die Liste der öffentlichen Seiten aktualisiert.

Funktionsweise

Auf dem Server, auf dem sich die MediaWiki-Installation befindet (Planungen zur möglichen Auslagerung werden gerade angestellt), läuft per Cronjob minütlich ein kleines Bash-Script, das die Wiki-Datenbank nach Seiten mit der Kategorie "öffentlich" und ohne die Kategorie "vertraulich" befragt. Aus der Liste dieser Seiten wird ein PHP-Script generiert, das die MediaWiki-Variable $wgWhitelistRead definiert. Alle in diesem Array aufgeführten Seitennamen sind von jedermann lesbar. Die generierte PHP-Datei wird in MediaWikis LocalSettings.php inkludiert.

Quellcode

c3mapublic.sh

(Dieses Script enthält das Datenbankpasswort und sollte von daher nur vom Besitzer, in unserem Fall root, lesbar sein.) #!/bin/sh

  1. Das Verzeichnis für die temporäre und die generierte Datei:

d=/var/www/mediawiki

  1. Name der temporären Datei

t=$d/Whitelist.tmp.php

  1. Name der generierten Datei

f=$d/Whitelist.php

  1. Prüft, ob das Skript bereits läuft. In diesem Fall wird das Skript
  2. direkt beendet.

if [ $(pgrep -c $(basename $0)) -gt 1 ]; then exit 0 fi

  1. Sollte das Skript in den nächsten Schritten fehlerhaft beendet werden,
  2. löscht die Trap bei Bedarf die angelegte temporäre Datei.

trap "rm -f $t" INT TERM EXIT

  1. Beginne PHP-Code in die temporäre Datei zu schreiben.
  2. Wir schreiben nicht in nach $f, weil sonst evtl. ein Zugriff
  3. auf das Wiki stattfinden könnte, während die Datei noch nicht
  4. fertig geschrieben ist. PHP würde einen Fehler melden.

echo '<?php $wgWhitelistRead = array ('>$t

  1. Schütze diese Datei vor fremdem Zugriff.

chown root:root $t chmod 0600 $t

  1. Passwort in Umgebungsvariable.

export MYSQL_PWD='dbpassword'

  1. Schleife über die Ergebnisse

for p in $(echo "SELECT a.cl_sortkey

                FROM categorylinks a
                WHERE a.cl_to LIKE '_ffentlich'
                      AND NOT EXISTS (SELECT b.cl_from
                                      FROM categorylinks b
                                      WHERE b.cl_from=a.cl_from
                                            AND b.cl_to LIKE '_ertraulich')\\G" |
          mysql -u dbuser dbname |
          grep -v '^*' |
          cut -d ' ' -f 2- |
          tr ' ' '_'); do
       # Jedes Ergebnis in single quotes und mit abschließendem Komma hinzufügen.
       echo "'$(echo "$p" | tr '_' ' ' | sed "s/'/\\\\'/g")',">>$t

done

  1. Noch ein paar andere Seiten verfügbar machen.

echo '"Hauptseite", "Special:Userlogin", "Spezial:Userlogin", "-", "MediaWiki:Monobook.css", "MediaWiki:Common.css" ); ?>'>>$t

  1. Wieder für alle lesbar.

chmod 0644 $t

  1. Und in einem Schlag die temporäre Datei über die bestehende schreiben.

mv $t $f

  1. Skript auf jeden Fall sauber beenden

trap - EXIT exit 0 Ein paar zusätzliche Erklärungen:

  • Das SQL-Query benutzt nicht die vollen Namen "öffentlich" und "vertraulich", da ich mir nicht sicher bin, ob es nicht Probleme mit Groß- und Kleinschreibung oder Umlauten geben könnte. Das bedeutet natürlich, dass eine eventuell existierende Kategorie "affentlich" ebenfalls Seiten lesbar machen würde.
  • Das SQL-Query benötigt ein MySQL mit Unterstützung für Subquerys (4.0 oder 4.1 oder so, vergessen).
  • Ohne Subquery würde das Query nur alle Seiten finden, die als "öffentlich" markiert sind, ohne Überprüfung, ob diese vielleicht ein vorrangiges "vertraulich" besitzen.
  • Es wird nicht der tatsächliche Name der Seite ausgelesen, sondern der "Sortkey" (z.B. in [[Kategorie:öffentlich|Sortkey]], vgl. MediaWiki-Dokumentation). Dieser entspricht standardmäßig dem Seitennamen. Würde man es "sauber" machen wollen, müsste man die PageID abfragen und mit den Seiten joinen und dann noch den Namespace dazujoinen... alles zu kompliziert. Stattdessen gilt die Regel, dass bei den Kategorien "öffentlich" und "vertraulich" die User keine Sortkeys benutzen dürfen. Wozu auch.
  • Das \\G am Ende des Querys sorgt dafür, dass die Ergebnisse leichter parsbar, nämlich vertikal (eine Tabellenspalte pro Textzeile), ausgegeben werden.
  • Das MySQL-Passwort wird in MYSQL_PWD eingetragen, damit es beim Aufruf von "ps" u.Ä. nicht sichtbar ist. Dies ist ein Feature des MySQL-CLI-Clients.
  • grep entfernt die Titelzeilen der Form ***** 1. row *****.
  • cut entfernt den Spaltennamen am Zeilenanfang.
  • tr ersetzt erst alle Leerzeichen im Seitennamen durch Unterstriche, damit die for-Schleife darüber laufen kann. Später werden die Unterstriche wieder in Leerzeichen verwandelt.
  • sed sorgt dafür, dass alle single quotes im Seitennamen korrekt escaped werden. Sonst könnte ein Schelm auf die Idee kommen, eine Seite weit gefährlicher als z.B. ');echo("Kimble rult!");$wgWhitelistRead=array_merge($wgWhitelistRead,array('blub zu nennen.

LocalSettings.php (Ausschnitt)

$wgGroupPermissions['*']['createaccount'] = false; $wgGroupPermissions['*']['edit'] = false; $wgGroupPermissions['*']['read'] = false; require('/var/www/chaostreff-mannheim.de/htdocs/Whitelist.php');

Whitelist.php (Beispiel)

So sieht das generierte Script z.B. aus: <?php $wgWhitelistRead = array ( 'C3MAWiki:Zugriffsschutz', 'Hacktraining 06a', 'Metarheinmain chaosdays 101b', 'Termine', 'Treffen 1. September 2006', 'Umstellung auf MediaWiki', 'Vorlage:Seminar', 'Vorlage:Treffen', "Hauptseite", "Special:Userlogin", "Spezial:Userlogin", "-", "MediaWiki:Monobook.css", "MediaWiki:Common.css" ); ?>