CSV file upload with ZIP containers, jQuery, Ajax and PHP 5.4 progress tracking – I

This article series is written in support for French colleagues in a PHP collaboration project and therefore in English. I want to describe some basic elements of an

Ajax controlled file upload process between

  • a browser based User Interface (HTML4/5, Javascript, jQuery)
  • and some PHP/MySQL application programs on a LAMP server.

Our customer’s project depends on a periodic transfer of up to 40 different CSV files with a lot of input data (around 0.5 GByte) to a database server. A requirement of our customer was that the data transfer should be performed with a ZIP file as a container for the individual CSV data files. After the transfer the contents of the individual CSV files should be imported into specific tables of a database.

As our whole interface of the web application is Ajax based, we decided to control all transfers via jQuery’s Ajax API. Meanwhile, there are jQuery Plugins available for this type of task. However, we wanted to fully control all important phases of the file transfer and the data import – both on the client (browser) as well as on the server. This meant that we needed to program all basic steps during an Ajax communication cycle between the browser client and the LAMP server by ourselves. In addition we needed to guarantee some error control.

Personally, I found it a bit astonishing that such a seemingly simple task lead me to some relatively intricate obstacles to overcome. Although most of the necessary ingredients are documented on the Internet, the documentation is sparse and distributed. My objective with this article series is to provide a coherent picture of process design aspects, some coding tricks and also limitations of such a process. This may be useful also for other developers having to solve similar problems. However, if you want to read about a most simple and problem free approach to file upload tasks with Ajax you are probably looking at the wrong article.

Objectives and Assumptions

  • We want to upload several CSV-files (up to 40), whose contents shall be transferred to specific database tables.
  • These files shall be sent to the server in one ZIP file. Reasons for using a ZIP-container file: compression; limitations of the HTML4 file upload API.
  • As the Zip-container may get relatively large we want to see and control the transfer progress over the Internet by some means of PHP 5.4 – as far as possible today.
  • The server shall extract the files from the ZIP and build up a “pipeline” of these files for a subsequent database import of their contents.
  • The data import into database tables shall be done by a sequence of Ajax controlled PHP jobs. Reason: Intermediate information transfer to the client with the option to stop further processing.
  • The server shall decide by some naming conventions what to do with each file.
  • All steps shall be Ajax controlled – a relatively continuous flow of information between client and server has to be established.
  • For the sake of simplicity each Ajax answer of the server at the end of each controlled Ajax transaction cycle shall be encoded in form of a JSON object. (So, if you want to be particularly precise: we use Ajaj instead of Ajax.)

Wording used in this article series

  • JS, jQuery, Ajax:JS below stands for Javascript (on the
    client side). We furthermore use jQuery and its Ajax interface functionality. We expect JSON responses from the server. Although not completely correct we nevertheless use Ajax and Ajaj as synonyms in the articles of this series.
  • Upload: By “upload” we normally mean the whole process. It comprises a “file transfer process” from the Web client PC to the server and subsequent “database import processes”. However, sometimes and for reasons of simplicity we also use the expression “file upload” in a restricted sense – namely for the file transfer to the server, only. It should become clear from the context what we mean.
  • Main PHP program/job:
    The PHP program receiving and working with the transferred Zip-container file and its contents is called “main PHP program” or “main PHP job”. It has to be distinguished from “polling jobs” (see below).
  • Polling jobs: A sequence of additional PHP “polling jobs” may be triggered by the client. This is done in form of a time loop with a short period. A “polling job” on the LAMP server reads some status information of a previously started and still running “Main PHP job” (as e.g. the file transfer job or long lasting database import jobs). The status information of the running main job is fetched from a common data source as the $_SESSION or a database table accessible to both the status writing “main PHP job” and the status reading “polling job”. Each short timed “polling job” fulfills its own complete Ajax transaction cycle. The evaluation of the Ajax response triggers the next polling job if the main PHP job is still running. We come back to the concept of “Ajax driven polling jobs” later on.
  • CtrlOs: Each user interaction area of a web page – e.g. a HTML FORM in a DIV container – shall be completely controlled by a so called JS “Control object” [CtrlO]. A CtrlO encapsulates all reactions of the UI to events in well defined prototype methods. A CtrlO uses jQuery’s proxy mechanism to register events and delegate event handling to defined CtrlO methods. CtrlO methods furthermore control the Ajax communication with the server.
  • Phases: “Phases” describe a full cycle of defined Ajax interaction between client and server. An example of such a full cycle would be:

    HTML Form => Ajax Setup via JS CtrlO method => Submit via JS CtrlO method => POST/FILE data transfer => Server action (PHP) => JSON object as Ajax response => Client analysis of the JSON object via CtrlO method for the Ajax response

  • Client: The client is in our case typically a browser (Firefox) with active JS and jQuery. We do not care about specific requirements of MS IE browsers in this article series; but we assume that at least MS IE browsers > 10 should work.
  • Pipeline: The ordered sequence by which the files of the transferred ZIP container are imported into their related database.

Relevant phases

To get a more detailed overview over what is to be done we distinguish the following main phases and steps (I omit error handling in this overview which may occur at every step):

Phase I – file transfer, progress control and Zip extraction

Step I.1 – Client: Use a HTML form to choose a ZIP file (<input type=”file”>) and use methods of a specifically designed JS
Control object [CtrlO] to control subsequent actions on the client. Add parameter data (hidden input fields) and prepare an Ajax transaction for the file upload (=transfer) process.

Step I.2 – Client: Start the transfer the ZIP file over the Internet to the server. Submit a special parameter in addition to the file to trigger the provision of transfer progress information on the server. Prepare and start the Ajax communication and the data transfer by a CtrlO method.

Step I.3 – Server: Initialize the progress measurement and provide progress data in the $_SESSION array.

Step I.4 – Client/Server: Initiate a sequence of Ajax polling jobs via a JS time loop for reading the progress information on the server. Handle the Ajax response of each polling job in separate defined methods of a special CtrlO. React to error situations and stop the polling job time loop in case of errors or when the file transfer has finalized.

Step I.5 – Server: Extract, expand and save the CSV files from the Zip-container into a special upload folder on the server. This is done by using standard methods of the PHP ZIP class. Define/Suggest a sequence of imports of the data contents of the different files into file specific database tables. This defined sequence may be controlled via an array (“DB Import Control array” = DBIC-array ) which is kept and updated in the $_SESSION array on the server AND which is also sent back via a JSON object to the client.

Step I.6 – Server: Prepare and send an Ajax response in form of a JSON object to the client with affirmation messages about which CSV files have been received, the name of the files and the order in which they shall be processed. Include error messages and system messages if necessary. The JSON object shall contain the “DBIC”-array.

Step I.7 – Client: Analyze the Ajax response. Display success and error information. Display the number and name of files to be processed afterwards. Stop the time loop for polling jobs.

Phase II – Database import of a file in the pipeline

Step II.1 – Client: Prepare and start a new Ajax job with some parameters. The PHP target program of this job shall import the data of one of the already transferred CSV files. Among other things it should be defined, which file shall be processed (= imported into its associated database table) next. This parameter can follow the suggested order of the array which came from the server at the end of Phase I. All parameters can be set up in a separate (hidden) form with hidden input fields. Submit the Ajax job.

Step II.2 – Server: Start the database import on the server with a flexible PHP program. For small and medium sized files (up to approx. below 500000 lines) do it line by line by appropriate special PHP standard methods for handling CSV files. Check the data of each line where reasonable. Gather at least 20 lines in one INSERT statement to accelerate the import process. Write intermediate progress information into a $_SESSION array or a special database table. (This status information may be read by “polling jobs” started on the client.)
For huge files you may extend the import methods later on by using the special MySQL
command “LOAD DATA INFILE”.

Step II.3 – Client: Launch a sequence of status information polling jobs via a time loop. Handle the return information of each job in separate methods.

Step II.3 – Server: After a successful import of a defined file remove the file from its upload directory (delete it or move it somewhere else, e.g. in a history directory for uploads). Update you Control Array for the sequence of uploads with the following info: Which of the original files have been loaded? Which had errors? Which are still unprocessed? Prepare a JSON object for an Ajax respond (including the upload Control Array). Send it back to the client.

Step II.4 – Client: Analyze the server’s response. Stop any polling jobs issued after the previous submit. Continue with displaying information of the success of the database import of the handled file. Determine the next file to load. Continue with the elements of Step 5 described above.

Phases III + n – Client/Server – Loop:

Cycle through a sequence of Steps described under II.1 to II.4 for further phases until all files are processed or an error has occurred.

Enough for today. In the next article

CSV file upload with Zip containers, jQuery, Ajax and PHP 5.4 progress tracking – II

we shall cover some major elements of Phase I.

Geschwindigkeit/Übertragungsrate eines Netzwerkinterfaces unter Linux reduzieren

Im Rahmen aktueller Arbeiten an Ajax getriebenen Dateiuploads tauchte das Problem auf, mal kurzfristig die Geschwindigkeit einer Netzwerkverbindung drosseln zu müssen, um im lokalen Netz einer länger andauernden Dateitransfer zwischen einem Browser und einem Server zu simulieren.

Aus alten Zeiten hatte ich Werkzeuge wie “wondershaper” oder “trickle” im Kopf. Siehe etwa
http://www.ubuntugeek.com/use-bandwidth-shapers-wondershaper-or-trickle-to-limit-internet-connection-speed.html
http://askubuntu.com/questions/20872/how-do-i-limit-internet-bandwidth
http://unix.stackexchange.com/questions/83888/limit-outgoing-bandwidth-on-an-specific-interface
Diese Tools sind aber sehr alt. Entsprechende Pakete für “trickle” findet man für aktuelle Opensuse Versionen nicht mehr in den Standard-Repositories.

Eine einfach schnelle Lösung für Ethernet-Schnittstellen bietet das CLI Werkzeug “ethtool”, das zum Standardumfang der meisten Distributionen gehört. “ethtool” ist ein mächtiges Werkzeug zur Analyse und zur Konfiguration/Manipulation von Schnittstellen. Es lohnt sich, sich damit ein wenig zu beschäftigen. Zu meiner Schande muss ich gestehen, dass ich dies bislang eher versäumt habe.

Für unseren Anwendungszweck ist die Syntax aber sehr einfach. Heißt unser Ethernet Device etwa “enp8s0”, so erhalten wir einen Überblick über technische Daten der Schnittstelle mit :

mytux:~ # ethtool enp8s0
Settings for enp8s0:
        Supported ports: [ TP MII ]
        Supported link modes:   10baseT/Half 10baseT/Full 
                                100baseT/Half 100baseT/Full 
                                1000baseT/Half 1000baseT/Full 
        Supported pause frame use: No
        Supports auto-negotiation: Yes
        Advertised link modes:  10baseT/Half 10baseT/Full 
                                100baseT/Half 100baseT/Full 
                                1000baseT/Half 1000baseT/Full 
        Advertised pause frame use: Symmetric Receive-only
        Advertised auto-negotiation: Yes
        Link partner advertised link modes:  10baseT/Half 10baseT/Full 
                                             100baseT/Half 100baseT/Full 
                                             1000baseT/Full 
        Link partner advertised pause frame use: Symmetric Receive-only
        Link partner advertised auto-negotiation: Yes
        Speed: 1000Mb/s
        Duplex: Full
        Port: MII
        PHYAD: 0
        Transceiver: internal
        Auto-negotiation: on
        Supports Wake-on: pumbg
        Wake-on: g
        Current message level: 0x00000033 (51)
                               drv probe ifdown ifup
        Link detected: yes

Welche Netzwerkschnittstellen auf dem eigenen System verfügbar sind, ermittelt man natürlich mit
“ip link show” oder “ifconfig”:

mytux:~ # ip link show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default 
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: enp8s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
    link/ether xx:xx:xx:xx:xx:xx brd ff:ff:ff:ff:ff:ff
3: enp9s0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether yy:yy:yy:yy:yy:yy brd ff:ff:ff:ff:ff:ff
4: vmnet1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 
1500 qdisc pfifo_fast state UNKNOWN mode DEFAULT group default qlen 1000
    link/ether nn:nn:nn:nn:nn:nn brd ff:ff:ff:ff:ff:ff
5: vmnet8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UNKNOWN mode DEFAULT group default qlen 1000
    link/ether mm:mm:mm:mm:mm:mm brd ff:ff:ff:ff:ff:ff

Die generelle Syntax zur Änderung der Geschwindigkeit mit ethtool ist:

ethtool -s DEVICE speed [SPEED] duplex [DUPLEX]

DEVICE ist durch den Schnittstellennamen, den man über ifconfig ermitteln kann, zu ersetzen. Welche SPEED Werte angegeben werden können, zeigt der Output von “ethtool DEVICE”; s. das Beispiel oben.

Will ich also die Übertragungsrate meiner Netzwerkschnittstelle temporär auf mögliche 10Mb/s reduzieren, so hilft:

mytux:~ # ethtool -s enp8s0 speed 10 duplex full

Und tatsächlich:

mytux:~ # ethtool enp8s0
Settings for enp8s0:
....    
	Link partner advertised auto-negotiation: Yes
        Speed: 10Mb/s
        Duplex: Full
....

Zurücksetzen erfolgt mit

mytux:~ # ethtool -s enp8s0 speed 1000 duplex full

Autonegotiation für weiterreichende Experimente, bei denen man Verbindungskabel abzieht/ansteckt, stoppt man übrigens mit

ethtool -s DEVICE autoneg off

Der Nachteil von “ethtool” gegenüber dem alten “trickle” ist übrigens, dass “trickle” durch Manipulationen im Userspace die Transfergeschwindigkeit für eine bestimmte Anwendung drosseln kann. Das geht mit ethtool nicht.

Eclipse PDT – Code Assist in PHP 5.4 Traits

Traits sind eine feine Sache, wenn man horizontales Design in PHP Projekten angemessen unterstützen will.
Siehe z.B.: http://www.kingcrunch.de/blog/2011/08/01/php5-4-traits-aka-horizontal-reuse/
Ich setze Traits z.Z. selbst verstärkt in Kundenprojekten ein. Ein kleines praktisches Problemchen, über das ich in Eclipse PDT dabei gestolpert bin, ist die Frage des Code Assists bzw. der Code Completion bei der Code-Erstellung innerhalb von Methoden (Funktionsblöcken) eines Traits.

In den Code-Blöcken der Methoden eines Traits kommt ja oft der $this-Operator mit Referenzen auf Methoden, Variablen und ggf. weitere (z.B. injizierte) Objekte der Zielobjekte bzw. Zielklassen des Traits zum Einsatz. Die Zielklassen eines Traits – also die Klassen, in die der Trait eingebunden und die Trait-Funktionen genutzt werden sollen – beinhalten ja typischerweise bereits Referenzen auf eigene Methoden und ggf. auch weitere Objekte (mit zugehörigen Klassen-Variablen und Methoden). Diese referenzierten Methoden und auch Objekte müssen im Trait u.U. angesprochen werden.

Bei der entwicklungstechnischen Bearbeitung der Zielklassen selbst unterstützt einen PDT umfangreich mit Code Assisting auch für weitere referenzierte Objekte und Klassen, wenn

  • diejenigen Member-Variablen, denen die intern referenzierten Objekte zugeordnet werden, z.B. per “phpDocumentor Tag”-Anweisung mit einem Hint hinsichtlich der Klassenzugehörigkeit versehen wurden
  • und/oder innerhalb der Methoden-Codes ein entsprechendes Type Hinting vorgenommen wurde.

Siehe hierzu:
PHP Type Hinting with Eclipse
PHP Code Content Assists und Inline Type Hinting in Eclipse

Nun möchte man gerne bei der Trait-Entwicklung

  • für die Methoden und Variablen der Zielklassen des Traits selbst
  • wie auch für Objekte und deren Klassen, die innerhalb der Zielklasse referenziert werden,

Code Assisting erhalten, wenn man diese in einer Trait-Methode ansprechen und nutzen will.

Natürlich kann die PDT-Engine bei der Bearbeitung eines Traits aber nicht wissen, für welche Ziel-Klassen das Trait zum Einsatz kommen wird. Mit welchem Klassentypus (einer Vererbungshierarchie) der $this-Operator innerhalb des Traits assoziiert sein wird, ist daher ohne weitere Hilfe unklar. Damit hängen auch alle über $this referenzierten internen Objekte in der Luft. Code Assist innerhalb eines Traits beschränkt sich daher ohne weiteres Zutun des Entwicklers nur auf genau die Variablen und Funktionen/Methoden, die im Trait selbst definiert wurden.

In dem Falle, dass die Ziel-Klassen des Traits alle von einer (gemeinsamen) Klasse abgeleitet wurden, kann man aber mehr erreichen.

Diese Situation entspricht z.B. der, dass man für bestimmte Objekt-Typen über eine Vererbungshierarchie einen Satz von Funktionalitäten bereitgestellt hat. Nun sollen entsprechende Objekte in einer unterschiedlichen Gruppen von Applikationen zum Einsatz kommen, in denen die Basis-Funktionalitäten in gruppen- und applikationsspezifischer Weise überschrieben und ergänzt werden sollen. Diese Änderungen/Ergänzungen seien applikationsspezifisch und nicht strukturell bedingt und mögen daher keinen Grund für eine Erweiterung der Klassenhierarchie selbst darstellen.
Dann kann man in PHP sein Ziel auf breiter Front pro Gruppe durch Integration von gruppenspezifischen Traits erreichen.

Beispiel: Eine Veererbungshierarchie stelle ein allgemeines Spektrum an Funktionalitäten für Template-Control-Objekte zur Verfügung. In unserem zu realisierenden Anwendungsspektrum sollen diese Funktionalitäten für definierte
Applikationsgruppen spezifisch – innerhalb einer Applikatonsgruppe jedoch immer in gleicher Weise – kombiniert werden. Traits lösen dieses Problem auf einfache und elegante Weise.

Innerhalb des Traits möchte man nun Code-Assisting für die Variablen der gemeinsamen Basisklassen erhalten. Nennen wir die potentiellen Zielklassen mal “Class_CTRL_1”, “Class_CTRL_2”, … und gehen wir davon aus, dass alle diese Klassen von einer gemeinsamen Parent-Klasse “Class_Basis_CTRL” abgeleitet sein sollen.

Der kleine aber wirkungsvolle Trick, um volles Code Assist zu bekommen, besteht nun darin, am Kopf einer Trait-Methode $this auf eine interne Variable abzubilden und dabei ein Typ-Hinting einzusetzen:

/* @var $myself Class_Basis_CTRL */
$myself = $this;

Danach arbeitet man in der Entwicklung der Trait-Methoden-Codes anstelle von $this mit $myself weiter und erhält dadurch kompletten Zugriff auf alle Variablen und Methoden von “Class_Basis_Ctrl” im Rahmen des PDT Code Assists. Und weiter auch auf referenzierte Objektklassen, wenn die für die zugehörigen Variablen in der Zielklasse bereits Type Hinting eingesetzt wurde. Das macht wirklich Spaß und Laune …

Viel Spaß künftig bei der effizienten Entwicklung von Traits unter PHP5.4 mit Eclipse !

Kmail, GnuPG, Thunderbird, enigmail und kryptierte HTML-Mails zwischen Linux und Windows Usern

Man kann sich nicht immer aussuchen, mit wem man in Projekten wie kommuniziert. So bin ich als Linuxer natürlich oft mit Kunden konfrontiert, die ein MS Betriebssystem nutzen. Einige dieser Kunden setzen in der Kommunikation mit mir inzwischen vernünftigerweise folgene Mittel ein:

  • Sie stellen entweder kryptierte Verbindungen zu speziellen ihrer Mail-Server zur Verfügung
  • oder aber sie verwenden die Kombination Thunderbird/GnuPGP/enigmail, um Mails zu verschlüsseln und an mich zu versenden, in denen schützenswerte geschäftsrelevante Informationen hinterlegt sind. Hierzu haben wir unsere Public OpenPGP Keys ausgetauscht.

Generell hat die Bereitschaft von Kunden, Mails (Ende zu Ende) zu verschlüsseln, seit den publizierten Ereignissen im IT-Security-Umfeld der letzten zwei Jahre zugenommen.

Manchmal taucht nun das Thema auf, dass Kunden in der Mail Dinge farblich oder fett markieren wollen. Das sind sie aus der firmeninternen Kommunikation so gewohnt. Damit steht dann der Wunsch nach etwas auf der Tagesordnung, das eine Quelle von viel Unheil darstellt – nämlich der Wunsch nach HTML-formatierten Mails. Aus Security-Perspektive stellt das etwas dar, was man aus meiner Sicht unbedingt vermeiden sollte. Formatierte Information gehört in Anhänge, nicht in den Body einer Mail. Aber ist dieser Anspruch praxisnah und vermittelbar? Mein Erfahrung ist: Nicht jeder Kunden kann und will mit dieser Einschränkung leben und arbeiten – auch bei aller vorhandener Bereitschaft zur Verschlüsselung nicht.

Potentielles Problem unter Kmail beim Öffnen von HTML-Mails, die mit Thunderbird/enigmail kryptiert wurden

Will der Kunde unbedingt HTML-Mails austauschen, so ergibt sich u.U. das Problem,

  • dass der Kunde (unter MS Win 7) mit Hilfe von Thunderbird/enigmil zwar eine von mir unter Linux mit Hilfe von Kmail erstellte und mit GnuPG/GPG kryptierte HTML Mail empfangen und ansehen kann,
  • aber ich selbst eine unter Thunderbird verfasste, mit “enigmail” kryptierte HTML Mail nur in Plain Text Form erhalte und der HTML-Anhang der Mail beim Öffnen nur krypierte Anweisungen enthält.

Der Grund liegt in einer speziellen unter Thunderbird/enigmail standardmäßig eingestellten Variante der Verschlüsselung – nämlich “Inline PGP”. Siehe hierzu:
http://de.wikipedia.org/ wiki/ PGP/ INLINE
https://www.enigmail.net/ forum/ viewtopic.php? f=3&t=134

Ein Grund für den standardmäßigen Einsatz von “Inline PGP” ist u.a. der, dass etliche (u.a. MS-lastige) Mail Clients mit der normierten Verschlüsselungsvariante “PGP/Mime” nicht richtig umgehen können. Siehe z.B.:
http://www.phildev.net/ pgp/ pgp_clear_vs_mime.html

Leider führt “Inline PGP” dazu, dass HTML Mails im Rahmen der Verschlüsselung nicht korrekt als Attachment-Streams kryptiert werden. Letzteres zieht bei meinem Kunden dann konsistenterweise Warnungen beim Versuch der Verschlüsselung einer erstellten HTML-Mail nach sich – nämlich dass vorgenommene Formatierungen beim Verschlüsseln und Signieren verloren gehen werden.

Gibt es einen Ausweg? Zumindest im Prinzip: ja. Man muss “enigmail” so einstellen, dass es den definierten Standard “PGP/MIME” zur Kryptierung anstelle von Inline PGP verwendet. Dann ist für eine standardkonforme Verschlüsselung von Mail-Attachments und damit – bei Wahl einer entsprechenden Versandart – auch für eine ordnungsgemäße Behandlung von HTML-Mails gesorgt.

Linux Mail Clients, die GnuPG/GPG einbinden, können i.d.R. mit Mails und Attachments umgehen, die gemäß der “PGP/MIME”-Regeln
kryptiert wurden. Siehe zu “PGP/MIME” etwa :
http://de.wikipedia.org/ wiki/ PGP/ MIME
http://de.wikipedia.org/ wiki/ OpenPGP

Dies trifft natürlich auch auf Kmail zu. So ist also der Einsatz von “PGP/Mime” durch den Kunden (mit MS Win, Thunderbird) zumindest in der Kommunikation mit mir kein Problem. Die entsprechenden Einstellungen können unter “Thunderbird/enigmail” zudem spezifisch für einen Mail Account vorgenommen werden. Hat der Kunde die Möglichkeit, einen spezifischen Mail-Account für die Kommunikation mit mir zu nutzen, so ist man als Linux-Kmail-Nutzer aus dem Schneider – nicht jedoch zwangsläufig als Security-Berater; s.hierzu einen speziellen Absatz weiter unten.

Erforderliche Einstellungen unter Thunderbird/enigmail

Zwei Schritte sind erforderlich, damit mit Thunderbird erstellte und mittels “enigmail” kryptierte HTML Mails auf einem Linux-System mit Kmail-Client nach Dekryptierung als HTML Mails geöffent werden können und danach alle vom Absender vorgenommenen Formatierungen auch angezeigt werden:

  • Schritt 1: Aktivierung von “PGP/MIME”
    Das entsprechende mit Häkchen zu versehende Feld findet man unter Thunderbird für Windows unter
    Extras >> Konten-Einstellungen >> dein relevanter Mail Account >> OpenPGP-Sicherheit >> PGP/MIME standardmäßig verwenden.
  • Schritt 2: Versand im Format “Reintext und HTML”
    Vor dem Versenden der E-Mail aus dem E-Mail-Erstellungsdialog von Thunderbird muss der Anwender explizit die Einstellung “Reintext und HTML” unter dem Menüpunkt “Optionen >> E-Mail Format” vornehmen.

Letzteres könnte man zwar auch als globale bzw. empfängerspezifische Option festlegen. Ich persönlich würde das aber nicht tun, sondern als Standard “Reintext” wählen. Es gilt ja nach wie vor die Maxime, dass HTML-Mails in der Mail-Kommunikation mit mir nur im Ausnahmefall zum Zuge kommen sollen.

Eine ausführlichere Beschreibung zu den vorzunehmenden Einstellungen von Thunderbird findet man z.B. unter:
https://micahflee.com/ 2013/ 09/ html-email-attachments-and-flowed-text-in-enigmail/

Sicherheitsaspekte

Nun ein paar Worte zu einigen potentiellen und interessanten Sicherheitsproblem von “enigmail” im Zusammenhang mit PGP/MIME, nämlich u.a. dem atomatischen Öffnen und Dekryptieren von Mails im Hintergrund. Siehe hierzu im Besonderen den Kommentar von Alan Eliasen zu dem eben zitierten Artikel
https://micahflee.com/ 2013/09/ html-email-attachments-and-flowed-text-in-enigmail/
und weitere entsprechende Hinweise unter
https://futureboy.us/ pgp.html
Letzterer Artikel enthält übrigens auch grundsätzliche und interessante Hinweise zum Einsatz von OpenPGP/GnuPG.

Besonders interessant und lehrreich im Zusammenhang mit “enigmail” ist die Diskussion zu dem besonders kritisierten Punkt im Zshg. mit PGP/MIME, der den enigmail-Entwicklern als Bug gemeldet und danach heftig diskutiert wurde. Siehe hierzu:
http://sourceforge.net/ p/ enigmail/ bugs/226/
und die dortigen Kommentare.

Was ist nun meine Meinung zu deser Debatte ? Grob Folgendes :

Ich verstehe die Kritik und die Bedenken von Hrn. Eliasen gut; inbesondere den von ihm geäußerte Kritik an der durch Thunderbird (mit Hilfe von enigmail) automatisch in Gang gesetzten Dekryptierung von PGP/MIME-verschlüsselten Mails samt Anhängen im
Hintergund. Auch die grundsätzlich in Betracht gezogenen Angriffsmethoden auf akustischer Ebene waren bis zu Gegenmaßnahmen auf der GnuPG-Seite relevante Punkte.

Aber: 100%-ige Sicherheit gibt es nicht – und in der Praxis werden nach Abwägung von Risiken immer wieder Kompromisse zu schließen sein. Dabei muss auch die sichere und bequeme Handhabung einer SW durch den Anwender einbezogen werden. Das ist hier durchaus relevant.

Nehmen wir mal an, nur autorisierte User haben Zugang zum PC/Laptop des Kunden: Wenn dann – also im Normalbetrieb – im Hintergrund dekryptierte Mails von einem Angreifer mitgeschnitten werden sollten, dann bestünde bereits ein grundsätzliches, über Thunderbird weit hinausgehendes Problem auf dem attackierten Computer bzw. im umgebenden Netzwerk. Auch akustische Attaken würden ein hohes Maß an krimineller Energie am Standort des empfangenden Computers voraussetzen.

Ferner geht es ja zunächst vor allem darum, dass der Kunde Mails überhaupt verschlüsselt über das Internet transportiert. Man muss ja (leider) schon dankbar sein, wenn man einen Nicht-IT-Fachmann dazu bewegen konnte, die für entsprechende Verschlüsselungsmaßnahmen notwendige Energie aufzuwenden. Bequem und einfach ist das für den Normalverbraucher eher nicht. Als wenig praxistauglich bis realitätsfern muss man gar Eliasen’s Aufruf zu einer manuellen Verschlüsselung des Mail-Bodies durch den Windows-Anwender einstufen.

In einer Hochsicherheitskommunikation ist die “Ende zu Ende”-Verschlüsselung auf dem Transportweg natürlich nur ein Teil der erforderlichen Maßnahmen. Die sichere kryptierte Ablage der Mails auf dem sendenden wie auf dem empfangenden System gehört mit in ein umfassendes Maßnahmenpaket. Aber sobald ein funktionierender Transfer mit einer “Ende zu Ende”-Verschlüsselung etabliert wurde, hat man immerhin einen wichtigen Schritt in Richtung einer verbesserten Sicherheit im Informationsaustausch hinter sich gebracht.

Alles weitere betrifft dann die Sicherheit der Informationsablage und Informationssnutzung auf den sendenden bzw. empfangenden Systemen. U.a. will man ja bei kryptierten Mails eine gewisse Grundsicherheit auch dann noch aufrecht erhalten, wenn ein physikalischer Zugriff (z.B. auf einen gestohlenen oder unbewachten Laptop) durch unautorisierte User erfolgt und ggf. nach Einsatz von Passwort-Crackernein Login durch den ungebetenen Gast gelingt. Hier zieht dann das Argument von Eliasen bzgl. der automatischen Dekryptierung wirklich:

Ohne explizit geforderte Dekryptierung durch einen autorisierten User sollte kein System eine Dekryptierung von Mails in Gang setzen. Der potentielle nicht-autorisierte Angreifer erhielte hier ggf. Zugang zu den geheim zu haltenden Informationen, ohne das Passwort für den privaten Schlüssel überhaupt benutzen zu müssen. Letzteres wäre z.B. dann gegeben, wenn der Angreifer Thunderbird nutzen kann und enigmail das erforderliche Passwort noch aus einem meist stadardmäßif vorkonfigurierten Zwischenspeicher bezieht.

Dieser Bedrohung kann man aber bei Bedarf dadurch begegnen, dass man den Schlüssel mit einem sicheren Passwort versieht und enigmail/GnuPG anweist, das Passwort für den privaten Schlüssel nicht – auch nicht für einen kurzen Zeitraum – zwischenzuspeichern. Bequemer wird der Einsatz von Thunderbird/enigmal dadurch aber nicht. (Steht Sicherheit wirklich über allem, so wird man ferner die Harddisks verschlüsseln, um im Verlustfall grundsätzlich mehr Sicherheit zu haben.)

Ferner möchte ich anmerken, dass die enigmail-Entwickler ja schließlich gerade aufgrund der geführten Debatte (dankenswerterweise) Schritte in Richtung einer besseren und kontrollierteren Handhabung der Dekryptierung vorgenommen haben.

Bleibt das Restrisiko, dass größere mit PGP/Mime verschlüsselte HTML-Anhänge eine Menge an bekannten Textfragmenten wie etwa Tags enthalten. Dies kann gut ausgestatteten Angreifern mindestens theoretisch eine Grundlage für statistik-basierte Dekryptierungsversuche
verschaffen. Sollte dieses Problem wirklich bestehen, dann würde ich darin insgesamt aber eher eine Schwäche des Kryptierungsverfahrens (also von GnuPG) sehen als von “enigmail”.

Habe ich die Wahl zwischen weiter bestehenden Rest-Risiken und einem total unverschlüsselten Email-Verkehr, so ziehe ich – nach entsprechender Unterweisung des Kunden – immer noch den Einsatz einer Verschlüsselung vor.

Abschließend gilt grundsätzlich :

Mit HTML-Mails sind jenseits von Wechselwirkungen mit Verschlüsselungsprogrammen weitere schwerwiegende Risiken verbunden, denen man sich im Rahmen einer sicheren Kommunikation (bei allem gegenseitigen Vertrauen der Kommunikationspartner) erst gar nicht aussetzen sollte. Der Kunde sollte also dahingehend beraten werden, HTML-Mails im Normalfall auch in der Kommunikation mit vertrauenswürdigen Kommunikationspartnern (in diesem Falle u.a. mit mir) zu vermeiden.

Selbst sollte man seinen E-Mail Client so einstellen, dass er HTML-Mails zunächst nur im Plain Text Format öffnet. Im Falle, dass HTML-Formatierungen wirklich eine wichtige Rolle spielen, kann man den PGP/MIME HTML-Anhang immer noch öffnen. Als Paranoiker auch bei vertrauenswürdigen Quellen ggf. zunächst in einem Standard-Editor, um den HTML-Code vor einer Ausführung zu analysieren. 🙂

 

Elipse Luna, JSDT JQuery – Code Assist-/Autocompletion-Problem – reduzierte Liste an jQuery Methoden ?

Wir entwickeln für einen Kunden z.Z. größere PHP und jQuery-lastige Projeke mit dynamischen Ajax basierten Web Interfaces. Unsere IDE ist Eclipse (in der Luna Version inkl. PDT, JSDT, Aptana Plugin). Unser Projekt nimmt dabei Bezug auf ältere Projekte und bindet über Links Verzeichnisse aus diesen Projekten in den Build Pfad des aktuellen Projektes ein.

In den letzten Wochen hat mich ein Problem genervt, dass ich nicht auf Anhieb lösen konnte: Um mit Javascript und jQuery effizient arbeiten zu können, nutzen wir JSDT

JavaScript Development Tools	1.6.100.v201410221502	org.eclipse.wst.jsdt.feature.feature.group	Eclipse Web Tools

und JSDT jQuery

JSDT jQuery Integration 1.7.0	org.eclipselabs.jsdt.jquery_feature.feature.group

um während der Javascript-Entwicklung u.a. auf jQuery-bezogene Code Assist und Autocompletion Hinweise im JSDT Javascript-Editor zugreifen zu können.

Zunm Setup siehe z.B.:
https://code.google.com/ a/ eclipselabs.org/ p/ jsdt-jquery/ wiki/ Installation
oder
http://www.htmlgoodies.com/ html5/ javascript/ add-external-js-libraries-to-eclipse-jsdt-driven-projects.html# fbid=PCl6TfPGIe5
und dort den Abschnitt “Adding a JS Object Model Plugin”.

Ein wichtiger Schritt zum jQuery Code Assisting ist, dass man die gewünschte aktuelle Version der jQuery-Definitions-Bibliothek in sein Projekt einbindet. Dies geschieht – wie in den obigen Artikeln beschrieben – über einen Eclipse Konfigurationsdialog zu den Javascript-Bibliotheken des aktuellen Projektes.

In neu angelegten Projekten mit kombinierten “PHP/JSDT Natures” oder “Faceted Natures” funktionierte das Code Assisting im JSDT eigenen Javascript Editor auch prima. Es wurde z.B. ein komplette Liste aller verfügbarer Methoden des jQuery Objekts angezeigt – je nach geladener Version der jQuery Library.

In meinem eigentlichen Haupt-Projekt mit seinen Verlinkungen in Bereiche anderer Projekte wurde beim Code Assisting dagegen nur eine sehr stark reduzierte Liste von Methoden des “jQuery”-Objekts angezeigt.

Das ist beim Entwickeln total nervig. Ich wich in solchen Fällen auf entsprechende Funktionalitäten des Apatana Plugins und dess JS-Editor aus – obwohl ich den (im Gegensatz zum Aptana HTML-Editor) nicht mag.

Zudem führte ein Rebuild meines Projektes nach einem “Clean” zu Abbrüchen mit (Java-NullPointer-) Fehlern des im Build-Verlaufs ausgeführten JS Validators.

Ich habe zwischenzeitlich mehrere Versuche unternommen, mein Projekt (und auch abhängige Projekte) bzgl. ihrer Natures und Facetten neu aufzubauen. Vergeblich. Die Code-Assist Länge wurde nicht besser. Auch ein Vergleich der Projekt-Einstellungen auf Eclipse-Ebene brachte nichts. Natürlich habe ich auch alle Versionen der geladenen Javascript-Bibliotheken (u.a. der konfigurierten jQuery-Definitionsbibliothek) abgeglichen. Das brachte alles keinen Erfolg.

Interessanterweise kam eine vollständige Liste an jQuery Methoden, wenn man unter den geladenen Javascript Libraries die
ECMA 3 Browser Support Library” im entsprechenden Javascript Konfigurationsdialog des Projektes entfernte. Eine vollständige Liste kam im Javascript Code Assisting auch dann, wenn man die JS-Unterstützung im Eclipse Projekt dadurch deaktivierte, dass man die JSDT Nature des Projektes entfernte: Dann taucht der Javascript-Validator nicht mehr unter den aktiven Validatoren des Projektes auf und wird demnach auch nicht benutzt.

Hieraus ergab sich, dass mein Problem mit dem JS Validator und seiner Prüfung vorhandener JS-Dateien zusammenhängen musste. Das brachte mich heute endlich auf die richtige Spur:

In meinen älteren Projekten gab es Verzeichnisse, in denen ich neben eigenen JS-Dateien etliche alte Versionen der jQuery-Bibliotheks- und Definitions-Dateien hinterlegt hatte. Z.B. jquery-1.4.2.min.js oder noch ältere Varianten.

Unglücklicherweise wurden diese Verzeichnisse durch die Verzeichnis-Verlinkungen Teil des Source- und des Build-Paths des aktuellen Projekts. Die dortigen alten Definitionen wirkten sich offenbar mit Priorität auf den JS-Validator und auch die Code Assist Funktionalität aus. Irgendwie logisch – auch wenn ich die Priorisierung der Validator-Analyse bei mehreren vorhandenen jQuery-Dateien nicht nachvollziehen kann. Dennoch: Mein Fehler ! Verschiedene Bibliotheken, die die Definitionen des jQuery-Objektes unterschiedlich vornehmen, können im Rahmen von Builds und Validierungen nur ins Chaos führen.

Was habe ich gelernt?

Um mit “JSDT jQuery” vernünfig arbeiten zu können, sollte man eine evtl. vorhandene Sammlung alter jQuery-Library-Dateien nicht in den Source und/oder Build Path des laufenden Projekts aufnehmen. Wenn man überhaupt eine jQuery-Definitionsdatei in die eigenen Source Code Verzeichnisse integriert, dann eine, die mit der für das Projekt geladenen Version der jQuery-Bibliothek kompatibel ist.

Seit ich das beherzige, funktionieren das generelle JSDT JS und das JSDT jQuery Code Assisting einwandfrei. Auch die Abstürze beim Clean/Rebuild eines Projektes sind verschwunden.

Viel Spaß weiterhin mit Eclipse und JSDT bei eueren Entwicklungsarbeiten.