Das Plugin WP-Commerce scheint mir echt gefähtlich für Datei-Downloads zum im eigenen Webshop zu sein.
Das gefährliche Problem
Bis zur aktuellen Version WP e-Commerce 3.5.2 RC4 (UND der teuren “gold” edition!) ist der Download gekaufter digitaler Dateien mit einer URL á la http://meinshop.de/?downloadid=3 verbunden. Immerhin geht der Link dann auch genau nur einmal – und zwar so lange, bis wieder einer was “downloadbares” kauft – dann ist es eben /?downloadid=4 und wer zuerst kommt mahlt zuerst.
Mindestens genau so schlimm ist, dass die geheimen Dateien in einem öffentlichen Verzeichnis liegen (/wp-content/plugins/wp-shopping-cart/files/) und zwar als SHA1 Hash. Nur ist der SHA1 Hash IMMER gleich der ID der Datei!!! Also 1, 2, 3 usw. encrypted!
D. h. in JEDEM WP-Commerce gibt es in dem Verzeichnis eine Datei namens
356a192b7913b04c54574d18c28d46e6395428ab (nämlich sha1(“1″)) und
da4b9237bacccdf19c0760cab7aec4a8359010b0 (sha1(“2″))
und so weiter. Natürlich hat das Verzeichnis dann auch noch 755 CHMOD Rechte (also für jeden lesbar). Was ist denn das für ein Scheiss? Wer auch immer dieses Plugin benutzt – ich muss ja nur die URL oben eingeben und kann eine geheime Datei nach der anderen runterladen. Im Forum des Betreibers hat sich auch noch keiner drüber beschwert (nur ein Einziger hat erwähnt, dass er das im live-system umprogrammieren musste, weil er die sicherheitslücke bemerkte – wer rechnet denn auch damit?)
Lösung
Das “files”-Verzeichnis natürlich erstmal auf CHMOD 700 setzen.
Im Folgenden nur mein Lösungsansatz (der bei mir wunderbar klappt!!!) und nicht jeder Schritt im Detail:
- Man fügt in seine wp_download_status Tabelle ein VARCHAR(45) Feld mit Namen “hash” ein.
- In der submit_checkout_function.php Zeile 165 erweitert man den INSERT INTO um dieses Feld und füllt es mit z. B. sha1(‘xyz’.$product_data['file'].$log_id.’blabla’). Also etwas was in jeder Zeile der Tabelle anders aussehen dürfte. Oder sha1(time()) ist auch sicher gut.
- In der transaction_result_functions.php wird der Download-Link für die Bestätigungs-Email erstellt. Zeile 101 muss dann um den hash z. B. so “erweitert” werden:
$link = $siteurl.”?downloadid=”.$download_data['id'].”&code=”.$download_data['hash'];
- Als letztes muss in der wp-shopping-cart.php Zeile 1189 geprüft werden, ob der code ebenfalls übergeben wurde:
if(is_numeric($_GET['downloadid']) && $_GET['code'] != null)
Nur vier Zeilen tiefer wird dass dann mit der Datenbank abgeglichen:
$code = $_GET['code']; # < Diese Zeile wird hinzugefügt die nächste abgeändert
if($download_data != null && $code == $download_data['datehash'])
Jetzt ist es doch etwas detailierter gewesen…
So! Jetzt kann man sein Shop-Plugin natürlich nicht mehr updaten :(
Egal, funktioniert jetzt erstmal! Noch ein Hinweis: downloadid habe ich so gelassen wie es ist und nicht NUR nach dem code in der Tabelle gesucht, weil es dann nicht mehr Injection-Safe wäre. downloadid muss ja numerisch sein und wenn die ID stimmt, wird der Code erst abgeglichen.

Ich heiße Captain Future und meine Leidenschaft ist es die Brücke zwischen Menschen und Technik zu schlagen.