Archive for the 'PHP' Category

Apr 24 2008

SQL und prepared Statements

Veröffentlicht by . Filed under: PHP

Bisher hab ich eigentlich fast immer meine SQL-Befehle direkt als einen String zusammengestellt und den SQL-Befehl mittels adoDB ausgeführt. Mir war zwar bekannt, dass es “prepared Statements” gibt, verwendet hab ich sie aber selten. Wenn man daran denkt, die eingefügten Werte zu maskieren (Stichwort SQL-Injection), hielt ich das bisher auch für kein Problem. Prepared Statements waren für mich also bisher genau dann sinnvoll, wenn der SQL-Befehl vorab kompiliert werden soll, was bei wiederholter SQL-Ausführung (Schleifen) sinnvoll ist.

Nun bin ich aber dabei, stärker mit DB2 zu arbeiten. Und da kann es passieren, dass ein solch erstellter SQL-Befehl nicht funktioniert. Das Problem ist, dass DB2 sich weigert Zeichenketten mit mehr als 32kb zu verarbeiten. Mit Hilfe von prepared Statements ist das aber kein Problem. Interessanterweise bietet DB2 sogar die Funktion an, direkt eine Binär-Datei (Bild) über prepared Statements einzufügen, ohne dass diese Datei vorher in PHP gelesen werden muss. Das ist mal ein echter Vorteil!

1 Star2 Stars3 Stars4 Stars5 Stars
Loading ... Loading ...
No responses yet

Mrz 15 2008

[lang_de]Chart-Diagramme[/lang_de][lang_en]chart diagrams[/lang_en]

Veröffentlicht by . Filed under: jQuery,PHP

[lang_de]Derzeit bin ich für meine Doktorarbeit auf der Suche nach guten Visualisierungstechniken für statistische Ausgaben. Glücklicherweise gibt es hier sowohl gute kostenpflichtige Projekte, aber es gibt auch meiner Meinung nach sehr gute kostenlose OpenSource-Projekte:

Da wäre natürlich ein auf jQuery basierendes Plugin wie Flot als auch das auf Mochikit basierende Plugin PlotKit. Beide verwenden SVG, um die Diagramme darzustellen (im IE natürlich einige Hacks). Der Vorteil besteht darin, dass sie äußerst einfach interaktiv gestaltet werden können.

Es gibt aber auch ein sehr nettes Projekt, welches direkt Flash-Diagramme in PHP erstellt: das Open Flash Project. Auch hier ist es möglich, mittels JavaScript die Interaktion zu verbessern.

Und das beste: vernünftige Lizenzen! Flot gibt es unter MIT-Lizenz, Plokit steht under BSD und ein Teil unter Apache-Lizenz, Open Flash Chart ist LGPL. Damit ist die Verwendung relativ problemlos.

Gibt es weitere interessante Projekte in dieser Hinsicht?[/lang_de]

[lang_en]
For my PhD thesis, I’m looking for technics to visualize statistical data. I’m very happy to see, that there are good professional tools, but there are also very good open source solutions:

Of course, there exists a jQuery plugin called Flot. There is also a very good plugin for Mochikit called PlotKit. Both JavaScript chart technics us SVG to visualize the data (IE needs hacks of couse). In this way, it is very easy to use JavaScript for interaction. Very nice!

There is also a really nice project, which can create Flash Diagramms with the help of PHP: the Open Flash Project. Here again, it is possible to use JavaScript for interaction.

And the best: they use nice licences! Flot is under MIT licence, Plokit uses BSD and a part of it uses the apache licence, Open Flash Chart is LGPL/MIT.

Are there any other interesting projects?
[/lang_en]

1 Star2 Stars3 Stars4 Stars5 Stars
Loading ... Loading ...
No responses yet

Feb 22 2008

[lang_de]PHP-Sicherheit: Session-Fixierung[/lang_de][lang_en]php security: session fixation[/lang_en]

Veröffentlicht by . Filed under: PHP

[lang_de]
PHP ist eine äußerst beliebte Programmiersprache. Wie jede Sprache hat sie natürlich ihre Vor- und Nachteile. Oft wird dabei die mangelhafte Sicherheit genannt. Das liegt jedoch nach meiner Meinung eher an schlechten Kenntnissen der meisten Programmierer. Ein solcher Punkt ist die sogenannte Session-Fixierung.

Problemsituation
In PHP ist es einfach, eine Session zu starten. Das geht häufig über

session_start();

Dabei wird geschaut, ob als Cookie oder als URL-Parameter (je nach Servereinstellung) eine Session-ID vorhanden ist. Ist sie das, wird die Session mit einer entsprechenden ID geladen. War sie bisher leer, so wird sie neu initialisiert. Ist hingegen keine ID vorhanden, so wird eine zufällige Session-ID verwendet.

Angriffszenario

Stellen wir uns einen Hacker vor, der einen Admin-Zugriff zu einem Shop haben will. Die einfachste Möglichkeit, an diesen zu gelangen, besteht darin, den Admin direkt danach zu fragen. So wäre folgende Mail an einen Shop-Inhaber denkbar:

Sehr geehrter Herr [Name],

ich habe heute Ihren Shop entdeckt und dabei ist mir aufgefallen, dass Ihr Shop eine Sicherheitslücke aufweist. Wenn Sie auf folgende URL klicken (manipulierte URL) und sich anschließend an Ihren Shop anmelden, sehen Sie, dass sich jeder Benutzer als Admin anmelden kann.

Der Shop-Besitzer, der natürlich Angst um seine Investition hat, wird ohne Nachdenken auf den Link klicken. Doch was tut dieser Link? Er leitet direkt an den Shop weiter, übergibt jedoch per Cookie oder per URL-Parameter eine festgelegte Session-ID. Den Namen der Session-ID hat der Hacker zuvor natürlich ausgekundschaftet, indem er einfach den Shop verwendete.

Das Problem ist jetzt, dass keine neue Session-ID erzeugt wird, da ja eine angegeben wurde. Der Shop-Besitzer muss sich nun lediglich anmelden und schon kann der Hacker als Admin tätig werden (er weiß die Session-ID ja).

Problemlösung
Die Lösung des Problems ist denkbar einfach: man muss beim Laden der Session lediglich prüfen, ob ein spezieller Wert schon angelegt wurde:

session_start();

if (!isset($_SESSION["init"])) {
//Session ist neu – neue ID auf jeden Fall vergeben
session_regenerate_id();
$_SESSION["init"]=true;
}

Sehr einfach und löst das Problem. Man muss es nur wissen.

[Update]
Nach Diskussion in den Kommentaren mit Erich folgender Hinweis: Natürlich ist es möglich, dass der Angreifer eine Session öffnet und diese offen hält. Diese Session-Daten könnte dann an einen Benutzer mit erhöhten Rechten mit Hilfe eines manipulierten Links gegeben werden. Klickt dieser darauf und meldet er sich an, so hab ich als Hacker die neuen Anmelde-Daten.

Im Prinzip übernimmt also der Benutzer die korrekte Session des Hackers, womit wir einen Fall von Session-Hijacking haben. Dies kann man mit oben beschriebenen Script nicht verhindern. Es gibt mehrere Möglichkeiten, das zu verhindern:

  • Ich verwende session_regenerate_id nach dem Anmelden. Damit stell ich sicher, dass ich auf jeden Fall eine neue ID verwende und der Hacker nicht mehr darauf zugreifen kann. Die alten Session-Daten werden dabei übernommen. Das Problem ist jedoch, dass je nach Session-Inhalt Daten übernommen werden, die weiterhin kritisch sind. Diese Lösung funktioniert deshalb nur, wenn ich auch darauf achte, dass die Session übernommen sein könnte. Wenn ich z.B. meine UserID in der Session speichere, muss ich berücksichtigen, dass die falsch sein könnte. Das Verfahren stellt also lediglich sicher, dass der Hacker keinen direkten Zugriff bekommt, weil er eine andere Session hat. Sie stellt aber nicht sicher, dass dadurch das System sicherer wird.
  • Die meiner Meinung nach bessere Möglichkeit besteht darin, sich wirklich gegen Session-Hijacking komplett zu schützen. Einen 100%-Schutz gibt es dabei nicht. Es hat sich aber bewährt, einen Fingerabruck vom Benutzer zu erstellen. Dazu sammelt man in einem Array erstmal Daten über den Benutzer und bildet darüber einen Hash-Wert.

    $fingerprintArray = array($_SERVER['HTTP_USER_AGENT'],substr($_SERVER["REMOTE_ADDR"],0,7),…);
    $fingerprint = md5(serialize($fingerprintArray));

    Wichtig ist dabei darauf zu achten, dass die Remote-Adresse nicht komplett benutzt wird, weil sie sich bei vielen Anbietern ständig ändert.

    Vergleicht man nun bei jeder Abfrage diesen Fingerabdruck, kann man recht sicher sein, dass der Benutzer korrekt identifiziert wurde. Heißt also: anderer Fingerabdruck? Session sofort löschen.

Sicher sollte man sein, indem man beide Techniken kombiniert.

[/lang_de]

[lang_en]
PHP is a loved programming language. But of course there are good and bad features as in any other programming language, too. Security can be heared to be one of the bad features. But in my opinion, the reason is not php but users who don’t know the problems. One problem is the so called session fixation

problem situation
It is very easy in PHP to start a session:

session_start();

If you start a session, the server looks if there is a cookie or a url param with a session id. If there is a session id, it will be used. If the session was not used before, it is created with this id. If there is no id, it will be generated randomly.

attack scenario

If you are a hacker and you want to have the admin access to a shop, what can you do. The simliest way is to ask the shop owner of course. So you write an email like this

Dear [Name],

I have found your shop and I have seen, that every user can get an admin access. I think this is a big security risk! If you click at this url (manupulated URL) and if you login, you will see that there is a big security hole.

The shop owner does not know anything about security and programming. So he will click the url to see the problem and to save his investment. But what does the url do? It only redirects the user to the shop and sets a cookie or a url param with a fixed session id. The name of the id is known by using the shop as costumer.

The problem is, that the session id is not regenerated. If the shop admin logs in, the hacker has an admin access.

problem solution
The solution of this problem is very simple. You only have to check if the session was used before. If not, you must regenerate the id for yourself:

session_start();

if (!isset($_SESSION["init"])) {
//session is new – regenerate the id!
session_regenerate_id();
$_SESSION["init"]=true;
}

Very easy, isn’t it?

[Update]
After disussing with Erich following notice: Of course, it is possible, that a hacker creates a valid session and that he can keep this session active. He can give a manipulated link to an user with higher rights. If this user would use the link and he would log on in the system, the hacker will have more rights.

In this case, the user uses a valid session, which is not his session. So, we have a special case of session hijacking. The above described script is NOT able to handle this. We can solve this problem like this:

  • Use session_regenerate_id after login, so that the user has surely a new session id. Old session data will remain, what is necessary in some systems. The problem is, that also critical session data will remain. So you have to be aware, that there can be wrong data (e.g. wrong user id) in your session. This solution will make sure, that the hacker gets no privileged access. But it does not make sure, that your application is secure at all.
  • In my opinion, it would be better to include a session hijacking protection. You can create a fingerprint of your user and you have to check this fingerprint at every connection. So collect information about your user and save it to the session as hash value:

    $fingerprintArray = array($_SERVER['HTTP_USER_AGENT'],substr($_SERVER["REMOTE_ADDR"],0,7),…);
    $fingerprint = md5(serialize($fingerprintArray));

    Important: don’t use the complete REMOTE_ADDR because it could change with every request.

    If the fingerprint is different to the stored fingerprint: delete the session.

The most secure way is to use both methods, surely.
[/lang_en]

1 Star2 Stars3 Stars4 Stars5 Stars
Loading ... Loading ...
22 responses so far

Feb 16 2008

[lang_de]Passwort-Hashes und Systemsicherheit[/lang_de][lang_en]password hashes and system security[/lang_en]

Veröffentlicht by . Filed under: PHP

[lang_de]
Inzwischen hat es sich rumgesprochen, dass man keine Passwörter in Plaintext speichern soll. Das stellt ein grobes Sicherheitsrisiko dar, da nicht davon ausgegangen werden kann, dass die Datenbank sicher vor fremden Zugriff hat. Nichts ist peinlicher, als dass man zugeben muss, dass Passwörter in Reintext geklaut werden konnten.

Deshalb speichern nahezu alle verfügbaren Systeme ein Passwort kodiert. Das geschieht meist mit einem md5, seltener auch mit einem SHA1-Hash:

$passwordEncoded = md5($password);

Da es sich bei Hash-Verfahren um Einweg-Verschlüsselungen handelt, ist es damit nicht möglich, direkt auf das Original-Passwort zu gelangen. Wunderbar könnte man meinen. Leider hat man dann nicht mit der Energie krimineller Täter gerechnet. Denn neben Brute-Force-Berechnungen gibt es noch ganz andere Möglichkeiten, auf die Original-Passwörter zu kommen. Das müssen keineswegs komplexe Rechenoperationen sein. Viel einfacher ist die Verwendung spezieller Datenbanken, die zu vielen Ausdrücken die entsprechenden Hashes vorweisen können.

Eine Lösung dieses Sicherheitsproblems besteht darin, dem Benutzer einzubläuen, dass er auf jeder Seite unterschiedliche Passwörter verwenden soll. Dass das nicht funktioniert, dürfte bekannt sein. Eine andere intelligentere Lösung besteht darin, SALTs zu verwenden. Dabei handelt es sich um meist zufällig generierte String-Muster, die bei der Berechnung des Hashes mitbenutzt werden. Dadurch ist die Verwendung von Datenbanken zur Rückkodierung der Passwörter sinnlos. Eine passende PHP-Funktion namens crypt ist auch in der Lage genau das zu tun.

/*
* Ohne Angabe wird theoretisch ein zufälliger Salt-Wert generiert (ACHTUNG, das ist nicht immer so und hängt von der Serverkonfiguration ab
*/
$encryptedPassword = crypt($password);

Das Problem ist hier, dass je nach Serverkonfiguration ein SALT zufällig berechnet wird oder fest vorgegeben ist. Die Idee hinter der Verwendung des SALT-Wertes ist es jedoch gerade, dass keine Datenbank dafür möglich ist. Sobald jedoch eine Standard-Eingabe verwendet wird, verblasst dieser Effekt. Deshalb sollte hier gezielt darauf geachtet werden, dass ein zufälliger SALT-Wert verwendet wird.

Die Überprüfung eines Passwortes ist recht einfach. Übergibt man als SALT-Wert das bisherige Passwort, so wird der verwendete SALT automatisch ausgelesen (meistens die ersten Buchstaben).

if (crypt($password,$oldPassword) == $oldPassword) {
//Passwort stimmt
}

Es existiert auch eine passende mySQL-Funktion namens ENCRYPT, so dass der Vergleich auch auf der Ebene der Datenbank möglich ist. Jedoch sollte von dieser Passwort-Überprüfung Abstand genommen werden, da für jede Datenbankzeile die crypt-Funktion ausgeführt werden muss. Sinnvoller ist es da, nur nach dem Benutzernamen die Zeilen abzufragen und dann im Code das Passwort einmal zu überprüfen.

Die Verwendung von SALT und Hashes ermöglicht die relativ sichere Speicherung von Passwörtern und bietet dem Benutzer maximal möglichen Schutz.
[/lang_de]

[lang_en]

It is known that you should never save your passwords as plain text. There is a big security risk because you cannot make sure, that your server cannot be manipulated. For this reason, nearly every software stores passwords as hashes. Often, this is a md5 or a SHA1 hash.

$passwordEncoded = md5($password);

Because you cannot decode hashes, you cannot detect the password directly. But criminals are not stupid! There are some methods to get a password for a specific hash. One possibility is to use special databases to find plain passwords for hashes.

One possibility to solve this security problem is to force users to use different passwords. You all know, that this is not possible. It would be more clever to use so called SALTs. These mostly random generated strings are used to calculate different hashes. Databases cannot be used anymore. Of course, there is a special php function called crypt.

/*
* without a SALT given, it should be generated a random SALT
*/
$encryptedPassword = crypt($password);

There is one big problem using this function. Depending on your server configuration, it is possible that it is used a fixed SALT. But that is no good idea, because with a fixed SALT databases can be used again. So make sure, that you will always use a random SALT zu encrypt passwords!

If you want to check, if a password is valid or not, you can use the crypt function again. You only have to use the “old password” als SALT. The used SALT can be extracted:

if (crypt($password,$oldPassword) == $oldPassword) {
//password is correct
}

There is also a mySQL function to encrypt your passwords: ENCRYPT. It is important to note, that you should not use this function to check passwords because for each row the crypt function has to be executed. You should only check the nickname and if there exists a row with a given nickname, you can check this row with the crypt function.

SALT and hases makes storing passwords more secure. So use it!
[/lang_en]

1 Star2 Stars3 Stars4 Stars5 Stars
Loading ... Loading ...
3 responses so far

Feb 15 2008

[lang_de]PHP debuggen[/lang_de][lang_en]Debugging PHP[/lang_en]

Veröffentlicht by . Filed under: PHP

[lang_de]PHP existiert nun wirklich schon sehr lange. Und trotzdem gab es bisher nur kostenpflichtige Programme, mit denen man PHP sauber debuggen konnte. Dabei meine ich nicht die Ausgabe bestimmter Variablen mit var_dump oder mittels Firebug-Konsole. Nein, ich meine

  • das setzen von Breakpoints innerhalb der PHP-Umgebung
  • das schrittweise Überprüfen von Variablen ohne var_dump-Ausgaben
  • die geziehlte Manipulation von Variableninhalten während der Laufzeit
  • das geziehlte Verfolgen des Programm-Ablaufs innerhalb der Entwicklungsumgebung

Dabei sollte es natürlich unerheblich sein, ob man eine Konsolen-Anwendung programmiert oder ob man ein PHP-Script zur Erzeugung von Websiten erstellt.

Nun ist es endlich möglich, diese Möglichkeiten zu nutzen. Basis hierfür ist das PDT-Projekt im Rahmen der Eclipse-Umgebung. Es ist ein neues Projekt, das unabhängig zur Entwicklungsumgebung PHP Eclipse entstanden ist. Da letzteres Projekt in letzter Zeit auch eingeschlafen zu sein scheint, sollte für jeden PHP-Programmierer PDT auf jeden Fall ein Blick wert sein.

Innerhalb von PDT kann jeglicher PHP-Code debugged werden. Dabei kann sowohl auf den Zend-Debugger als auch auf das OpenSource-Modul xDebug zurückgegriffen werden. Es ist bei beiden Debuggern unerheblich, ob es sich um ein Konsolen-Script handelt oder ob es sich um eine Remote-Seite handelt. Vor allem das debuggen dieser Remote-Scripte ist sehr elegant gelöst. Man startet hierzu einfach den Debugger und kann die Seite wie gewohnt durchlaufen. Eclipse hält dabei die Verarbeitung der Scripte genau dann an, wenn ein Breakpoint gesetzt wurde. Dabei können alle Variableninhalte betrachtet werden und es ist auch möglich, diese Inhalte geziehlt zu manipulieren. Das Script kann anschließend schrittweise fortgesetzt werden oder man springt direkt zum nächsten Breakpoint.

Ich habe inzwischen mit dem Debugger in Verbindung mit xDebug beste Erfahrung gemacht. Konsolen-Ausgaben waren definitiv gestern!

[Link-Tipp]Remote debugging with PDT and xdebug
[/lang_de]

[lang_en]
PHP is really not a young language today. But until now, there have been only software with costs to debug PHP scripts. I don’t mean debugging via var_dump or with Firebug. No, I mean

  • using breakpoints within the development environment
  • checking variables step be step without using var_dump
  • manupulating variables
  • tracing program flows

Of course, it shouldn’t matter, if I’m analysing a script which was written for console or which was written for a web browser.

Now, this is all possible. All you have to use is the PDT project which is part of eclipse. It was developed independent of PHP Eclipse. It seems, that this project is not continued.

Within PDT, every PHP code can be debugged. There are two debuggers avaiable: the Zend-Debugger or an open source modul called xDebug. You can use both to debug PHP scripts which have been written for console or which have been written for browsers – so called remote scripts. If you want to debug remote scripts, you can start your debugger which will open your page in your favourite browser. You can use your web page as you use it without debugging. But when the script reaches a breakpoint, eclipse will stop it and you can see every variable and you can even manipulate them. If you want, you can continue the script step by step or you can jump to the next breakpoint.

I have used PDT for several weeks now and it works fantastic with xdebug. Debugging via var_dump was yesterday!

[Link tip]Remote debugging with PDT and xdebug
[/lang_en]

1 Star2 Stars3 Stars4 Stars5 Stars
Loading ... Loading ...
One response so far

Next Entries » | « Previous Entries

^