Programmierung

Mehrere Datenbanken unter Symfony

In einem Projekt bestand die Notwendigkeit, die applikationsspezifische Datenbank (MariaDB) und eine externen Datenbank (MS-SQL) gleichzeitig zu verwenden. An der Datenbankstruktur war nichts zu drehen, da die MS-SQL Datenbank in anderen Projekten ebenfalls im Produktivbetrieb verwendet wurde. Somit bestand das Problem, zwei Datenbankverbindungen parallel offen zu halten und je nach Entity-Klasse die richtige Datenbank zu verwenden.

Wie man sich unter Linux mit einer MS-SQL Datenbank verbindet, habe ich bereits im Artikel MS-SQL mit Symfony unter Linux im Detail beschrieben. In diesem Artikel geht es vornehmlich um den gleichzeitigen Betrieb zweier Datenbank und die automatische Auswahl der korrekten Datenbankverbindung.

Zwei Datenbanken parallel betreiben

Hierfür habe ich zur einfacheren Übersicht in den Verzeichnissen src/Entity und src/Repository ein Unterverzeichnis MsSql angelegt, in welche die Klassen der externen Datenbank gelegt werden. Dieser Schritt erhöht lediglich die Übersicht für menschliche Betrachter; Symfony/Doctrine ist das egal.

Somit ergeben sich die Verzeichnisse

Verzeichnis Verwendung
src/Entity Entity-Klassen der MariaDB-Datenbank
src/Entity/MsSql Entity-Klassen der MS-SQL-Datenbank
src/Repository Repository-Klassen der MariaDB-Datenbank
src/Repository/MsSql Repository-Klassen der MS-SQL-Datenbank

Zudem habe ich in der Datei doctrine.yaml zwei Verbindungen und zwei Entity-Manager definiert:

doctrine:
    dbal:
        default_connection:       default
        connections:
            default:
                driver: pdo_mysql
                dbname:           "%env(resolve:DATABASE_DB)%"
                user:             "%env(resolve:DATABASE_USER)%"
                password:         "%env(resolve:DATABASE_PASS)%"
                host:             "%env(resolve:DATABASE_HOST)%"
                port: 3306
                schema_filter: ~^(?!tt[a-z]{4}[0-9]{6})~  # Ignore Mssql tables
            mssql:
                # IMPORTANT: this configuration requires FreeTDS installed!
Weiter lesen

Piep-Show im Vogelhaus

Die heimischen Vögel sind im Frühjahr immer wieder imposant zu beobachten. Schon früh morgens um 5 beginnen sie mit ihrem Gesang (andere nennen es unerträgliches Geplärr) und flattern den ganzen Tag von Busch zu Baum zu Hecke zu Zaun und zurück. Da es bei uns in der Umgebung relativ wenig Nistmöglichkeiten gibt, kam die Idee auf, ein Vogelhaus im Garten anzubringen. Natürlich ein richtiges Maker-Vogelhaus mit Kamera für die Piep-Show. Herzstück des Vogelhauses ist ein ESP32-CAM Modul, das WLAN, eine Kamera im Megapixel-Bereich und einen programmierbaren Mikrocontroller mitbringt.

Mehr»

Javascript, Typescript, Webpack und neues im Web

Während man sich in den letzten Jahren auf Webseiten meist mit JavaScript in einer sehr einfachen Art begnügte, sind in der letzten Zeit unheimlich potente (und meist damit auch komplexe) Erweiterungen erschienen. Beginnend mit dem Angular-Framework, das manche mögen und andere hassen, hat sich die Webseiten-Programmierung immer weiter der klassischen Softwareentwicklung angenähert. Der erste Schritt waren die Module, die beispielsweise via AMD oder RequireJS geladen wurden und eine Kapselung hinsichtlich der Daten und des Programmcodes ermöglichten. Dann kam Webpack, das mit dem Tool „babel“ die Möglichkeit bot, neueste Programmiertechniken bei der Entwicklung zu verwenden und es ähnlich wie bei einem Compiler zu einem kleinsten gemeinsamen Nenner zu „transpilen“. Zuletzt hat die Einführung von Typescript die Möglichkeit einer Statischen Codeanalyse eröffnet, damit Fehler schon zur Entwicklungszeit und nicht erst anhand von Meldungen in der Error-Console aufgedeckt werden können.

Ich werde in der nächsten Zeit zu all diesen Themen ein wenig schreiben und dies mit ganz vielen Codebeispielen ergänzen. Dabei gehe ich wenig bis gar nicht auf Dinge wie HTML5, klassisches JavaScript, Programmier-Basics und Webserver-Konfiguration ein, denn zu diesen Themen gibt es mehr als genug Quellen im Netz. Mir geht es eher darum, wie jemand, der bereits die klassische Webentwicklung kennt, möglichst schnell in diese neue Welt eintauchen kann und sie sich zu Nutze machen kann. Weiter lesen

SQL Injection Attack mit Hilfe der Stadt, Teil 2


Im Dezember 2008 hatte ich unter SQL Injection Attack mit Hilfe der Stadt darüber berichtet, dass ich mit unserem Straßennamen “ Auf’m Diek “ bei einem Internethändler auf nicht unerhebliche Probleme gestoßen bin.

Für diejenigen, die nicht viel mit SQL am Hut haben, will ich mal kurz erläutern, was damals passiert ist: Bei SQL, das ist eine Datenbanksprache, die auf den meisten Webseiten verwendet wird, werden Texte in Hochkommatas eingeschlossen, um zu kennzeichnen, wo der Text anfängt und wo er endet. Außerhalb der Hochkommatas stehen Befehle, was die Datenbank machen soll. Ein typischer Befehl sähe also so aus:

SELECT address FROM customer WHERE name='Carsten';

Soll nun der eigentliche Text selbst ein Hochkomma haben, so muss man es speziell kenntlich machen, der Experte sagt „escapen“. Dies erfolgt bei SQL durch einen vorangestellten Backslash:

SELECT address FROM customer WHERE name='Carsten\'s Name';

Macht man das nicht, passieren mehr oder minder lustige Dinge: Die Datenbank kann nicht mehr unterscheiden, wo der Text endet und der nachfolgende Befehl endet. Randall Munroe von XKCD hat die möglichen Effekte in einem Comic sehr anschaulich beschrieben:

Quelle: XKCD, Oktober 2007

Seitdem meinem vorhergehenden Posting sind fast 7 Jahre vergangen. SQL Injection Angriffe sind inzwischen selbst in der Breiten Öffentlichkeit angekommen und für jeden seriösen Entwickler ist es inzwischen Standard, seine Anwendung auf solche Schwachstellen zu überprüfen. Weiter lesen

Contabo und SPF

Seit wir unseren neuen Server, einen VPS bei Contabo haben, bekommen wir für angenehm wenig Geld relativ viel Leistung. Auf dem VPS betreiben wir auch einen Mailserver, der (basierend auf einem Debian) für verschiedene Domains Mails ausliefert und annimmt.

Die Tage fiel mir auf, dass einige Mails, vornehmlich solche an @gmail.com oder @live.de mit Fehlermeldungen zurückkamen:

empfaenger@gmail.com
SMTP error from remote mail server after end of data:
host gmail-smtp-in.l.google.com [2a00:1450:4013:c01::1b]:
550-5.7.1 [2a02:c200:1:10:3:0:6175:1 12] Our system has detected that this
550-5.7.1 message is likely unsolicited mail. To reduce the amount of spam sent
550-5.7.1 to Gmail, this message has been blocked. Please visit
550-5.7.1 http://support.google.com/mail/bin/answer.py?hl=en&answer=188131 for
550 5.7.1 more information. lj18si16872950wic.58 - gsmtp

In erster Instanz sah es so aus, als würden unsere Mails als SPAM klassifiziert. Die Ursachenforschung begann.

Google verwendet diverse Dienste/Protokolle, um festzustellen, ob es sich bei einer eingehenden Mail um SPAM oder normale Post handelt. Hierzu zählen z.a. DKIM und SPF. Eigentlich sollte unsere Domain SPF unterstützen und einen gültigen Record zurückliefern. Die Domain heißt „ff-holsterhausen.de“, der Mailserver identifiziert sich unter dem Namen „hora.tempus-vivit.net“ und der IP 213.136.68.159.

Die erste Anlaufstelle ist das Linux-Tool dig, mit dem man DNS-Informationen abfragen kann. Eine Abfrage auf die Domain zeigte folgendes:

user@tempus-vivit.net:#
Weiter lesen

FHEM: Zufällige Zeit-Offsets

Möchte man sein Haus automatisieren, stehen einem ein ganzer Zoo von verschiedenen Systemen zur Verfügung: HomeMatic, FS20, EnOcean, Peha, KNX und viele mehr. Leider haben die Steuerzentralen der einzelenen Systeme eins gemeinsam: Sie können nur Komponenten des eigenen Systems ansprechen und lassen sich schlecht erweitern.

Daher hat Rudolf Koenig mit einigen anderen Entwicklern eine universelle Hausautomatisierungszentrale entwickelt: FHEM. Hiermit lassen sich, wenn man entsprechende Gateways auf die jeweiligen Funksysteme hat, beliebige Systeme anbinden.

Möchte man Rollos automatisieren, so bietet die Sunset-Funktion einen einfachen Weg, bei Sonnenuntergang die Rollos herunterzufahren. So sorgt der Befehl


define Zimmer1.Rollo.Herunter at *{sunset(0,"17:00","22:00")} set Zimmer1.Rollo off

dafür, dass das Rollo Kueche.Rollo bei Sonnenuntergang heruntergefahren wird, jedoch nicht vor 17:00 und nicht nach 22:00.

Macht man das für alle Rollos auf diesem Weg, ergibt sich jedoch ein Problem. Das ganze sieht ziemlich automatisiert aus und taugt für keine 5 Pfennig (ähh…Cent) als Anwesenheitssimulation. Man würde schließlich wenn man anwesend ist, auch nicht alle Rollos gleichzeitig herunterfahren können. Praktisch wäre ein zufälliger Offset. FHEM bietet diese Funktion leider nicht von Haus aus, aber man kann sich schnell so eine Funktion selber bauen:

# Zufälligen Offset auf Zeitstamp addieren/subtrahieren
sub
time_random_offset
{
  # Eingangs-Zeitstempel in Variable holen
  my ($timestamp) = shift;

  # Maximalen Zeitoffset (in Sekunden) in Variable speichern
  my ($maxoffset) = shift;

  # Zeitstempel in das interne Format konvertieren: 17:30:09 ==> 17.5025
  # Stunden werden als ganze Zahlen gespeichert, minuten als 1/60 und sekunden als 1/3600
  my ($t) = hms2h($timestamp);

  $t += rand()  * $maxoffset / 3600;

  # Zurück in HH:MM:SS konvertieren.
Weiter lesen

Speicher beim STM32 (Cortex-M3/Cortex-M0) sparen

In der letzten Zeit programmiere ich recht viel mit dem STM32. Dabei handelt es sich um einen Microcontroller mit ARM-v7 Kern (Cortex-M0, Cortex-M3, Cortex-M4), der sich grob im Preisniveau von AVRs bewegt, aber deutlich performanter ist. Seitens des Herstellers (ST Microelectronics) wird eine angenehm nutzbare Firmware-Library (Standard Peripherals Library) mitgeliefert, sodass man eigentlich direkt starten kann. Achsoo, GCC gibts natürlich auch als Compiler: . Das ganze wird dann unter Eclipse programmiert und mit OpenOCD debuggt.

Jetzt aber zum eigentlichen Thema. Wenn man nämlich wie von ST in den Beispielen der Firmware-Library die Peripherie initialisiert, dann sieht das in etwa so aus:

RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC, ENABLE);

GPIO_InitTypeDef gpio;
gpio.GPIO_Mode = GPIO_Mode_OUT;
gpio.GPIO_OType = GPIO_OType_PP;
gpio.GPIO_PuPd = GPIO_PuPd_NOPULL;
gpio.GPIO_Speed = GPIO_Speed_Level_1;
gpio.GPIO_Pin = GPIO_Pin_14 | GPIO_Pin_15;
GPIO_Init(GPIOC, &gpio);

Zum einen ist dieser Code recht unübersichtlich, zum anderen passiert aber hier etwas, was man eigentlich gar nicht möchte. Zuerst wird nämlich auf dem Stack Speicher für die Struktur reserviert, dann im Programm Feld für Feld mit Werten gefüllt und danach an die Init-Funktion übergeben. Im Assembler sieht das übrigens so aus:

  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC, ENABLE);
 800899a:	2380      	movs	r3, #128	; 0x80
 800899c:	031b      	lsls	r3, r3, #12
 800899e:	1c18      	adds	r0, r3, #0
 80089a0:	2101      	movs	r1, #1
 80089a2:	f7fa f919 	bl	8002bd8 <RCC_AHBPeriphClockCmd>

  GPIO_InitTypeDef gpio;
  gpio.GPIO_Mode
Weiter lesen

OwnCloud 8 mit Custom User Backend

Die Einsatzgebiete von OwnCloud sind vielfältig. Man kann seine Kalender synchronisieren, Dateien austauschen oder aber die Arbeit in kleinen Gruppen organisieren. In solchen Fällen hat man häufig schon eine andere Software im Einsatz, sei es ein Wiki, einen Bugtracker oder eine andere Homepage, bei der man sich anmelden muss.

Wünschenswert wäre in diesem Fall, dass man nur einen Benutzernamen und ein Passwort hat, das für alle Dienste gilt. Praktischerweise bietet OwnCloud hier mit Hausmitteln schon eine Lösung, wenn man ein paar Fallstricke beachtet.

Dieses Beispiel geht davon aus, dass bereits eine OwnCloud 7 Installation vorhanden ist und dass als Backend MySQL verwendet wird.

Schritt 1: Vorbereiten der Datenbank

Leider werden bei der Installation von OwnCloud 7 nicht alle Tabellen automatisch angelegt, die für ein Custom User Backend notwendig sind. Daher muss man die Tabelle oc_users_external anlegen:

CREATE TABLE IF NOT EXISTS `oc_users_external` (
    `backend` varchar(128) NOT NULL,
    `uid` varchar(64) NOT NULL,
    `displayname` varchar(64) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

Schritt 2: Erstellen eines eigenen Backends

Im Verzeichnis apps/user_external/lib/ finden sich einige Beispiele (z.B. imap.php), die man für seine eigenen Zwecke umschreiben kann. Ein Minimalbeispiel sieht so aus (Man ersetze MYSITE durch einen eigenen Identifier)

<?php 
class OC_User_MYSITE extends \OCA\user_external\Base{
    private $host;
    public function __construct($host, $secure=false) {
        $this->host=$host;
        parent::__construct('mysite://' .
Weiter lesen

Home-Automation Sniffing

Vor einiger Zeit habe ich mir von ELV für unser Wohnzimmer Funk-Heizkörperthermostate bestellt. Zuerst habe ich die ETH comfort 100 Thermostate zusammen mit der dazugehörigen Funkfernbedienung bestellt.

Leider endeten schon die ersten Tests in einer mittleren Katastrophe. Die Soll-Temperatur lässt sich nämlich an den Thermostaten einstellen und zeitgesteuert programmieren. Diese Prozedur darf man natürlich an jedem Thermostat wiederholen…und das bei jeder Änderung der Vorgaben. Die Fernbedienung war jedoch der absolute Super-GAU. Mit Ihr ließ sich nicht wie erwartet die gewünschte Temperatur einstellen, sondern nur der Offset zu der bereits gewählten Temperatur am Thermostat. Leider konnte man auf der Fernbedienung nicht ablesen, welche Temperatur grade am Thermostat eingestellt war, sodass das ganze zu einer Art „Blinde Kuh“ Spiel mutierte. Damit nicht genug; hatte ein Thermostat die Funkübertragung nicht mitbekommen, das andere aber doch, hatten sie fortan unterschiedliche Sollwerte, die sich mit der Fernbedienung auch nicht mehr in Einklang bringen ließen. Also wurden die Geräte wieder eingetütet und zum Verursacher zurückgeschickt.

Als nächstes habe ich mir dann von ELV die anderen Thermostate des Typs FHT8xx nebst Raumregler und Türkontakt bestellt. Außerdem habe ich noch ein kleines Empfangsmodul RX868-3V dazubestellt.

Die Inbetriebnahme gestaltete sich deutlich einfacher als bei den anderen Geräten, auch wenn eines der gelieferten Thermostate direkt defekt war (µC gestorben). Weiter lesen

SQL Injection Attack mit Hilfe der Stadt

Umzüge bringen ja so einiges mit sich. Unter anderem auch meistens eine neue Adresse. Bei der Planung des Wohngebiets, in das wir nun gezogen sind, hat die Stadt Dorsten jedoch außerordentliche Kreativität an den Tag gelegt und gezeigt, dass Straßennamen nicht nur aus Buchstaben bestehen müssen.

Unsere Straße hat in dieser kreativen Phase den Namen Auf’m Diek bekommen und ja, das mit dem Apostroph ist die offizielle Schreibweise.

Für die ersten lustigen Effekte sorgte der Name bereits, als wir unsere DSL-Leitung bei Versatel bestellen wollten. Dort gab es nämlich ganze 5 Straßen, die in die Endauswahl kamen: Aufm Diek, Auf dem Diek, Auf'm Diek, Auf´m Diek sowie Auf`m Diek. Wir haben uns einfach mal für eine beliebige Variante entschieden und es hat auf Anhieb funktioniert.

Nicht so viel Glück hatten wir gestern, als wir im Internet etwas bestellen wollten. Produkt ausgewählt, ab zur Kasse, Kundenkonto angelegt, Versandadresse eingegeben und dann das:

1064 – You have an error in your SQL syntax; check the manual that
corresponds to your MySQL server version for the right syntax to use near
‚m Diek‘, ‚Dorsten‘, ‚46284‘, 0)‘ at line 2
INSERT INTO customers_credit_reform (score, customers_id, address_valid,
address_valid_code, address_known, address_street_no, address_street_name,
address_town, address_postcode, credit_error) VALUES (42, 91756,
“, ’03‘, ‚0‘, ’19‘, ‚Auf’m Diek‘, ‚Dorsten‘, ‚46284‘, 0)
[XT SQL Error]

BugEine solche Meldung lässt das Herz jedes Softwareentwicklers höher schlagen. Weiter lesen