Archiv | Update

24. Dezember 2010 ~ 0 Kommentare | ÄHNLICHE ARTIKEL

[Update] WeizenSpr.eu ist Spam-Opfer

Was ist das denn für ein bescheuertes Weihnachtsgeschenk? Wie ich gerade mitbekommen habe, ist WeizenSpr.eu derzeit Opfer eines umfangreichen Spamangriffes. Wie ich anhand von mehreren Delivery-Messages erfahren habe, schickt irgendjemand Spam-E-Mails und setzt als Return-Path-Adresse zufällig ausgewählte WeizenSpr.eu-Mailadressen. Dadurch erhalte ich im Moment einen Haufen Backscatter-Mails.

Ich als Domain-Inhaber kann gegen diese Spam-Mails leider garnichts machen! Diese Mails stammen nicht von mir! Schuld daran ist, dass sich die Header von E-Mails viel zu leicht fälschen lassen!

Wie ich durch eine Delivery-Message gesehen habe, sind übrigens auch Weltbild.de und andere größere Webseiten von dem aktuell stattfindenden Angriff betroffen. Ich wünsche euch trotzdem ein besinnliches Weihnachtsfest und hoffe, dass dieser Angriff sehr bald wieder abklingen wird.

Update:
Da sehr viele Backscattering-Mails von Microsoft-Domains gekommen sind, habe ich den Leuten dort mal eine persönliche E-Mail geschickt, in der ich sie darum gebeten habe, ihr Backscattering-Problem zu lösen. Mal sehen, ob und wie Microsoft reagiert:

Dear people at Microsoft,

as I have learned your mail servers for @hotmail.com, @live.com and the
like are malconfigured. They accept e-mails for accounts that do not
exist and later on send Non-Delivery-Reports (NDRs) to the alleged
senders of the e-mails. This is bad behaviour and a main cause of
so-called backscattering: http://www.backscatterer.org/?target=bounces

I would therefore ask you - as one of the major e-mail service providers
in the world - to look into this problem and fix the configuration of
your mail servers as soon as possible.

With kind regards and all good wishes for Christmas and the new year,
Kevin Niehage, B.Sc. (Hons)

Update:
Um in Zukunft den besser konfigurierten Mailservern helfen zu können, habe ich nun für alle Domains, die bereits bei Hetzner gehostet werden, SPF-Records definiert. Anhand derer können empfangende Server erkennen, ob E-Mails über die korrekten SMTP-Server versendet werden. GMX nutzt diese Technik übrigens schon seit über 6 Jahren! :-)

Genervte Weihnachtsgrüße, Kenny

P.S.: Auch meine Blogkommentarfunktion wird derzeit mal wieder massiv angegriffen (in den letzten paar Stunden sind über 200 Spamkommentare eingetroffen). Diese werden jedoch alle erfolgreich durch Sergej Müllers Plugin Antispam-Bee aufgehalten. Vielen Dank deshalb nochmal an ihn für sein tolles Plugin!

P.P.S.: Ich habe nun erstmal meine CatchAll-Adresse deaktiviert. Damit sollten die Mailserver, die Spam empfangen nicht mehr in der Lage sein, mir Backscatter-Mails zu schicken. Evtl. hilft das diesen Servern ja, die Spam-Angriffe ein bisschen einzudämmen.


09. Dezember 2010 ~ 1 Kommentar | ÄHNLICHE ARTIKEL

[Update] Twitter-Tweets zu Identi.ca übertragen…

Zur Zeit wird ja viel über Wikileaks geredet und irgendwie macht sich derzeit so ziemlich jedes Unternehmen unbeliebt, weil es irgendein Konto von Wikileaks oder einem seiner Verbündeten sperrt. Es gibt sogar eine Hackerfront, die die Webseite jedes Widersachers mit DDOS-Attacken zuschüttet... einige sprechen schon von einem Cyberwar.

Auch Twitter ist in Ungnade gefallen, sodass nun einige Leute darüber nachdenken, zum Opensource-Konkurrenten Identi.ca zu wechseln. Ich persönlich - und einige andere auch - möchten diesen Schritt noch nicht gehen, sich jedoch trotzdem langsam von Twitter als Plattform lösen. Eine einfache Möglichkeit, dies zu tun, ist, erstmal einfach alle Tweets auch auf Identi.ca zu veröffentlichen. Hierfür gibt es mehrere Möglichkeiten:

  • Zum einen kann man Identi.ca als primäre Plattform nutzen, sie mit Twitter verknüpfen und die integrierte Synchronisation von Identi.ca verwenden. Dadurch werden alle "Dents" (die Nachrichten bei Identi.ca) auch bei Twitter veröffentlicht. Leider ist das Angebot an Twitter-Clients viel besser als das Angebot an Identi.ca-Clients.
  • Eine zweite Möglichkeit ist, einen Client zu verwenden, der sowohl Twitter als auch Identi.ca beherrscht. Mit diesem kann man dann beide Plattformen gleichzeitig nutzen und ist nicht darauf beschränkt, dass die Nachrichten der einen Plattform eine exakte Kopie der anderen Plattform sind. Für mich persönlich gibt es hierfür jedoch keine guten Clients.
  • Die dritte Möglichkeit ist, einen externen Dienst zu nutzen, der die Tweets von Twitter automatisch bei Identi.ca veröffentlicht. Dadurch kann man seinen gewohnten Twitter-Client weiternutzen und muss sich keinen suchen, der auch Identi.ca unterstützt.

Da mir - wie gesagt - die Clients mit Identi.ca-Unterstützung nicht wirklich gefallen haben, habe ich geguckt, welche Möglichkeit es gibt, meine Tweets mit Identi.ca zu synchronisieren. Dabei bin ich auf das Angebot von Twitterfeed.com gestoßen, das ich bis heute auch genutzt habe. Leider hat das Tool einen großen Haken: pro 30 Minuten werden maximal 5 Tweets synchronisiert. Dadurch gehen massenweise Tweets einfach verloren. :-(

Glücklicherweise ist mir heute durch @rka (dem Landesvorstandsvorsitzenden der Piratenpartei Berlin) ein Stück PHP-Code in die Finger gefallen, der die Synchronisation zwischen Twitter und Identi.ca übernehmen konnte. Leider entsprach der Code überhaupt nicht meinen Ansprüchen. Wie es aussieht, wurde er ursprünglich von @cdevroe geschrieben und hieß damals noch rss2twitter. Nix mit Identi.ca und so. Diese Anpassungen wurden anscheinend durch @einfachben und @hermes42 geleistet. Wenn man sich den Original-Quelltext ansieht, kann man sich vorstellen, wie das Stück Code aussah, das heute bei mir gelandet war.

Da ich die Idee, das Synchronisieren selber vornehmen zu können, trotzdem so großartig fand, habe ich mich dran gesetzt und den Code einmal komplett neu geschrieben - lediglich die Ideen aus dem ursprünglichen Code blieben erhalten. Da der ursprüngliche Code unter der GPL-Lizenz steht (und ich nicht sagen kann, wieviele Prozent des Originalcodes in meiner Version noch enthalten sind), steht meine Variante ebenfalls unter der GPL:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
<?php
  // TCtoICsync 0.1b - Post Twitter.com tweets as Identi.ca dents
  // Copyright (C) 2010 Kevin Niehage (@weizenspreu)
  //
  // This program is free software: you can redistribute it and/or modify
  // it under the terms of the GNU General Public License as published by
  // the Free Software Foundation, either version 3 of the License, or
  // (at your option) any later version.
  //
  // This program is distributed in the hope that it will be useful,
  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  // GNU General Public License for more details.
  //
  // You should have received a copy of the GNU General Public License
  // along with this program. If not, see <http://www.gnu.org/licenses/>.
  //
  // This tool is based on the work of @cdevroe, @einfachben and @hermes42.
  //
  // HowTo:
  // ======
  //
  // In order to use this Twitter.Com to Identi.Ca synchronization
  // tool you have to specify the following values:
  //
  // * $EXECUTE_PASSWORD:  Will protect you from malicious callers.
  //                       Only the people knowing this password
  //                       can call the synchronization process.
  //                       This password has to be provided as the
  //                       GET parameter "pwd" when calling this script.
  // * $IDENTICA_NICK:     This is your identi.ca nickname. It is
  //                       needed for using the identi.ca API.
  // * $IDENTICA_PASSWORD: This is your identi.ca password. It is
  //                       needed for using the identi.ca API.
  // * $TWITTER_NICK:      This is your twitter nickname. It is
  //                       needed for formating the messages that
  //                       are read from the twitter RSS feed.
  // * $AUTO_REFRESH:      This feature enables a small JavaScript
  //                       auto-refresh feature. This value defines
  //                       the number of seconds the page waits before
  //                       it refreshes itself. A value of zero or less
  //                       deactivates the refresh feature.
  //
  // This tool is not useful if you are not able to call it frequently.
  // A good way to do so is to employ a CRON job. Alternatively you can
  // activate the $AUTO_REFRESH feature.
  //
  // You can use this script for more than one twitter/identi.ca account.
  // To do so you have to read $IDENTICA_NICK, $IDENTICA_PASSSWORD and
  // $TWITTER_NICK from some other place (like a database).
  //
  // If you do not want others to see the status of your synchronization
  // you can protect the "*.date" and "*.lock" files with a small ".htaccess"
  // file that contains the following code (remove the leading ">"):
  // > RewriteEngine on
  // > Options +FollowSymLinks
  // >
  // > RewriteBase /
  // >
  // > RewriteRule ^(.*)\.date$ - [L,R=404]
  // > RewriteRule ^(.*)\.lock$ - [L,R=404]

  /* THESE SETTINGS ARE FREE TO EDIT */

  $EXECUTE_PASSWORD = "[EXECUTE_PASSWORD]";

  $AUTO_REFRESH      = 0;
  $IDENTICA_NICK     = "[IDENTICA_NICK]";
  $IDENTICA_PASSWORD = "[IDENTICA_PASSWORD]";
  $TWITTER_NICK      = "[TWITTER_NICK]";

  /* STOP EDITING HERE IF YOU DO NOT KNOW WHAT YOU ARE DOING */

  $DATE_FILE    = dirname(__FILE__) . "/" . $TWITTER_NICK . ".date";
  $IDENTICA_API = "https://identi.ca/api/statuses/update.xml";
  $LOCK_FILE    = dirname(__FILE__) . "/" . $TWITTER_NICK . ".lock";
  $TWITTER_RSS  = "http://twitter.com/statuses/user_timeline/" . $TWITTER_NICK . ".rss";
  $USER_AGENT   = "TCtoICsync 0.1b";

  /* STOP EDITING HERE */

  // we are going to output some UTF-8
  header("Content-Type: text/html; charset=utf-8");

  // only allow authorized access
  if (isset($_GET["pwd"]) && ($_GET["pwd"] == $EXECUTE_PASSWORD)) {
    // stop other executions from making trouble
    $locked = "0";
    if (file_exists($LOCK_FILE)) {
      $locked = file_get_contents($LOCK_FILE);
    }

    if ($locked == "0") {
      try {
        // disallow next execution
        file_put_contents($LOCK_FILE, "1");

        // retrieve Twitter RSS feed of user
        $options = array(
          CURLOPT_RETURNTRANSFER => true,
          CURLOPT_SSL_VERIFYHOST => false,
          CURLOPT_SSL_VERIFYPEER => false,
          CURLOPT_USERAGENT      => $USER_AGENT,
          CURLOPT_VERBOSE        => 1
        );
        $curl = curl_init($TWITTER_RSS);
        curl_setopt_array($curl, $options);
        $xml    = curl_exec($curl);
        $header = curl_getinfo($curl);
        curl_close($curl);

        // only proceed if Twitter RSS feed could be retrieved
        if ($header["http_code"] == 200) {
          print("Twitter RSS feed retrieved: " . $TWITTER_RSS . "<br />\n");

          // load last synchronization date
          $previousDate = null;
          if (file_exists($DATE_FILE)) {
            $previousDate = file_get_contents($DATE_FILE);
          }

          // parse feed
          $xml = new SimpleXMLElement($xml);

          // convert SimpleXMLElement to array
          $index      = 0;
          $latestDate = $previousDate;
          $messages   = null;
          foreach ($xml->channel[0]->item as $item) {
            if (($item->title != null) && ($item->pubDate != null)) {
              $currentDate = strtotime($item->pubDate);

              // only synchronize new tweets
              if (($previousDate == null) || ($previousDate < $currentDate)) {
                $temp = html_entity_decode($item->title, ENT_QUOTES, "UTF-8");

                // check if tweet belongs to selected twitter user
                if (stripos($temp, $TWITTER_NICK) === 0) {
                  $messages[$index++] = substr($temp, strlen($TWITTER_NICK)+2);

                  if ($latestDate == null) {
                    $latestDate = $currentDate;
                  } else {
                    if ($latestDate < $currentDate) {
                      $latestDate = $currentDate;
                    }
                  }
                }
              }
            }
          }

          if (($messages != null) && (count($messages) > 0)) {
            // reverse messages
            $messages = array_reverse($messages);
            ksort($messages);

            // handle Twitter messages
            foreach ($messages as $message) {
              // call identi.ca API
              $options = array(
                CURLOPT_HTTPAUTH       => CURLAUTH_BASIC,
                CURLOPT_POST           => true,
                CURLOPT_POSTFIELDS     => "status=" . urlencode($message) . "&source=" . urlencode($USER_AGENT),
                CURLOPT_RETURNTRANSFER => true,
                CURLOPT_SSL_VERIFYHOST => false,
                CURLOPT_SSL_VERIFYPEER => false,
                CURLOPT_USERAGENT      => $USER_AGENT,
                CURLOPT_USERPWD        => $IDENTICA_NICK . ":" . $IDENTICA_PASSWORD,
                CURLOPT_VERBOSE        => 1
              );
              $curl = curl_init($IDENTICA_API);
              curl_setopt_array($curl, $options);
              $output = curl_exec($curl);
              $header = curl_getinfo($curl);
              curl_close($curl);

              if ($header["http_code"] == 200) {
                print("Tweet synchronized: " . $message . "<br />\n");
              } else {
                print("Tweet could not be synchronized: " . $message . "<br />\n" . $output . "<br />\n");
              }
            }
          }

          // save last synchronization date
          if ($latestDate != null) {
            file_put_contents($DATE_FILE, $latestDate);
          }
        } else {
          print("Twitter RSS feed could not be retrieved: " . $TWITTER_RSS . "<br />\n");
        }
      } catch (Exception $e) {
        print("An exception has occured. Execution has been aborted.<br />\n");
      }

      // allow next execution
      file_put_contents($LOCK_FILE, "0");
    } else {
      print("The synchronization is already running.<br />\n");
    }
  } else {
    print("You are not authorized to execute this action.<br />\n");
  }
  print("DONE!<br />\n");

  if ($AUTO_REFRESH > 0) {
    print("<br />\nWill auto-refresh in " . $AUTO_REFRESH . " seconds.<br />\n");
    print("<script tyle=\"text/JavaScript\">\n");
    print("<!--\n");
    print("  setTimeout(\"location.reload(true);\", " . $AUTO_REFRESH*1000 . ");\n");
    print("//-->\n");
    print("</script>\n");
  }
?>

Ja, es ist ein Batzen Code, deswegen hier ein kurze Erklärung: Ganz am Anfang in dem elendig langen Kommentar steht das ganze GPL-Geraffel, gefolgt von einem kleinen Howto. Dort wird beschrieben, welche Werte vom Benutzer geändert werden müssen, was sie bedeuten und wofür sie benutzt werden. Es gibt noch ein paar weitere Werte, die verändert werden können - das sollte allerdings nur von Leuten getan werden, die auch wirklich wissen, was sie da tun!

Zu Beginn des eigentlichen Codes wird ein Passwort überprüft. Das soll verhindern, dass fremde Leute mit dem Code rumspielen und das Script nach Belieben aufrufen können. Zudem wird sichergestellt, dass das Script nicht mehrfach parallel ausgeführt werden kann. Hierdurch könnten Tweets mehrfach bei Identi.ca landen. Auf die Implementierung der Sperre sollte man sich jedoch nicht zu 100% verlassen, da sie relativ einfach gestrickt ist. Die gröbsten Probleme sollte sie jedoch auffangen können.

Die eigentliche Funktionalität sieht nun so aus: Das Script ruft den RSS-Feed des Twitter-Nutzers ab. In diesem befinden sich die letzten 20 Tweets, die man verfasst hat. Wichtig: Die Tweets müssen für alle zugänglich sein, ansonsten kann das Script die Tweets nicht auslesen. Wenn die Tweets ausgelesen worden sind, wird überprüft, ob sie zum richtigen Benutzer gehören und ob sie nicht bereits bei Identi.ca eingespielt wurden (wird anhand des Datums geprüft). Anschließend werden die neuen Tweets mit Hilfe der Identi.ca-API auf der Plattform eingespielt.

Das Script selber legt zwei Dateien an - eine "*.date"-Datei und eine "*.lock"-Datei. In die .date-Datei wird der Zeitstempel des letzten Tweets geschrieben, der nach Identi.ca synchronisiert wurde - dadurch kann beim nächsten Aufruf geprüft werden, welche Tweets neu sind. Die .lock-Datei ist dafür da, um sicherzustellen, dass das Script nicht doppelt ausgeführt werden kann.

Eigentlich hatte ich vor, das Script bei Hetzner mit einem einfachen CRON-Job jede Minute einmal laufen zu lassen. Leider ist es dort nur erlaubt, einen CRON-Job alle 2 Stunden laufen zu lassen - viel zu viel für solch eine Aufgabe! Deshalb habe ich eine Option eingebaut, mit der ein Stück JavaScript in die Ergebnisseite des Scripts geschrieben wird. Durch diesen JavaScript-Code kann man das regelmäßige Aufrufen mit jedem beliebigen Browser erledigen, der JavaScript beherrscht. Einfach die Seite einmal aufrufen und fertig. Bei mir läuft das Script nun z.B. im Browser meines Windows-Heimservers - der ist schließlich sowieso die ganze Zeit eingeschaltet. ;-)

So, das war es zum Sync-Script; jetzt noch ein kleiner Tipp für die Leute, die gerne zweigleisig fahren wollen: Da man mit dieser Lösung weiterhin mit Twitter als primäre Plattform arbeitet, kriegt man hintenrum garnicht mit, dass ein Identi.ca-Nutzer einem eine Nachricht geschrieben hat. Hierfür bietet Identi.ca direkt eine Lösung an. Und zwar kann man seinen Identi.ca-Account mit seinem Twitter-Account verbinden und Identi.ca dann anweisen, @-Replies von Identi.ca nach Twitter zu schicken, damit man sie dort wie normale Tweets lesen kann:

Twitter-Optionen bei Identi.ca

Sooo... ich hoffe, dieser ziemlich lange Artikel hat euch gefallen. Ich würde mich freuen, dem ein oder anderen mit dieser Arbeit zu helfen, sich ein Stückchen von Twitter zu lösen. Das gezeigte Script dürfte hierfür ein gutes, schmerzloses Mittel sein. :-)

Zum Schluss noch etwas Rechtliches:
Der Autor dieses Programms haftet nicht für Schäden an Soft- oder Hardware oder Vermögensschäden, die durch das Benutzen des Programms entstehen, es sei denn, diese beruhen auf einem grob fahrlässigen oder vorsätzlichen Handeln des Autors, seiner Erfüllungsgehilfen oder seiner gesetzlichen Vertreter.

Update:
Derzeit funktioniert dieses Script leider nicht, da die verwendete URL zum Abrufen der Tweets von Twitter nicht mehr angeboten wird. Es gibt jedoch die Möglichkeit, das Script auf die URL http://search.twitter.com/search.rss?q=from%3Ausername umzuschreiben. Diese Arbeit muss ich jedoch erst noch auf mich nehmen. :-)

Twitdentende Grüße, Kenny


24. November 2010 ~ 2 Kommentare | ÄHNLICHE ARTIKEL

[Update] Passwörter von TightVNC ermitteln…

Nachdem ich letztens nachgewiesen habe, wie unsicher eines der Lieblingstools von Hannes Schurig ist, hat dieser mich gestern angeschrieben und gefragt, ob ich mir nicht mal das OpenSource-Tool TightVNC angucken könnte.

Wie er mitbekommen hatte, speichert der TightVNC-Server in der Registry unter "HKCU\Software\TightVNC\Server" zwei Werte mit den Namen "Password" und "PasswordViewOnly". Seine Frage war nun, ob es möglich wäre, aus den kryptischen Werten die ursprünglichen Passworte für den "Remote Control"- und den "Remote View Only"-Zugang wiederherzustellen.

Da man von diesem Programm die Quelltexte erhält, habe ich mir diesen natürlich zuerst angeguckt und habe auch relativ schnell eine Antwort auf die Frage gefunden: Ja, man kann die ursprünglichen Passworte anhand der Werte in der Registry ermitteln!

Um das herauszufinden, habe ich am Quellcode entlang gehangelt. Begonnen habe ich in der Datei "ServerConfig.cpp" - in dieser wird die Klasse ServerConfig definiert, die später anscheinend die gesamte Konfiguration vorhält. In dieser Klasse gibt es u.a. auch die beiden Methoden "setControlPassword()" und "setReadOnlyPassword()", die einen Rückschluss auf die verschiedenen Zugänge zulassen.
Um zu sehen, was weiter geschieht, habe ich nachgesehen, wo die Methode setControlPassword() überall aufgerufen wird - das wiederum ist u.a. in der Datei "ControlApplication.cpp" der Fall, in der sich die Methode "run()" befindet. In der Methode werden anscheinend Kommandozeilen-Parameter verarbeitet und wie es aussieht, kann man die Passwörter über die Kommandozeile setzen.
Auffallend ist die Verwendung der Methode "getCryptedPassword()" - sie befindet sich in der gleichen Datei und enthält u.a. einen Aufruf der Form "VncPassCrypt::getEncryptedPass()". Diese Methode (die sich in der Datei "VncPassCrypt.cpp" befindet) enthält nun die eigentlich interessante Passage:

1
2
3
4
5
6
7
void VncPassCrypt::getEncryptedPass(UINT8 encryptedPass[8],
                                    const UINT8 plainPassword[8])
{
  DesCrypt desCrypt;
  desCrypt.encrypt(encryptedPass, plainPassword,
                   sizeof(encryptedPass), m_key);
}

Das Passwort, das oben eingekippt wird, wird unten DES-verschlüsselt wieder ausgegeben - eine Entschlüsselungsmethode wird übrigens gleich mitgeliefert und selbst das Passwort liegt fest einprogrammiert im Quelltext vor:

1
const UINT8 VncPassCrypt::m_key[] = { 23, 82, 107, 6, 35, 78, 88, 7 };

Man sollte sich also dringend überlegen, wie man die Passwörter in der Registry absichert, wenn man vorhat, TightVNC zum Beispiel zur Fernwartung von Mitarbeiter-PCs zu nutzen. Die Leute könnten schneller an das Passwort kommen, als einem lieb sein dürfte.

Entschlüsselte Grüße, Kenny


01. November 2010 ~ 1 Kommentar | ÄHNLICHE ARTIKEL

[Update] Kommentare auf der Indexseite…

Kennt ihr das? Man arbeitet Stunde um Stunde an einem Problem, macht permanent Fortschritte und trotzdem fühlt es sich an, als ob man auf der Stelle treten würde? Genauso geht es mir gerade mit einer neuen WordPress-basierten Seite, an der ich gerade arbeite.

Bei dieser möchte ich, dass man auf der Artikelübersichtsseite bereits Kommentare lesen und schreiben kann. Das ist garnicht sooo einfach, weil kaum ein WordPress-Theme (geschweige denn WordPress selber) dafür konzipiert zu sein scheint. Da ich nun (so hoffe ich jedenfalls) alle wichtigen Schritte hinter mir haben sollte, dachte ich mir, ich veröffentliche einen kleinen Leidtfaden, um euch zu erklären, worauf ihr bei solch einem Vorhaben unbedingt achten müsst.

Fangen wir mal mit dem wahrscheinlich größten Krisenherd an: der "comments.php" eures Themes. Diese enthält den Aufbau des Kommentarbereichs und ist mit hoher Wahrscheinlichkeit nicht dafür ausgelegt, mehrfach auf einer Seite angezeigt zu werden! Primäres Problem ist, dass es einige Elemente gibt, die unter Garantie mit einem id-Attribut versehen sind - diese müsst ihr so abändern, dass die IDs wieder eindeutig werden. Hierfür solltet ihr ziemlich weit oben solch einen Codeblock einfügen:

1
2
3
4
5
6
7
8
9
10
11
<?php
  // use this when more than one comment form is displayed
  global $postTABcount;
    if (!isset($postTABcount)) {
    $postTABcount = 1;
  }
  $postIDstring = "";
  if ((!is_single()) && (!is_page())) {
    $postIDstring = "-" . get_the_ID();
  }
?>

In diesem werden zwei Variablen initialisiert - "$postTABcount" und "$postIDstring". Während $postIDstring euch helfen wird, eure IDs eindeutig zu machen, ist $postTABcount dafür da, eure Tab-Indizes ordentlich zu setzen - aber dazu später mehr!

Angenommen ihr habt in eurer Datei solch eine Zeile stehen:

1
<div id="comments">

Dann würde ich euch empfehlen, diese wie folgt abzuändern:

1
<div id="comments<?php print($postIDstring); ?>" class="comments">

Dadurch habt ihr folgendes erreicht: Die ID ist eindeutig und durch Setzen der Klasse könnt ihr trotzdem noch ein einheitliches Styling einrichten.

Weiterhin solltet ihr überprüfen, wie das eigentliche Kommentare-anzeigen implementiert ist. In meinem Fall wurde dazu die Funktion "wp_list_comments()" verwendet. Bei dieser müsst ihr darauf achten, dass die Liste der zu zeigenden Kommentare explizit mitgegeben wird. Ansonsten kann es euch passieren, dass ihr unter jedem Artikel die gleichen Kommentare angezeigt bekommt. ;-)

1
2
3
<ol class="commentlist">
  <?php wp_list_comments($commentStyling, get_comments('post_id=' . get_the_ID())); ?>
</ol>

Eine Besonderheit erwartet euch am Ende eures Formulars: Seit ein paar Version wird es vom Codex verlangt, dass im Kommentarformular der Rückgabewert der Funktion get_comment_id_fields() eingebaut wird - und wie es der Zufall will, handelt es sich dabei um versteckte Input-Elemente inklusive id-Attribut. Um diese id-Attribute eindeutig zu machen, könnt ihr folgenden Quellcode nutzen:

1
2
3
4
<?php
  // change "id" in autogenerated code
  print(preg_replace("/\<(.+) id\=\'(.+)\' (.+)\>/iU", "<$1 id='$2" . $postIDstring . "' class='$2' $3>", get_comment_id_fields()));
?>

Nun erwartet euch in dieser Datei nur noch eine Kleinigkeit: Es ist wahrscheinlich, dass die Inputfelder des Kommentarbereiches mit tabindex-Attributen ausgestattet sind. Durch diese ist es möglich, durch drücken der Tab-Taste ins nächste Feld zu springen. Da es später potentiell mehrere Felder geben wird, solltet ihr die statischen Zahlen (meist 1 bis 5) durch diesen Code ersetzen, der die Zahl automatisch hochzählt:

1
<?php print($postTABcount++); ?>

Wenn ihr alle Stellen gefunden und ersetzt habt, seid ihr mit dieser Datei soweit durch! :D

Machen wir also schnell weiter! Angenommen, ihr wollt die Kommentarfunktion auf der Indexseite anbieten. Dann müsst ihr nun die "index.php"-Datei eures Themes öffnen. In dieser sollte sich eine Zeile befinden, die so oder so ähnlich aussieht:

1
<?php if (have_posts()) : while (have_posts()) : the_post(); ?>

Über diese Zeile solltet ihr folgenden Code einfügen, der dafür sorgt, dass das Tabindex-Durchnummerieren korrekt funktioniert:

1
2
3
4
<?php
  // needed for tabindex of comment form elements
  $postTABcount = 1;
?>

Und nun der letzte größere Schritt: In der while-Schleife, die sich in der Datei befindet, sollte irgendwo ein Aufruf der Funktion the_content() oder the_excerpt() zu finden sein. Unter diesen Aufruf solltet ihr nun folgenden Code einfügen können, um das gerade vorbereitete Kommentarformular anzeigen zu lassen:

1
2
3
4
<?php
  $withcomments = true;
  comments_template();
?>

Das Setzen der Variable "$withcomments" sorgt übrigens dafür, dass der Aufruf der Funktion comments_template() auch im Index- und Archiv-Template funktioniert. ;-)

Wenn ihr so weit gekommen seid, sollte euer Kommentarbereich eigentlich schon unter jedem Post auf der Indexseite angezeigt werden. In meinem Anwendungsfall ist es nun aber so, dass es den Nutzern nicht möglich ist, eine einzelne Artikelseite zu öffnen - sie müssen auf der Indexseite bleiben. Das stellt beim Kommentar absenden ein großes Problem dar. Denn standardmäßig springt WordPress nach dem Absenden eines Kommentars in den dazugehörigen Artikel! Um dieses Verhalten zu umgehen, habe ich ein kleines Plugin ("Back2Ref") geschrieben, das einen nach dem Absenden eines Kommentars zu der Seite zurücklotst, auf der man den Kommentar geschrieben hat:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?php
  /*
    Plugin Name: Back2Ref
    Plugin URI: http://weizenspr.eu/
    Description: Will redirect the user to the referer he comes from when sending a comment.
    Version: 0.1c1
    Author: Kevin Niehage
    Author URI: http://weizenspr.eu
  */


  function back2ref_execute($location, $comment) {
    $result = $location;

    if (isset($_SERVER['HTTP_REFERER'])) {
      $result = $_SERVER['HTTP_REFERER'];

      if ($comment != null) {
        $result = $result . "#comment-" . $comment->comment_ID;
      }
    }

    return $result;
  }

  add_filter('comment_post_redirect', 'back2ref_execute', 10, 2);
?>

Puuuh... nun ist es aber wirklich endlich geschafft! Das war doch mal ein Haufen Arbeit für einen einzigen Artikel. ;-)

Update:
Hinweis zu AntispamBee entfernt.

Zum Schluss noch etwas Rechtliches:
Der Autor dieses Programms haftet nicht für Schäden an Soft- oder Hardware oder Vermögensschäden, die durch das Benutzen des Programms entstehen, es sei denn, diese beruhen auf einem grob fahrlässigen oder vorsätzlichen Handeln des Autors, seiner Erfüllungsgehilfen oder seiner gesetzlichen Vertreter.

Kommentierende Grüße, Kenny


28. Oktober 2010 ~ 9 Kommentare | ÄHNLICHE ARTIKEL

[Update] Öffentliche Schlüssel sind KEINE Zertifikate!

Ich könnte gerade einfach nur schreien. Es ist ein Anwendungsfall aufgetaucht, in dem es notwendig wäre, SSH-Zugänge nicht über eine Passwort-Abfrage, sondern über eine Public-Key-Infrastruktur zu realisieren. Natürlich habe ich mich im Internet auf die Suche danach gemacht, wie man Zertifikate im Zusammenhang mit OpenSSH (wäre die bevorzuge Implementierung) nutzen kann.

Was ich dabei jedoch gefunden habe, spottet jeder Beschreibung. Es scheint so, als ob der Großteil der SSH-Nutzer-Bevölkerung nicht den Unterschied zwischen einem öffentlichen Schlüssel und einem Zertifikat kennt. Diese Unwissenheit reicht dabei von Bloggern, die zu wenig Zeit für Windows haben bis hin zu größeren Projekten wie TortoiseSVN.

Da liest man dann schonmal Dinge wie: "Im Grunde [wird ein] sehr kurzes Passwort durch ein sehr langes ersetzt [...]. Nur wird es dann Zertifikat genannt. Dieses Zertifikat ist in zwei Teile aufgeteilt; in einen privaten und in einen öffentlichen Teil." (wurde inzwischen korrigiert).
Nein, natürlich ist das kein Zertifikat, dass da aus einem öffentlichen und einem privaten Teil besteht - so ein Zertifikat ist idR. immer öffentlich, sonst könnte es niemand auf Echtheit prüfen.

Die Dokumentation von TortoiseSVN hat mich besonders geärgert. Da ich dort auf mehr Fachwissen gehofft hatte, habe ich mich auf den Artikel mit dem Titel "Creating OpenSSH Certificates" gestürzt, nur um dann zu lesen, wie man mit OpenSSH ein RSA-Schlüsselpaar (besteht aus einem öffentlichen und einem privaten Schlüssel) erzeugen kann.

Ein wirklich echtes Zertifikat wird nicht einfach nur erzeugt, sondern es muss eine dritte Partei (eine Certificate Authority) involviert sein, die das Zertifikat erstellt. Dabei kommt dann meist soetwas wie ein Certificate Signing Request zum Einsatz.
Denn was ich eigentlich will ist folgendes: Ich möchte, dass man sich mit einem privaten Schlüssel am SSH-Server anmelden kann, wenn das dazu passende Zertifikat (enthält idR. auch den öffentlichen Schlüssel) auf dem Server hinterlegt ist. Die Crux des Ganzen: Beim versuchten Login müsste der SSH-Server prüfen, ob das Zertifikat tatsächlich von der zugelassenen Zertifizierungsstelle stammt und, ob das Zertifikat überhaupt noch gültig ist! Alles andere würde dazu führen, dass Nutzer sich (potentiell) selbst einen SSH-Login einrichten können und dieser zudem beliebig lange nutzbar bleibt.

Wenn also irgendjemand weiß, wie man OpenSSH mit Zertifikaten (nicht mit einfachen öffentlichen Schlüsseln!) absichern kann, dann würde ich mich über eine Nachricht von demjenigen freuen. :-)

Update:
Nachdem ich mich gerade noch durch die OpenSSH-Dokumentation gegraben habe, habe ich herausgefunden, dass OpenSSH in der Tat auch mit Zertifikaten arbeiten kann :D ! Dafür müssen zum einen die öffentlichen Schlüssel der Nutzer von einer CA signiert werden und zum anderen muss der Daemon sshd so konfiguriert werden (Stichwort "TrustedUserCAKeys"), dass dem CA, der das Zertifikat erstellt hat, auch vom Server vertraut wird.

Zertifizierte Grüße, Kenny


490
no-www.org extra-www.org
IPv6 ready XHTML 1.0 Transitional

Datenbank: 51 Abfragen | Generierung: 0,32033 Sekunden