Ihr Browser versucht gerade eine Seite aus dem sogenannten Internet auszudrucken. Das Internet ist ein weltweites Netzwerk von Computern, das den Menschen ganz neue Möglichkeiten der Kommunikation bietet.

Da Politiker im Regelfall von neuen Dingen nichts verstehen, halten wir es für notwendig, Sie davor zu schätzen. Dies ist im beidseitigen Interesse, da unnötige Angstzustiände bei Ihnen verhindert werden, ebenso wie es uns vor profilierungs- und machtsächtigen Politikern schützt.

Sollten Sie der Meinung sein, dass Sie diese Internetseite dennoch sehen sollten, so können Sie jederzeit durch normalen Gebrauch eines Internetbrowsers darauf zugreifen. Dazu sind aber minimale Computerkenntnisse erforderlich. Sollten Sie diese nicht haben, vergessen Sie einfach dieses Internet und lassen uns in Ruhe.

Die Umgehung dieser Ausdrucksperre ist nach §95a UrhG verboten.

Mehr Informationen unter www.politiker-stopp.de.

0 10. März 2010
0 9. März 2010
0 27. Februar 2010
1 29. Januar 2010


Archiv der Kategorie 'Ich / Blog'

Identifikation und Authentifikation in RESTful APIs

Mittwoch, den 10. März 2010

Ja, viele von euch (srsly?) haben sicher schon einmal ein (semi) RESTful API entwickelt. Ein haeufiges Problem ist herauszufinden, ob ein Aufruf auch durchgefuehrt werden darf. Das Problem besteht darin, dass wir es dabei mit einem zustandslosen Protokoll (RFC 2616) zu tun haben, also fallen die Elgamal- und Diffie-Hellman-Kryptosysteme aus.

Um nun festzustellen, ob die Person (bzw. eine Applikation, stellvertretend fuer eine Person), die die Anfrage sendet auch wirklich die Person ist, fuer die sie sich ausgibt (Identifikation) und um gleichzeitig festzustellen, ob die Anfrage nicht manipuliert wurde (Authentifikation), gibt es zum einen das freie OAuth Protokoll, was aber relativ kompliziert zu implementieren ist, und zum anderen gibt es aehnliche Ansaetze, wie zum Beispiel das Flickr Auth Protokoll. Beide Protokolle bieten ausserdem die Moeglichkeit externen Programmen (Clients) den Zugriff auf das System (Service Provider) zu authorisieren.

Sofern letzteres nicht noetig ist, reicht jedoch ein abgespecktes Protokoll, das dem Flickr Protokoll sehr nah kommt. Hierbei faellt der Aufwand der sicheren Schluesseluebertragung weg. Und so einfach kann es gehen:

  • Der Service Provider generiert einen oeffentlichen Schluessel (API Key) und einen privaten Schluessel (Secret). Ich habe fuer den oeffentlichen Schluessel die SHA1 Pruefsumme verschiedener Variablen und fuer den privaten Schluessel die MD5 Pruefsumme von Variablen, Zufallszahlen und Timestamps genutzt.
  • Der Client wird mit beiden Keys ausgestattet. Wie gesagt: Der unwiretapped Schluesselaustausch muss anders sichergestellt werden. Bei meinem System kann der Benutzer die Keys einsehen, wenn er sich zuvor mit seinen Zugangsdaten eingeloggt hat. Das ist auch gaengige Praxis.
  • Bei einer Anfragegenerierung werden die Variablen inkl. oeffentlichem Schluessel (die Bezeichner, nicht die Werte!) alphabetisch sortiert und dann mit ihrem Wert konkateniert. Dann werden die Key-Value-Strings konkateniert und der private Schluessel wird vorangestellt. Das Ganze wird jetzt gehasht (e.g. MD5). Nun werden alle Variablen und die zusaetzlich generierte signature-Variable uebertragen.
  • Der Service Provider empfaengt alle Variablen, nimmt davon den oeffentlichen Schluessel und sucht in seiner Datenbank nach dem dazu passenden privaten Schluessel. Jetzt kann der Service Provider das selbe Spiel spielen, das der Client schon durchgemacht hat: Variablen sortieren, Key-Value-Strings bauen, konkatenieren, den privaten Schluessel voranstellen und hashen. Der Vergleich der uebermittelten Signatur und der generierten Signatur erlaubt die Authentifizierung des Zugriffs.

Beispiel

Der API Key ist fd40e3589bbb58ec358122c5cd32fcc6481707bb, das Geheimnis ist 162c9d446beb754b804b904772ff87b6. Die Variablen sind (Bezeichner = Wert):

  • method = deleteEntries
  • rangeFrom = 99
  • rangeTo = 101

Die Anfrage wird nun wie folgt Client-seitig generiert:
Sortieren:

apiKey vor method vor rangeFrom vor rangeTo

Konkatenieren:

apiKeyfd40e3589bbb58ec358122c5cd32fcc6481707bbmethoddeleteEntriesrangeFrom99rangeTo101

Private Key voranstellen:

162c9d446beb754b804b904772ff87b6apiKeyfd40e3589bbb58ec358122c5cd32fcc6481707bbmethoddeleteEntriesrangeFrom99rangeTo101

Hashen:

9ad5100448f0549472b0e70722aa06bb

Variablen fuer die Anfrage zusammensetzen:

http://example.com/rest/?apiKey=fd40e3589bbb58ec358122c5cd32fcc6481707bb&method=deleteEntries&rangeFrom=99&rangeTo=101&signature=9ad5100448f0549472b0e70722aa06bb

Das wird nun ausgefuehrt und auf der Service Provider Seite geht es dann so weiter:
API Key auslesen:

fd40e3589bbb58ec358122c5cd32fcc6481707bb

In der Datenbank nach dem passenden privaten Schluessel suchen:

162c9d446beb754b804b904772ff87b6

Sortieren, Konkatenieren, Private Key voranstellen, Hashen (s.o.):

9ad5100448f0549472b0e70722aa06bb

Ergebnisse vergleichen:

9ad5100448f0549472b0e70722aa06bb = 9ad5100448f0549472b0e70722aa06bb

That’s it. Ist sehr einfach zu implementieren und ist dafuer extrem sicher.

Just Married: Zend Framework & Flickr

Dienstag, den 9. März 2010

Vorweg: Ich glaube dieser Post wird lang…

Also zur Zeit bastel ich an einem Projekt, das aus einigen Social Networks Daten beziehen und diese auf Public Displays anzeigen soll. Da nur-Text etwas oede ist, habe ich mich also an die Flickr API gesetzt. Eigentlich bietet das Zend Framework dafuer die Klasse Zend_Service_Flickr an, aber leider ist die nicht dafuer ausgelegt Applikationen mit Flickr zu verbinden, sondern lediglich fuer eine direkte Benutzerauthentifizierung via Benutzername/Passwort.

Mein erster Ansatz war also erstmal in die API von Flickr zu schauen, denn die bietet ein OAuth aehnliches Verfahren zur Anwendungsauthentifizierung an. Der Trick war nun Zend_Service_Flickr damit zu verheiraten. Und so geht’s:

Als erstes registriert man eine Anwendung bei Flickr und richtet eine Callback URL ein. In meinem Fall wird damit die callbackAction meines FlickrControllers getriggert. Ich brauchte also einen FlickrController…

class FlickrController extends Zend_Controller_Action
{
    public function indexAction() { }
    public function authenticateAction() { }
    public function callbackAction() { }
}

Die Authentifizierung laeuft so ab:

  1. Der Benutzer oeffnet die index-Seite. Dort ist ein Link zur authenticate-Seite, wenn alles nicht schon gelaufen ist.
  2. Die authenticate-Action prueft zunaechst, ob die Anwendung bereits mit Flickr verknuepft ist. Wenn ja, dann wird zur index-Seite weitergeleitet. Wenn nein, dann wird eine Authentication Request URL gebaut und dorthin wird weitergeleitet.
  3. Auf der Flickr-Seite muss der Benutzer der Anwendung nun den Zugriff erlauben. Ist das geschehen, wird der Benutzer von Flickr direkt zur callback-Seite geleitet. Flickr haengt dabei noch eine Variable mit dem Namen frob an.
  4. Die callback-Action sendet daraufhin eine Anfrage an Flickr, die u.A. auch die frob-Variable enthaelt. Ausserdem wird eine Signatur angehangen.
  5. Flickr antwortet mit einem Token, der dann gespeichert wird und fuer zukuenftige Calls verwendet wird.

So, bevor ich alle mit Erklaerungen langweile: Jetzt kommt Code!

class SenScreen_Service_Flickr extends Zend_Service_Flickr
{
    protected $_secret;
    protected $_perms;
    protected $_token;
 
    const PATH_AUTH = '/services/auth/';
    const PATH_REST = '/services/rest/';
 
    public function __construct(array $options = null)
    {
        parent::__construct(null);
 
        $this->setOptions($options);
    }
 
    public function setOptions(array $options = null)
    {
        if ($options == null) {
            return;
        }
 
        $validOptions = array('api_key', 'secret', 'perms', 'token');
 
        $this->_compareOptions($options, $validOptions);
 
        if (isset($options['api_key'])) {
            $this->apiKey = $options['api_key'];
        }
        if (isset($options['secret'])) {
            $this->_secret = $options['secret'];
        }
        if (isset($options['perms'])) {
            $this->_perms = $options['perms'];
        } else {
            $this->_perms = 'read';
        }
        if (isset($options['token']) && $options['token'] instanceof SenScreen_Service_Flickr_AuthToken) {
            $this->_token = $options['token'];
        }
    }
 
    public function setApiKey($apiKey)
    {
        $this->apiKey = $apiKey;
        return $this;
    }
 
    public function getApiKey()
    {
        return $this->apiKey;
    }
 
    public function setSecret($secret)
    {
        $this->_secret = $secret;
        return $this;
    }
 
    public function getSecret($secret)
    {
        return $this->_secret;
    }
 
    public function setPerms($perms)
    {
        $this->_perms = $perms;
        return $this;
    }
 
    public function getPerms()
    {
        return $this->_perms;
    }
 
    public function setToken($token)
    {
        $this->_token = $token;
        return $this;
    }
 
    public function getAuthToken()
    {
        return $this->_token;
    }
 
    public function getApiSignature(array $params)
    {
        $plainSignature = $this->_secret;
        ksort($params);
        foreach ($params as $key => $value) {
            $plainSignature .= $key . $value;
        }
        return md5($plainSignature);
    }
 
    private function _getSignedUrl($path, array $params)
    {
        $url = self::URI_BASE . $path . '?';
        $urlParams = array();
        foreach ($params as $key => $value) {
            $urlParams[] = $key . '=' . $value;
        }
        $url .= implode('&', $urlParams);
        $url .= '&api_sig=' . $this->getApiSignature($params);
        return $url;
    }
 
    public function redirect()
    {
        $params = array(
            'api_key' => $this->apiKey,
            'perms'   => $this->_perms
        );
        $redirectUrl = $this->_getSignedUrl(self::PATH_AUTH, $params);
        header('Location: ' . $redirectUrl);
        exit(1);
    }
 
    public function getFrob()
    {
        return $_GET['frob'];
    }
 
    public function requestToken()
    {
        $params = array(
            'method'  => 'flickr.auth.getToken',
            'api_key' => $this->apiKey,
            'frob'      => $this->getFrob(),
            'perms'      => $this->_perms
        );
 
        $httpClient = new Zend_Http_Client($this->_getSignedUrl(self::PATH_REST, $params));
        $httpClient->resetParameters();
        $httpClient->setParameterGet($params);
        $httpClient->setHeaders(array(
            'Accept-encoding' => ''
        ));
        return $this->_parseToken($httpClient->request('GET'));
    }
 
    private function _parseToken(Zend_Http_Response $response)
    {
        $xmlElement = new SimpleXMLElement($response->getBody());
        return new SenScreen_Service_Flickr_AuthToken(
            (string) $xmlElement->auth->token,
            (string) $xmlElement->auth->user['username'],
            (string) $xmlElement->auth->user['fullname']
        );
    }
 
    public function isRestrictedMethod($method)
    {
        $restrictedMethods = array(
            'flickr.photos.getContactsPhotos'
        );
 
        return in_array($method, $restrictedMethods);
    }
 
    private function _execute($method, $defaultOptions, $options)
    {
        $options = $this->_prepareOptions($method, $options, $defaultOptions);
 
        $restClient = $this->getRestClient();
        $restClient->getHttpClient()->resetParameters();
        $response = $restClient->restGet('/services/rest/', $options);
 
        if ($response->isError()) {
            throw new Zend_Service_Exception('An error occurred sending request. Status code: '
                                           . $response->getStatus());
        }
 
        $dom = new DOMDocument();
        $dom->loadXML($response->getBody());
 
        self::_checkErrors($dom);
 
        return new Zend_Service_Flickr_ResultSet($dom, $this);
    }
 
    public function getContactsPhotos(array $options = array())
    {
        static $method = 'flickr.photos.getContactsPhotos';
        static $defaultOptions = array(
            'count'           => 100,
            'just_friends' => 0,
            'single_photo' => 0,
            'include_self' => 0,
            'extras'       => 'license, date_upload, date_taken, owner_name, icon_server, original_format, last_update.'
        );
        return $this->_execute($method, $defaultOptions, $options);
    }
 
    public function getRecent()
    {
        static $method = 'flickr.photos.getRecent';
        static $defaultOptions = array(
            'per_page' => 10,
            'page'     => 1,
            'extras'   => 'license, date_upload, date_taken, owner_name, icon_server, original_format, last_update.'
        );
        return $this->_execute($method, $defaultOptions);
    }
}

Diese Klasse erweitert Zend_Service_Flickr, sodass diese auch mit Authentifizierung umgehen kann. Als naechstes muss der Zend_Http_Client ausgetauscht (bzw. erweitert) werden, sodass auch er mit Signaturen und dem Kram umgehen kann:

class SenScreen_Service_Flickr_Http_Client extends Zend_Http_Client
{
    protected $_flickr;
 
    public function __construct()
    {
        parent::__construct();
 
        $this->setHeaders(array('Accept-Encoding' => ''));
    }
 
    public function setFlickr(SenScreen_Service_Flickr $flickr)
    {
        $this->_flickr = $flickr;
    }
 
    public function request($method = null)
    {
        if ($this->_flickr->isRestrictedMethod($this->paramsGet['method'])) {
            $this->paramsGet['auth_token'] = $this->_flickr->getAuthToken()->getToken();
 
            $this->paramsGet = array_merge($this->paramsGet, array(
                'api_sig' => $this->_flickr->getApiSignature($this->paramsGet)
            ));
        }
        return parent::request($method);
    }
}

Als naechstes Brauchen wir noch eine Klasse, die unser Token aufbewahrt und serialisierbar in der DB ablegbar ist:

class SenScreen_Service_Flickr_AuthToken
{
    private $_token;
    private $_username;
    private $_fullname;
 
    public function __construct($token, $username, $fullname)
    {
        $this->_token    = $token;
        $this->_username = $username;
        $this->_fullname = $fullname;
    }
 
    public function getToken()
    {
        return $this->_token;
    }
 
    public function getUsername()
    {
        return $this->_username;
    }
 
    public function getFullname()
    {
        return $this->_fullname;
    }
}

Und dann koennen wir endlich den Controller fuellen und jetzt kommen auch mal Kommentare in den Code, damit ich nicht mehr so viel quarken muss:

class FlickrController extends Zend_Controller_Action
{
    protected $_config = array(
        'api_key' => 'myapplicationkey',
        'secret'  => 'mysecret'
    );
 
    protected $_flickr;
 
    public function init()
    {
        $this->_flickr = new SenScreen_Service_Flickr();
        $httpClient = new SenScreen_Service_Flickr_Http_Client();
        $httpClient->setFlickr($this->_flickr);
        Zend_Rest_Client::setHttpClient($httpClient);
    }
 
    public function indexAction()
    {
        $userId = Zend_Auth::getInstance()->getIdentity()->id;
        /**
         * Check whether the current user has an access
         * token for Flickr.
         */
        $userSettingModel = new Model_UserSetting();
        if ($userSettingModel->get($userId, 'flickr_token')) {
            /**
             * Get the access token.
             */
            $access_token = unserialize($userSettingModel->getValue());
 
            /**
             * Configure the Flickr instance.
             */
            $this->_flickr->setOptions(array_merge(
                $this->_config,
                array('token' => $access_token)
            ));
 
            $this->view->contactPhotos = $this->_flickr->getContactsPhotos(array('include_self' => 1, 'extras' => ''));
 
            $this->view->showAuthenticationButton = false;
        } else {
            $this->view->showAuthenticationButton = true;
        }
    }
 
    public function authenticateAction()
    {
        $userId = Zend_Auth::getInstance()->getIdentity()->id;
 
        /**
         * Check whether the current user has an access
         * token for Flickr.
         */
        $userSettingModel = new Model_UserSetting();
        if ($userSettingModel->get($userId, 'flickr_token')) {
            /**
             * Get the access token.
             */
            $this->_helper->redirector('index');
        } else {
            /**
             * The user is not authenticated with Flickr.
             * Request Flickr auth frob and redirect to
             * Flickr's authentication page.
             */
            $this->_flickr->setOptions($this->_config);
            $this->_flickr->redirect();
        }
    }
 
    public function callbackAction()
    {
        $userId = Zend_Auth::getInstance()->getIdentity()->id;
 
        $this->_flickr->setOptions($this->_config);
 
        /**
         * Check whether a frob is present for this user.
         */
        if ($this->_flickr->getFrob()) {
            /**
             * A frob is present. Request a token and
             * save it in the database.
             */
            $token = $this->_flickr->requestToken();
            $userSettingModel = new Model_UserSetting();
            $userSettingModel->setUserId($userId)
                             ->setKey('flickr_token')
                             ->setValue(serialize($token))
                             ->save();
 
            /**
             * Everything is done, redirect to the index
             * page.
             */
            $this->_helper->redirector('index', 'flickr');
        } else {
            /**
             * The callback has been called without having
             * a request token. Redirect to the index page.
             */
            $this->_helper->redirector('index', 'flickr');
        }
    }
}

Sollte soweit selbsterklaerend sein. Viel Spass damit. ;-)

Update:
Wie ihr vielleicht bemerkt habt, nutze ich das Abstract Data Mapper Design Pattern.

Finsternis

Samstag, den 27. Februar 2010

Gestern habe ich das Geschenk fuer meine Freundin zum Einjaehrigen eingeloest: Ein Essen im Restaurant Finster in Essen. Dort angekommen hat uns ein Mann mit trockenem Humor empfangen und unsere Essenswuensche und die erste Getraenkebestellung entgegengenommen. Er hat dann eine der Mitarbeiterinnen per Funk geordert, die uns dann Polonaise-artig durch eine Lichtschleuse und dann zum Tisch geleitet hat. Dort angekommen musste man sich erst an die absolute Dunkelheit gewoehnen. Eine solche Dunkelheit kann man zuhause kaum erreichen. Es gibt dort keinerlei Restlicht. Man ist quasi blind.

Wir haben also zunaechst den Tisch abgetastet und einen kleinen Teller vorgefunden, neben dem links, rechts und dahinter das Besteck traditionell angeordnet war. Die Kellnerin hat uns dann erklaert, dass in der Mitte des Tisches eine Schuessel mit Dip und Brot liegt. Ich habe natuerlich als erstes in den Dip gelangt. Spaeter hat sich herausgestellt, dass es Ajoli war. Erschmeckt haben wir es nicht. Wir haben auf eine Cocktailsauce oder Tzatziki getippt.

Nachdem wir das Brot vertilgt hatten, kam auch schon unsere Vorspeise: Eine Suppe, die wir schnell als Kartoffelsuppe identifiziert hatten. Dazu brachte man uns direkt die Getraenke, die man uns dann in die Hand gegeben hat. Neben unserem Tisch befand sich eine Saeule, an der wir die Glaeser positioniert haben, damit wir sie jederzeit wiederfinden und die Gefahr senken, die Glaeser umzuwerfen.

Eine Weile nachdem wir nun auch endlich die Vorspeise geloeffelt hatten, wurde der Tisch dann abgeraeumt und die Hauptspeise wurde gereicht. Und das war der Zeitpunkt, ab dem bei mir die Sauerei anfing. Ich wollte als erstes herausfinden, was ueberhaupt auf meinem Teller liegt, denn man bekommt weder gesagt was es ist, noch wo es ist. Auf meiner Seite links auf dem Teller lagen kleine Knoedel, deren Geschmack auf Gnocchi hinwies. Ueber den ganzen Teller verteilt lag Brokkoli mit irgendeiner Sauce und erst spaeter haben wir einen grossen Klumpen entdeckt, der gegenueber von den Gnocchi lag. Den Klumpen konnten wir nicht identifizieren, aber es koennte alles von Reis bis Kuskus in Frikadellenform, paniert und frittiert, gewesen sein. Da der Geschmack nicht so meins war, habe ich den Klumpen dann heimlich auf den Teller meiner Freundin befoerdert.

Meine Finger und die Serviette, die ich mir in den Kragen gestopft hatte, waren bis dahin schon total eingesaut. Das Essen war aber reichlich und wir haben es beide nicht aufgegessen. Eine gefuehlte halbe Stunde spaeter kam die Kellnerin wieder und hat die Teller abgeraeumt und uns neue Getraenke gebracht. Kurze Zeit spaeter kam dann auch der Nachtisch: Panna cotta mit einer alkoholhaltigen Sauce.

Alles in Allem war das Essen sehr lecker. Es ist aber sehr krass ohne etwas zu sehen zu essen. Die Hauptspeise konnte ich nur mit den Fingern essen, da ich sonst nichts aufs Besteck bekommen haette, die Nachspeise musste ich mit dem Dessertloeffel essen, aber das hat auch nicht wirklich geklappt. Meistens war der Loeffel leer, zu voll oder alles fiel schon zuvor auf den Tisch. Was mich gestoert hat war, dass es sehr laut wurde, als eine etwas groessere Gruppe in die Dunkelkammer gebracht wurde.

Irgendwann beim Dessert rief dann ein Kellner dazu auf, einem 8 Jahre alt gewordenem Maedchen ein Staendchen zu singen. Ich hatte da aber den Mund voll, da ich es endlich geschafft hatte ein riesiges Stueck Panna cotta mit dem Loeffel von der schifffoermigen Schuessel zu meinem Mund zu befoerdern.

Der Preis ist sehr hoch, aber es ist die Erfahrung wert.

Identitaet und Privatsphaere

Freitag, den 29. Januar 2010

Identitaet – was ist das eigentlich? Irrelevanzia definiert die Identitaet wie folgt:

Beim Menschen bezeichnet Identitaet (v. lat. idem, derselbe, der gleiche) die ihn kennzeichnende und als Individuum von anderen Menschen unterscheidende Eigentuemlichkeit seines Wesens.

Es geht also um Alleinstellungsmerkmale und die kann man zumindest stochastisch evaluieren. Wir ich schon in meinem Paper ueber Reality Mining1 bereits beschrieben habe, ist Entropie ein dabei besonders interessantes Mass. Es gilt als Einheit fuer Unordnung, aber es ist viel mehr als das. Entropie kann dazu verwendet werden, um Muster zu visualisieren und sie sogar mathematisch vergleichbar zu machen, selbst wenn wir diese Muster nicht in Worte fassen koennen. Eine andere Definition von Entropie nennt es die Generalisierung der Anzahl von moeglichen zufaelligen Unterschieden. Solche Anzahlen werden haeufig auch durch Bits of Entropy dargestellt. Beispiel: Bei einem Zufallsexperiment gibt es zwei moegliche Elementarereignisse. Wir sprechen hierbei dann von einer Entropy von einem Bit, da 2^1 = 2. Wenn wir eine Entropy von 3 Bits bei einem Zufallsexperiment annehmen, so gibt es 2^3 = 8 Ereignisse, usw.

Nun koennen wir dieses simple mathematische Modell auf die Identitaet anwenden: Es gibt ca. 6,9 Milliarden Menschen (6.900.000.000). Also benoetigt man \log_2 (1/6900000000) = 32,6839 Bits, um eine Person auf der Welt eindeutig zu identifizieren. Da es bei Computern so immer die Sache mit der 8 ist, koennen wir jetzt mal approximieren: 4*8 < 32,6839 < 5 * 8, also weniger als 5 Byte. Zum Vergleich: Auf x86 Maschinen ist die Assembler Anweisung nop (=no operation, hexadezimal 90 oder auch 10010000) 8 Bit lang. 8 Bits wuerden genuegen, um im optimalen Fall 256 Personen unterscheiden zu koennen. Das ist alles wirklich nicht viel.

Treiben wir das ganze noch weiter und werden politischer: Wenn EVILOFYOURCHOICE Daten von Personen speichert, z.B. Land, Most Viewed Website, durchschnittliche Online-Zeit, Browser, Displaygroesse, zuletzt online gekaufter Artikel, zuletzt offline gekaufter Artikel, etc., ohne zu wissen, wer diese Person ist, so ist das voellig egal, denn man kennt natuerlich auch die Personen, die mit dieser Person kontakt hatten (Telefon, E-Mail, SMS) und deren Daten und das alles aggregiert sich zu einem riesigen Netz (ja, jetzt sind wir beim Reality Mining angelangt). Jetzt nehmen wir mal an, dass wir dieses Netz kennen und eine Person aus diesem Neetz geht in einen Laden und nutzt seine Payback-Karte, die mit dem Namen der Person assoziiert ist… dann wissen wir auf einmal noch viel mehr und koennen ohne Muehe andere Personen aus diesem Netz identifizieren.

Leute, die unsere Daten speichern, nutzen solche Techniken (die ich bewusst sehr plump erklaert habe) schon seit Jahren! Sie nutzen das auch aus und senden Werbung oder bevorzugen besondere Zentralpersonen solcher Netze bei Hotlines und bei Kulanz. Wisst ihr ueberhaupt, wer was von euch weiss? Glaubt ihr wirklich, dass eure Privatsphaere geschuetzt ist und ihr nichts zu verbergen habt?

Uebrigens: Wenn die Polizei so etwas macht, dann nennt man das Rasterfahndung, deren Vertraeglichkeit mit dem Grundgesetz doch stark zu bezweifeln ist, da sie die Unschuldsvermutung, die wie folgt rechtlich (GG Art. 11 Abs. 1) definiert ist, aufhebt:

Jeder Mensch, der einer strafbaren Handlung beschuldigt wird, ist solange als unschuldig anzusehen, bis seine Schuld in einem oeffentlichen Verfahren, in dem alle fuer seine Verteidigung noetigen Voraussetzungen gewaehrleistet waren, gemaess dem Gesetz nachgewiesen ist.

Auf Europaeischer ebene verletzt es meiner Ansicht nach auch Art. 6 Abs. 2 der Europaeischen Menschenrechtskonvention:

Jede Person, die einer Straftat angeklagt ist, gilt bis zum gesetzlichen Beweis ihrer Schuld als unschuldig.

Dennoch wird es gemacht! Wollt ihr wirklich den neuen Personalausweis oder bis vor kurzem ePA?

SRSLY?

Mehr Informationen zu Bits & Privacy? Hier.

  1. Veroeffentlichung steht noch aus. []

Der lange Weg zum NAS

Donnerstag, den 21. Januar 2010

Wie ich waehrend des 26C3 festgestellt habe, mag ich Netzwerk Storages. Ich habe also bei eBay herumgeschaut und musste wiederum feststellen, dass ich mir eine richtige Kiste nicht leisten kann. Also habe ich mich prompt dazu entschieden, mir ein NAS zu improvisieren. Die Zutaten:

  • ein Thin Client
  • ein paar USB Sticks
  • ein paar externe Festplatten
  • Linux

Ich habe mir also bei eBay zwei (just in case…) Thin Clients (FSC Futro S300 und HP Thin Client t5510) fuer insgesamt rund 70 EUR gekauft. Da der HP schoener aussieht und als erstes geliefert wurde, habe ich ihn auserkoren zum NAS zu werden.

Der naive Versuch

Da der HP (und auch der FSC) kein CD Laufwerk hat, bleibt nur USB. Das war mir ja klar, also habe ich auch direkt ein paar (2x 4GB, 10x 2GB, weil die so guenstig waren) USB Sticks gekauft und den Ubuntu Installer auf einen der 4GB Sticks geknallt. Da der Installer aber nach 30 Minuten noch immer nicht komplett geladen war, habe ich das mit dem Ubuntu ad acta gelegt.

Kleine Pueppchen

Nun musste also eine Ersatzdistro her, die am Besten auf Debian basiert (Debian ist sexy). Nach ein paar brutalen Stunden, die ich mit Google verbracht hab, war ich von dem Linux Terminal Server Project etwas enttaeuscht. Dann bin ich endlich auf Puppy Linux gestossen. Die knapp 100MB grosse Linux Distribution habe ich dann gepflegt in den Downloadmanager geladen und froehlich 1,5 Stunden(!!!) gewartet. Tolle Mirrors….

Aber endlich war es dann soweit. USB Stick mit Puppy Linux beladen und gib ihm… Haettstewohlgern! Die Fehlermeldung beim Booten haette genauso gut auch EPIC FAIL heissen koennen. Blieb mir nur eins:

dd if=/dev/null of=/dev/sda

Verdammt klein

… soll ja Damn Small Linux sein. Da es auch auf Debian basiert, war es meine naechste Wahl. Saugen,  auf den Stick knallen, booten. Endlich! Innerhalb von Sekunden(!!!) startete Fluxbox. Coole Sache. Das hat mich an meine (spaete, da ich anfaenglich nur mit CLI gearbeitet habe) OpenBSD Zeit erinnert. Da gab es tatsaechlich auch die Moeglichkeit ein Pendrive Linux zu installieren. Also steckte ich einen weiteren USB Stick in den Thin Client, der zum Glueck 4 USB Slots hat, und startete sogleich auch den Pendrive Installer. EPIC FAIL. Abgeschmiert. Zu wenig RAM… Damn Small aber dennoch Damn Memory-leaky. Diesmal habe ich mir dann mit…

shred -n 10 -v /dev/sda

…geholfen. *facepalm*1

Verzweiflung

Zu dem Zeitpunkt war ich doch schon sehr verzweifelt, da ich schon mehrere Tage (da ich ja immer erst spaet von der Uni komme) daran gehockt habe und noch zu keinem Ergebnis gelangt bin. Unter Windows lief mal wieder mein VMware-Ubuntu im Unity-Mode (sexy, wenn auch von Parallels abgeguckt). Da Ubuntu von Debian abstammt, kommt man auch sehr schnell auf die Idee debootstrap anzuschmeissen und sich sein Debian manuell zusammenzubauen. Gesagt, getan: Nach ein paar Stunden Frickelei (USB+ext3 = keine gute Idee, USB+vfat+Linux = noch schlechtere Idee, USB+Grub = beschissene Idee) habe ich es dann auch geschafft mir ein Linux zu bauen, das ich halbwegs booten konnte. Halbwegs. Kernel Panic. Aus die Maus.

cfdisk -z /dev/sda

… und auf Wiedersehen Partitionstabelle.

RTFM

Manchmal ist es doch so einfach: Die Debian Doku enthaelt einen netten Abschnitt ueber das Vorbereiten von Dateien fuer das Booten von einem USB Stick. Die boot.img.gz-URL hat mir Google sofort geliefert. wget, zcat, mount und eine sowieso in meinem Dateiarchiv existierende und aktuelle Debian ISO draufgeschoben, brachte mich nun endlich zum Erfolg. Der Debian Installer im Textmodus startete problemlos und hat es zugelassen die Installation auf einen anderen USB Stick vorzunehmen. Nur das mit dem Grub ist da so eine Sache… Der Installer dachte “ich USB, ich = sda, sdb = Ziel, (hd2,0) also Bootpartition” (hd0 ist die interne 32MB Flash Card, die so fest verbaut ist, dass man sie nicht austauschen kann). Dementsprechend pflanzte der Installer eine Grub Config (in (hd1,1), also /dev/sda1, wtf?) und die Flash Card habe ich als MBR-Bettchen erkoren. Beim Rebooten (und gleichzeitigem Entfernen des Installer-Sticks) war es natuerlich klar, dass Grub etwas verwirrt war. Interessanterweise hat er die Config gefunden. Nunja, jetzt zwei Zeichen im Bootmenue zu aendern war nicht das Problem und so bootete endlich(!!!) ein jungfraeuliches Debian.

Fileserver

… sind auch so eine Sache fuer sich. Samba (jaja, oldschool – aber soll ja jeder hier im Haus nutzen koennen) hat eine sehr interessante fluide Syntax fuer die Config. Wichtig hierbei war lediglich root preexec zum Mounten der Festplatte (sofern nicht bereits geschehen). Da meine Externe einen netten Stromsparmodus hat und sich selber abschaltet, wenn sie laenger nicht genutzt wurde, konnte ich mir postexec sparen.

Wenn man nun schon einen Fileserver hat, dann kann der ruhig auch hier und da mal dezentrales Filesharing (ohja, man kann auch legale Sachen damit herunterladen!) betreiben. rtorrent hatte ich noch im Hinterkopf, aber das habe ich ganz schnell wieder verworfen. Drecksteil. Das hat mehr Shortcuts als screen und vi zusammen. Oergs. Dann wollte ich noch torrentflux, eine Webschnittstelle zu rtorrent, nutzen… Ein guter Tipp: MySQL und 128MB RAM vertragen sich gar nicht. Letztendlich war MySQL an, dpkg dachte es sei deinstalliert (sogar purged) und das Init-Script mochte es nicht stoppen, weil es dazu ersteinmal initial-gestartet werden muesste, um die Configs zu generieren. Argh! Uebrigens, folgendes hilft:

dpkg --remove --force-remove-reinstreq mysql-server-5.0

Wo war ich? Achja, torrentflux. MySQL + Low Memory = Dreck. Apache ging lustigerweise. Aber ohne torrentflux brauch ich es nicht. Also weg mit dem Mist. Dann blieb ich erstmal bei Transmission. Dank babels Tipp habe ich mir dann doch (das per Default bereits installierte) BitTornado bzw. btdownloadcurses angeschaut. Nach knapp 1,5 Stunden Spielereien mit screen und btdownloadcurses kam dann ein nettes Bash-Script heraus, das Torrents herunterladen, sie archivieren, sharen und gleichzeitig in eine wunderbare Multiwindow-Screen-Umgebung packen kann. Das moechte ich natuerlich niemanden vorenthalten (ja, inkonsistente Schreibweise, aber ich bin atm zu faul):

#!/bin/bash
 
### CONFIG ###
 
DEVICE="/dev/sdb1"
MOUNTPOINT="/media/storage"
TORRENTDIR="/root/torrents"
DOWNLOADDIR="/media/storage/public"
PORTFILE="/root/torrents/.ports"
SCREEN_SESSION_NAME="__DEFAULT"
SCREEN_DATETIME="$(date +%Y%m%d_%H%M%S)"
MAX_UPLOAD_RATE=30
MIN_PORT=53535
MAX_PORT=53559
 
### CODE ###
 
if [ "$(cat /proc/mounts | grep /media/storage | wc -l)" -eq "0" ]; then
    echo -n "Mounting $DEVICE on $MOUNTPOINT..."
    mount -t ntfs-g3 $DEVICE $MOUNTPOINT > /dev/null 2>&1
    if [ "$?" -eq 0 ]; then
        echo " done."
    fi
fi
 
FILE=""
 
if [ -f "$1" ]; then
        echo "Loading $1..."
        FILE="$1"
else
        echo -n "Downloading torrent..."
        rm -f tmp.torrent
        wget -O tmp.torrent $1 > /dev/null 2>&1
        echo " done."
        if [ -f "tmp.torrent" ]; then
                echo -n "Name: "
                read NAME
                FILE="$NAME.torrent"
                mv tmp.torrent "$FILE"
        else
                echo "Torrent file does not exist"
                exit 1
        fi
fi
 
cd $DOWNLOADDIR
 
SCREEN_EXISTS=$(screen -ls | grep ${SCREEN_SESSION_NAME} | wc -l)
 
if [ "$SCREEN_EXISTS" -eq "0" ]; then
        /usr/bin/screen -S "${SCREEN_SESSION_NAME}" /usr/bin/btdownloadcurses --max_upload_rate $MAX_UPLOAD_RATE --minport $MIN_PORT --maxport $MAX_PORT "$TORRENTDIR/$FILE"
else
        COMMAND="screen /usr/bin/btdownloadcurses --max_upload_rate $MAX_UPLOAD_RATE --minport $MIN_PORT --maxport $MAX_PORT \"$TORRENTDIR/$FILE\""
        /usr/bin/screen -r "${SCREEN_SESSION_NAME}" -X eval "$COMMAND"
fi

Last but not least muss ich sagen: Es hat sich (bisher) gelohnt.

  1. Ich lese definitiv zu viel Fefe []

Woran merkt man, dass die Welt untergeht?

Freitag, den 8. Januar 2010

Und hier folgen auch schon meine Top 10:

Platz 10

peep peep peep peeeeep peeeeep peeeeep peep peep peep

Platz 9

Die Russen kommen.

Platz 8

Es tauchen RFCs zum Thema Archebau auf und es ist nicht der 1. April.

Platz 7

Ueberall rennen Hollaender wild umher und schreien “Vloed!!!” (Flut).

Platz 6

China laesst Gefangene frei.

Platz 5

Die Bild sagt die Wahrheit.

Platz 4

Es gibt kein Bier mehr.

Platz 3

Die USA fängt an neues Geld zu drucken.

Platz 2

CDU und/oder FDP sind an der Macht.

Platz 1

Fefe hat aufgehoert zu bloggen.

Mein idealer Arbeitsplatz

Sonntag, den 22. November 2009

Durch Dirks Umfrage zum idealen Arbeitsplatz fuehle ich mich gezwungen auch etwas zu schreiben…

Mein idealer Arbeitsplatz erfuellt folgende Kriterien:

  • das Arbeitsklima ist freundschaftlich; bei Fragen wird man unterstuetzt und Hilfe muss nicht erbettelt werden
  • die Arbeitszeit ist frei; solange X am Y fertig ist, ist alles okay; es gibt kein Zeiterfassungssystem
  • der Arbeitsort ist variabel. Wenn das Buero nervt, arbeitet man von Zuhause oder wo man moechte
  • das Geld stimmt
  • die Wahl der Hilfsmittel/Tools/Entwicklungsumgebungen/Software/Hardware ist frei
  • es gibt keine Rufbereitschaft
  • man muss nicht um Urlaubstermine streiten
  • die Arbeit wird dokumentiert
  • es wird strukturiert gearbeitet
  • die Vorgesetzten wissen, wovon sie reden
  • die Aufgabenstellungen werden klar formuliert
  • Deadlines werden sinnvoll gelegt
  • Risikoabschaetzung wird durchgefuehrt

Die meisten Punkte werden von meinem Job am Lehrstuhl extrem gut erfuellt, muss ich feststellen. :-)

GPS Device?

Montag, den 9. November 2009

Zur Zeit suche ich ein geeignetes GPS Geraet, das folgende Eigenschaften erfuellen soll:

  • Bluetooth + USB
  • Logging + Real-Time Navigation
  • Manuelle Speicherung der Position (Push-To-Log)
  • mind. 50 Kanaele
  • lange Akkulaufzeit (Minimum: 10 Stunden)
  • mind. 1 Hz (Logging & Receiving)
  • AGPS Unterstuetzung
  • NMEA via COM Port lesbar
  • Real-Time Navigation via Google Earth soll moeglich sein
  • Speicher fuer mind. 100.000 Wegpunkte
  • geringe Cold/Warm/Hot-Startzeiten
  • geringer Preis (< 80 EUR)

Hat jemand zufaellig Erfahrungen und Vorschlaege?

Nachtrag (10.11.2009):
Ich habe mir heute einen GPS Receiver von Nokia bei Amazon gekauft, weil ich das Teil heute life testen konnte und positiv ueberrascht war. Das werde ich erstmal durchtesten. Vorschlaege fuer andere Geraete sind immernoch willkommen, da ich einen Logger haben moechte. Ich habe das Geraet aber nur gekauft, weil es extrem guenstig und dafuer sehr gut ist. Gekauft habe ich es bei Amazon: Nokia LD-4W Bluetooth GPS Modul.

ZoneTrak

Freitag, den 30. Oktober 2009

Mjam, wie Einige schon mitbekommen haben, entwickle ich ein Real-Time Tracking System fuer Katastrophenschutzorganisationen am Pervasive Computing and User Interface Lehrstuhl von Prof. Albrecht Schmidt an der Universitaet Duisburg-Essen… Bevor ich alle langweile: Hier gibt es weitere Informationen fuer die jenigen, die mehr erfahren wollen:

ZoneTrak @ Tomorrow Lab

Zensursula’s Reich

Montag, den 24. August 2009

(Entweder JavaScript ist nicht aktiviert, oder Sie benutzen eine alte Version von Adobe Flash Player. Installieren Sie bitte den aktuellsten Flash Player. )
Propaganda pur… Das haette Goebbels nicht besser hinbekommen. Bevor ich meinen rechten Arm gen Zensursula strecken und ihr Heil wuenschen muss, lauf ich lachend in eine Kreissaege.

Transkript (Ausschnitt):

Und dann sag ich den Linken ganz deutlich: Ihr traut diesem Land nichts zu! Wir sollten in der Lage sein hier deutlich auch Zeichen zu setzen, dass wir diese Sperren können.
[Beifall]
Dann aber, meine Damen und Herren, dann wurde es eine Stufe schlimmer. Dann hieß es verfassungsrechtlich bedenklich wegen der Informationsfreiheit. Meine Damen und Herren, wir sollten nicht den Eindruck vermitteln, unsere Verfassung würde die Verbreitung der Vergewaltigung von Kindern Schutz geben. Das ist absurd! Massenkommunikation ist wichtig, ja. Aber es kann ja wohl nicht so weit gehen, dass man dafür, weil man die Massenkommunikation so hoch stellt, die Würde und den Schutz eines Kindes hinten anstellt und sagt: Dies ist nachrangig. Und dann habe ich, weil die Linken auf Tauchkurs gegangen sind, zunächst einmal alleine mit den Anbietern von Internetzugängen, das sind ganz normale Telefongesellschaften wie die Telekom, Vodafone, Arcor und so weiter, Verträge gemacht. Mein Kabinettskollege Karl-Theodor zu Guttenberg hat Ruck-Zuck ein Gesetz auf den Weg gebracht, das deutlich macht: Wir sperren von Deutschland aus, weil wir eine ganz klare Haltung auch dazu haben, diese schrecklichen Bilder und den Zugang zu diesen schrecklichen Bildern.. Und dann kam das Tollste. Dann kam der Chaos Computer Club und die Piratenpartei, die plötzlich schrien: Das ist Zensur!. Meine Damen und Herren, Kinderpornographie im Internet im Internet anzuschauen ist Kindesmissbrauch und ich rufe all denjenigen zu, die in diesem Zusammenhang von Zensur im Internet sprechen: Das Internet ist kein rechtsfreier Raum und das Recht gilt online genauso wie offline. Was wir niemals in einer Zeitung tolerieren würden, tolerieren wir im Internet genau so wenig.
[Beifall]
Meine Damen und Herren, hier ist der Schlüsselbegriff, auch wenns ungemütlich wird, Verantwortung. Wir werden eines Tages nicht nur gefragt nach dem, was wir getan haben, sondern auch nach dem, was wir vielleicht nicht getan haben. Wo wir gekniffen haben. Wo wir uns geduckt haben, nur weils anstrengend wird. Hier muss man dann auch Farbe bekennen. Hier muss man dann auch Stürme durchstehen. Antoine de Saint-Exupéry, der Vater oder der Autor des kleinen Prinzen, hat es eigentlich wunderschön auf den Punkt gebracht. Er hat gesagt: Mensch sein heißt verantwortlich sein. Genau das ist es: Mensch sein heißt verantwortlich sein. [...]

Zum von mir unterstrichenen Text: Eben, wofuer dann neue Gesetze? Ist doch schon verboten. Diese Frau redet nur Unsinn und gehoert ebenfalls notgeschlachtet.

P.S.: Der versprochene Urlaubsbeitrag kommt sobald die Unterwasserfotos entwickelt wurden…

Presseausweis?

Freitag, den 7. August 2009

Ich habe mir ernsthaft darueber Gedanken gemacht, ob ich mir einen Presseausweis zulegen soll. Geht das als Blogger ueberhaupt? Ja, geht1. Wozu? Ein Beispiel:

Der Eintritt in den Resellerbereich auf der CeBIT ist Resellern, die sich als solche Ausweisen koennen, und der Presse, unter Vorlage eines Presseausweises, vorbehalten.

Die CeBIT ist wahrscheinlich ein schlechtes Beispiel, weil sie als eine der wenig(st)en Veranstaltungen selber Presseausweise fuer Blogger ausstellt. Aber das Beispiel gilt o.B.d.A.

Nun, wieso nicht? Minimal 97 EUR Aufnahmegebuehr in den DVPJ + bis zu 36 EUR monatlichen Mitgliedsbeitrag. *cough*

Idee: Man sollte einen neuen Verband gruenden: den Deutschen Verband der Presseblogger (DVPB). Dabei muesste man Presseblogger nur noch so definieren, dass ein Blogger genau dann ein Presseblogger ist, wenn seine Beitraege nachweislich (zum Teil) journalistischer Natur sind.

  1. http://www.jurablogs.com/de/presseausweis-fuer-blogger []

Ferien

Mittwoch, den 5. August 2009

Endlich ist es soweit. Die letzten Klausuren sind geschrieben. Frei. Schluss. Ende. Bam!

Bowling Champions

Samstag, den 1. August 2009

Heute Abend waren wir Bowlen. In Knippie’s Bowlingcenter gibt es regelmaessig Aktionen, bei denen man zum Beispiel eine Art Kamelrennen im Kirmesstil gegen alle anderen Bahnen spielt. Jeder Wurf, bei dem mindestens 7 Punkte erreicht werden, zaehlt.

Aber noch etwas Vorgeplaenkel: Wir waren insgesamt zu viert und sind nicht wirklich so die Bowler. Eigentlich waren wir alle seit Ewigkeiten nicht mehr Bowlen. Nun ging irgendwann das Licht aus und Discolicht wurde angeschaltet. Spaeter erschien auf Leinwaenden ein Kamelrennenscreen mit allen Bahnen. Das Rennen wurde bekanntgegeben und wir haben natuerlich wie die Bloeden drauf los geperzt. Neben uns war anscheinend ein Bowlingverein oder zumindest eine Gruppe von sehr guten Bowlern.

Beim Rennen waren wir interessanterweise immer im vorderen Bereich. Im letzten Viertel ueberholten wir die sehr mannstarke Gruppe von Bahn 4, die bei jedem Wurf laut jubelten. Letztendlich erreichten wir als erstes die maximale Punktzahl und gewannen das Rennen voellig unerwartet mit einem grossen Vorsprung zu den meisten Bahnen aber nur geringem Vorsprung zu Bahn 4. Als Preis erhielten wir alle Gutscheine.

In der Vergangenheit war ich eigentlich immer der absolute Verlierer beim Bowlen und habe noch nie einen Strike geworfen. Heute waren es einige Strikes – sogar in Folge.

Ob da was im Bier war? … Naja, jetzt gehts erstmal ins Delta Essen.

DBMS + REM2: done

Donnerstag, den 30. Juli 2009

Puh, das wars fuer diese Woche. Ich bin tot.

Cryptography: done

Mittwoch, den 29. Juli 2009

So, eben habe ich erfahren, dass ich bestanden habe. Ich haette zwar gerne eine 1 vor dem Komma gehabt, aber naja… Mal gucken, was ich bei der Einsicht der Klausur noch rausholen kann…

Und gleich gehts in die naechste Klausur: Datenbankmanagementsysteme.