Türchen 15: Ein kleiner Einblick in Magentos validation.js

Nachdem mir in diesem Jahr auch die Ehre zuteil wurde, ein Teil des Webguys Adventskalenders zu sein, werde ich hier versuchen, dieser Ehre gerecht zu werden. Was in den nächsten Absätzen folgt, soll ein kleiner Einblick in die Frontend-Validierungsmöglichkeiten werden, die Magento so bietet.

Sicherheit - Ein Gedanke der sich durch alle Kundenschichten hindurchzieht

Heutzutage denken viele Kunden über verschiedene Sicherheitsaspekte in ihren Online-Shops nach und kommen zu dem Schluss, dass hier dringend etwas getan werden muss. Natürlich sind diese Sicherheitsaspekte auf ein Spektrum konzentriert, das sich oft mit dem Frontend beschäftigt und weniger mit serverseitigen Prozessen. Genau aus diesem Anlass kam mir kürzlich eine Kundenanfrage auf den Tisch, in der darum gebeten wurde im Rahmen der EHI-Zertifizierung, verschärfte Vorgaben für Kundenpasswörter umzusetzen.

Während dieser Arbeit habe ich mich verstärkt mit Magentos Formularverifizierungen auseinandergesetzt und möchte das hier ein wenig ausbreiten.

Really Easy Field Validation

Magento benutzt für die Validierung von Formularen validation.js - diese Bibliothek entstammt dem Projekt Really Easy Field Validation (im Folgenden REFV genannt). Diese Bibliothek ist in der Lage, über CSS-Selektoren Formularfelder nach bestimmten Regeln zu validieren. Diese Regeln können dynamisch erweitert oder ersetzt werden und bieten damit die ideale Grundlage, die Regeln für Passwörter oder beispielsweise Benutzernamen anzupassen, bevor diese an Magento geschickt werden.

Um die eingangs erwähnte Problemstellung zu lösen, habe ich eine kleine Extension erstellt, die die bestehende Passwort-Validierung auf den customer/account/create-Seiten überschreibt und mit einem RegExp auf etwas aufwändigere Regeln prüft.

  • Nicht nur Buchstaben, auch Sonderzeichen und Ziffern müssen verwendet werden
  • Die Zeichenfolge des Passwortes darf nicht gleich dem Benutzer-Identifier sein (sprich, das Passwort darf nicht die Anmelde-Email-Adresse sein)
  • Einfachstmuster a lá "aaaaaaaaa" oder "1234567" dürfen nicht verwendet werden
  • Das Passwort muss zwischen 8 und 20 Zeichen lang sein

Ein kleines Modul übernimmt das Einbinden des erweiterten Validators per layout.xml. Wie das geht, werde ich hier allerdings nicht erklären - vielmehr werde ich den Inhalt des zusätzlichen Validators etwas genauer unter die Lupe nehmen.

Ein zusätzlicher Validator

var pattern = '^(?=.*\\d)(?=.*[A-Z])(?=.*[!@#\\$%\\^&\\*()_\\+\\-={}\\[\\]\\\\:;"'+"'"+'<>,./]).{8,20}$';
if (Validation) {
  Validation.addAllThese([
  [
    'validate-password',
    'Your password must contain at least a letter, a number and a specialcharacter. I needs to contain 8-20 characters and cannot be the same as your first or last name',
      {
        pattern: new RegExp(pattern)
      }
    ]
  ])
};

Was haben wir hier vor uns? Im Prinzip nicht viel - ein pattern, das ausgelagert wurde, da die Übergabe in den RegExp-Konstruktor mit den verschiedenen Anführungszeichen nicht zurechtkommt und das stark maskiert wurde, um die Funktion des RegExps zu gewährleisten. Dazu kommt eine Prüfung, ob das Validation-Objekt bereits existiert. Im positiven Falle wird über die addAllThese()-Methode ein weiterer Validator zur Validierung hinzugefügt. Da wir hier validate-password verwenden, wird die bestehende Passwort-Validierung schlicht überschrieben.

Weiterhin übergeben wir einen Text, der im Falle einer fehlgeschlagenen Validierung ausgegeben wird und wir übergeben die Validierungsregel pattern, die unser RegExp enthält.

Was kann validation.js noch?

Mit REFV ist man in der Lage, beliebige Felder in Formularen nach bestimmten Regeln zu validieren. Hier ein kleiner Auszug aus der Github-Seite von REFV:

Validation.add('class-name', 'Error message text', {
     pattern : new RegExp("^[a-zA-Z]+$","gi"), // only letter allowed
     minLength : 6, // value must be at least 6 characters
     maxLength : 13, // value must be no longer than 13 characters
     min : 5, // value is not less than this number
     max : 100, // value is not more than this number
     notOneOf : ['password', 'PASSWORD'], // value does not equal anything in this array
     oneOf : ['fish','chicken','beef'], // value must equal one of the values in this array
     is :  '5', // value is equal to this string
     isNot : 'turnip', //value is not equal to this string
     equalToField : 'password', // value is equal to the form element with this ID
     notEqualToField : 'username', // value is not equal to the form element with this ID
     include : ['validate-alphanum'] // also tests each validator included in this array of validator keys (there are no sanity checks so beware infinite loops!)
});

Hier sind die verschiedenen Parameter, die man zum Validieren verwenden kann einmal kurz erklärt. Um einen ganz eigenen Validator zu erstellen und zu verwenden, benötigt man ein

-Element auf der Seite, auf der auch validation.js eingebunden ist. Wenn man die Form-ID in den Validation()-Konstruktor gibt, hängt REFV  sich per Observer auf den im Formular verwendeten Submit-Button. Um die Felder vor dem Abschicken zu validieren, müssen sie mit CSS-Klassen versehen werden, die aussagen, welcher Validator verwendet werden soll, zum Beispiel validate-passwordSolange per add() oder addAllThese() ein Validator mit dem entsprechenden Namen an das Validation-Objekt gehängt worden ist, wird das entsprechende Feld mit dem entsprechenden Validator geprüft.

Diese Validatoren können entweder nach Namen und Fehlermeldung als drittes Argument eine anonyme Funktion enthalten, die die Validierung vornimmt, oder man kann eine Liste von Parametern nach obigem Beispiel anhängen, um auf bereits bestehende Mechanismen zur Validierung zurückzugreifen. Beim Verwenden einer anonymen Funktion muss darauf geachtet werden, dass diese natürlich true oder false zurück liefert. ;)

Fazit

Really Easy Field Validation ist ein mächtiges Werkzeug zum Validieren von Formularen und durch seinen Aufbau sehr flexibel. Es ist leicht, bestehende Validierungen zu überschreiben und neue hinzuzufügen. Durch ausgefeilte Validierungen ist es zum Beispiel nicht nur möglich, Richtlinien für Zertifizierungen einzuhalten, sondern unter anderem auch Spam-Anmeldungen im Kundenbereich zu reduzieren. Der Großteil solcher Bots kann bei entsprechenden Maßnahmen, wie Passwort-Mustern oder Nutzernamen-Mustern nicht mithalten.

Davon abgesehen ist es auch möglich, validation.js auf der EPA (Einzelproduktansicht) zu verwenden, um beispielsweise zulässige Werte für Freifeld-Optionen zu gewährleisten oder ähnliches. Alles in Allem ist die validation.js ein schönes kleines Tool innerhalb von Magento.



Ein Beitrag von Peter Ukena
Peter's avatar

Peter Ukena hat im April 2012 mit Magento angefangen, arbeitet bei der Firma Hucke Media aus Oldenburg und ist seit Ende 2012 zertifizierter Magento-Entwickler. In seiner Freizeit liest er Tech-Blogs, vertreibt sich die Zeit im IRC und kümmert sich mit kurzen Schulungen um seine Kollegen. Ohne seine Mütze findet man ihn kaum - auch mit kurzen Haaren nicht.

Alle Beiträge von Peter

Kommentare
Mathis am

Moin, ich denke mal so meinte es Rokko ^^ mit dem Rewrite, im Kern Ändern sollte man nie nie gar nie ^^

Validierung durch JS ist in meinen Augen wichtig, da schon über 90 der möglich Fehler am Client abgefangen werden. Und somit etwas Performance spart.. und auch im Mobilen Zeitalter die Seite am Handy mit 2G oder langsamer nicht neu geladen werden muss ;-)

Peter Ukena am

Hey Rokko,

danke für den Kommentar. Das mit der Mütze liegt schlicht daran, das ich kein Foto mit der Mütze hatte - das kommt aber sicher noch. ;)

Zu deinem Kommentar: Klar - recht hast du - serverseitige Validierung ist genauso nötig, wie clientseitige Validierung. Es ging hier aber nicht unbedingt darum, wie man Magento dazu bringt durch und durch andere Passwörter zu fordern, sondern vielmehr um eben validation.js, die sich nur auf dem Client abspielt. Es geht ja auch nicht nur um Passwörter - man kann mit validation.js jedes beliebige Magento-Formular validieren lassen - Nutzernamen, E-Mails (wobei es da nicht viel zu machen gibt ;) ). Man kann aber auch z.B. Freitextfelder auf Artikelseiten gegen bestimmte Regeln validieren lassen und damit schon im Vorfeld gültige (im Rahmen des Geschäftsprozesses) Anfragen an Magento schicken.

Klar - für Passwortsicherheit reicht es nicht aus, die Validierung nur im Frontend zu machen. Danke auch für den schönen Tip mit dem Password-Model. Aber wieso das Backend-Model ändern, wenn man per Rewrite über config-XML sein eigenes Backendmodel nehmen kann, ohne das Attribut anzufassen? :)

Ich wünsche ebenfalls eine schöne Weihnachtszeit!

Peter

Rokko am

Hallo Peter,

danke erstmal für einen interessanten Artikel, der Magento-Backend-Coder mal ein wenig weg von ihren Observern, Blocks und Models bringt, und sie in das Javascript-Thema einführt, welches leider oft vernachlässigt wird.

Deine Code-Vorschläge sind schicke Beispiele dafür, wie man die Validierung von Magento ohne hartes Eingreifen modifiziert.

Da JavaScript als klientseitig ausgeführter Code leicht zu umgehen und zu modifizieren ist, benötigt man stets noch eine serverseitige Validierung. Bei Magento ist das schick gemacht - Attribute werden vor dem Speichern (und nach dem Laden) durch ein Backend-Model konvertiert. An dieser Stelle findet in Magento die Password-Validierung statt, genau ist es

Mage_Customer_Model_Customer_Attribute_Backend_Password::beforeSave().

Das heißt, durch Überschreiben der Methode dieser Klasse bekommen wir die Validierung auch auf Server-Seite hin. Vorbildlicher und modularer (aber leider schlechter zu debuggen) wäre es natürlich, durch ein Setup-Script das Backend-Model des Passwortes in der eav_attribute zu verändern.

Eine Frage bleibt noch: Warum ist auf deinem Profilbild keine Mütze abgebildet?! ;)

Schöne Weihnachtszeit noch! Rokko

Dein Kommentar