Nie jest tajemnicą, że nasze postępowanie w sieci jest rejestrowane. Zajmują się tym w różnych celach różne podmioty. Najczęstszym celem stosowania mechanizmów śledzenia są mechanizmy analityki. W tym artykule pochylimy się nad tematem z nieco bardziej prywatnej perspektywy. Technika, którą przybliżę nazywana jest metodą obrazka śledzącego.

Zasada działania

W celu zrozumienia tej metody, należy przeanalizować proces przeglądania obrazów za pośrednictwem przeglądarki. Jest on bardzo prosty. Niezależnie, czy obraz jest elementem strony internetowej czy odwiedzamy go bezpośrednio - w każdym przypadku mamy do czynienia z pobraniem zasobu z serwera. Poniższy schemat przedstawia proces w sposób uproszczony:

Zazwyczaj sprawa wygląda następująco: klient wysyła żądanie o zasób obraz.png na co serwer odpowiada nagłówkiem o typie treści Content-type: image/png a następnie treścią binarną obrazka.

Sytuacja zmienia się kiedy zdefiniujemy reguły mod_rewrite w konfiguracji serwera lub pliku .htaccess. Programista może tak skonfigurować serwer, aby ten wykonał skrypt, który jedynie zasymuluje przedstawione wyżej zachowanie. Taki skrypt może wykonać dowolne czynności (w szczególności zapisać informacje o kliencie) a następnie wysłać obraz, nie budząc niepokoju klienta.

Zastosowania

Najczęstszym z zastosowań omawianej dziś techniki są wiadomości e-mail. Zdarza się, że chcemy otrzymać potwierdzenie odebrania wiadomości. Nie zawsze jednak odbiorca zgadza się na wysłanie takiego potwierdzenia, bądź nie chcemy jawnie pokazać, że zależy nam na tej informacji. Innym zastosowaniem może być przeprowadzenie rekonesansu przeglądarki użytkownika. Wystarczy wysłać komuś adres takiego obrazu, a kiedy tylko zostanie odwiedzony, na serwerze zapisane zostaną zachowane dane na temat odwiedzającego.

Realizacja

Postawmy cel:

Stworzyć skrypt, którego adres url i zachowanie będą wyglądały jak zwykły adres obrazu .png, który zbierze informacje na temat odwiedzającego.

Dlaczego jest to możliwe?

Ze względu na framework rewrite engine dostarczany przez serwery www. Pozwala on upiększać adresy url. Jest to mechanizm bardzo często używany, głównie ze względu na optymalizację strony pod względem silników wyszukiwarek internetowych. Dokładniejszy opis mod_rewrite można znaleźć w tym poście na addbytes.com.

Jak zastosujemy ten mechanizm w realizacji celu?

Pod adresem https://michalp.net/open projects/track/*.png zastąpienie gwiazdki dowolnym ciągiem znaków ma zakończyć się wyświetleniem obrazka. W trakcie wczytywania skrypt powinien zapisać do pliku ciąg podany jako nazwa pliku oraz wszystkie informacje środowiskowe serwera.

Etap 1 - reguły mod_rewrite w pliku .htaccess

Serwer z zainstalowanym modułem przepisywania (RewriteEngine) adresów, który otrzyma zapytanie o zasób musi wykonać sprawdzenie reguł. Pierwszym miejscem, które zostanie przeszukane będzie rekord VirtualHost w konfiguracji głównej (tym aspektem nie będziemy się zajmować). Kolejnym, interesującym nas miejscem, jest plik .htaccess, znajdujący się w katalogu, do którego odnosi się zapytanie. Proponuję następującą regułę przepisywania adresów:

RewriteEngine On
RewriteBase "/open projects/track/"

RewriteRule ^([A-z0-9]+).png$ tracker.py?id=$1 [L]

Uwaga: Plik .htaccess powinien kończyć się pustą linią (znakiem końca linii) aby został prawidłowo odczytany przez webserwer.

Pierwsza linia skryptu wskazuje serwerowi, że należy uruchomić RewriteEngine. Kolejna wskazuje katalog bazowy, w którym serwer ma szukać plików, które faktycznie będą realizowały odpowiedź na otrzymane zapytania. Ostatnia zapisana linia jest najważniejsza. Zawiera ona polecenie RewriteRule rozpoczynające regułę przepisywania adresów. Pierwszym argumentem jest wyrażenie regularne, które jest swoistym szablonem nazwy. Znak ^ informuje, że ciąg powinien rozpoczynać się od ([A-z0-9]+) czyli dowolnie długiego ciągu alfanumerycznego. Przepisaniu ulegną tylko takie adresy, w których nasz dowolnie długi ciąg alfanumeryczny zakończony będzie przez .png. Znak $ oznacza dokładnie tyle, że w tym miejscu ciąg musi się kończyć. Wspomniany już post opisuje dokładniej wyrażenia regularne w .htaccess.

Drugim argumentem reguły jest plik docelowy. Wiemy już, że jest to skrypt znajdujący się w katalogu “/open projects/track/”. Oznaczenie $1 odzwierciedla ciąg, który został wychwycony przez wyrażenie regularne ([A-z0-9]+). Jeśli zatem odwiedzimy adres https://michalp.net/open projects/track/abcd123.png w rzeczywistości odwiedzimy adres https://michalp.net/open projects/track/tracker.py?id=abcd123 nie będąc świadomymi tego faktu.

Ostatni argument jest mniej istotny, zabezpiecza nas jedynie przed stosowaniem kolejnych reguł w stosunku do tego pliku.

Etap 2 - skrypt obsługujący zapytanie

Dzięki mechanizmom przepisywania adresów umiemy zamaskować faktyczny adres skryptu. Przystąpimy teraz do jego przygotowania. Najprostszy mechanizm, który jedynie otworzy znajdujący się na serwerze plik i udostępni go klientowi wygląda następująco:

#!/usr/bin/python

print "Content-type: image/png\n"
print open("logo.png", "rb").read()

Po wysłaniu zapytania skrypt wysyła nagłówek informujący o typie zawartości (zgodnym z rozszerzeniem pliku) a następnie zawartość pliku graficznego. Jedyne o czym należy pamiętać to by nazwać skrypt zgodnie z nazwą użytą w .htaccess i nadać mu uprawnienia wykonywania.

Taka forma funkcjonuje, jednak nie daje nam żadnej informacji o odwiedzającym. Rozszerzmy skrypt o zapisywanie nazwy pliku, z jakiej uruchomiono skrypt.

#!/usr/bin/python
import cgi
form = cgi.FieldStorage()

with open(".log", "a") as logfile:
    logfile.write("Odwiedziny z nazwy: " + form.getvalue('id') + "\n")
	
	
print "Content-type: image/png\n"
print open("logo.png", "rb").read()

Do rozszerzenia użyliśmy modułu CGI, dzięki któremu przechwyciliśmy parametry, z jakimi uruchomiony został skrypt. Po wywołaniu otworzy on w trybie dopisywania plik .log, do którego każdorazowo dopisze nazwę pliku.

Zbieramy już pewne informacje o odwiedzających, jednak ich ilość może być znacznie większa. Poniższy przykład przedstawia udoskonalenie, które poza nazwą pliku zapisuje jeszcze datę odwiedzin oraz informację o zmiennych środowiskowych serwera:

#!/usr/bin/python
import cgi
import os
import time

def currentTime():
    return time.strftime("%H:%M:%S")+" "+time.strftime("%d/%m/%Y")

form = cgi.FieldStorage()

with open(".log", "a") as logfile:
    logfile.write(currentTime())
    logfile.write(" - id: "+form.getvalue('id'))
    for p in os.environ.keys():
        logfile.write(", "+p+": "+os.environ[p])
    logfile.write("\n")
	
print "Content-type: image/png\n"
print open("logo.png", "rb").read()

Do odczytu zmiennych środowiskowych zaimportowaliśmy moduł os, natomiast time oczywiście do odczytu aktualnego czasu. W celu poprawienia czytelności kodu generowanie czasu odwiedzin oddzieliłem do odrębnej funkcji currentTime(). W bloku dopisującym dane do logu zauważamy również iterację przez słownik zmiennych środowiskowych.

Efekt końcowy:

Podsumowanie

Przedstawione powyżej studium przypadku przybliżyło mechanizmy mod_rewrite oraz pokazało jak do pracy w trybie CGI zaprzęgnąć język Python. Przykład jest dość prymitywny, logowanie danych można oddelegować do bazy danych a generowanie indywidualnych obrazów śledzących należałoby obsłużyć za pomocą panelu administracyjnego.

Osoby chcące poszerzyć swoją wiedzę na temat języka python odsyłam na guru99.