Des del 2000 compartiendo sobre…

Tag: security

Secure download URLs with expiration time

Reading time: 4 – 6 minutes


Imagine a HTTP server with those restrictions:

  • only specific files can be downloaded
  • with a limited time (expiration date)
  • an ID allows to trace who download files
  • with minimal maintenance and dependencies (no databases, or things like that)

the base of the solution that I designed is the URL format:

  • signature: is calculated with the next formula, given a “seed”
    • seed = “This is just a random text.”
    • str = customer_id + expire_date + path_n_file
    • signature = encode_base64( hmac_sha1( seed, str))
  • customer_id: just an arbitrary identifier when you want to distinguish who use the URL
  • expire_date: when the generated URL stops working
  • path_n_file: relative path in your private repository and the file to share

Understanding the ideas explained before I think it’s enough to understand what is the goal of the solution. I developed the solution using NGINX and LUA. But the NGINX version used is not the default version is a very patched version called Openresty. This version is specially famous because some important Chinese webs works with that, for instance, Taobao.com

Expiration URL solution Architecture schema

In the above schema there is a master who wants to share a file which is in the internal private repository, but the file has a time restriction and the URL is only for that customer. Then using the command line admin creates a unique URL with desired constrains (expiration date, customer to share and file to share). Next step is send the URL to the customer’s user. When the URL is requested NGINX server evaluates the URL and returns desired file only if the user has a valid URL. It means the URL is not expired, the file already exists, the customer identification is valid and the signature is not modified.

NGINX Configuration

server {
 server_name downloads.local;

 location ~ ^/(?<signature>[^/]+)/(?<customer_id>[^/]+)/(?<expire_date>[^/]+)/(?<path_n_file>.*)$ {
 content_by_lua_file "lua/get_file.lua";

 location / {
 return 403;

This is the server part of the NGINX configuration file, the rest of the file can as you want. Understanding this file is really simple, because the “server_name” works as always. Then only locations command are relevant. First “location” is just a regular expression which identifies the relevant variables of the URL and passes them to the LUA script. All other URLs that doesn’t match with the URI pattern fall in path “/” and the response is always “Forbiden” (HTTP 403 code). Then magics happen all in LUA code.

LUA scripts

There are some LUA files required:

  • create_secure_link.lua: creates secure URLs
  • get_file.lua: evaluates URLs and serves content of the required file
  • lib.lua: module developed to reuse code between other lua files
  • sha1.lua: SHA-1 secure hash computation, and HMAC-SHA1 signature computation in Lua (get from https://github.com/kikito/sha.lua)

It’s required to configure “lib.lua” file, at the beginning of the file are three variables to set up:

lib.secret = "This is just a long string to set a seed"
lib.base_url = "http://downloads.local/"
lib.base_dir = "/tmp/downloads/"

Create secure URLs is really simple, take look of the command parameters:

$ ./create_secure_link.lua 

 ./create_secure_link.lua <customer_id> <expiration_date> <relative_path/filename>

Create URLs with expiration date.

 customer_id: any string identifying the customer who wants the URL
 expiration_date: when URL has to expire, format: YYYY-MM-DDTHH:MM
 relative_path/filename: relative path to file to transfer, base path is: /tmp/downloads/

Run example:

$ mkdir -p /tmp/downloads/dir1
$ echo hello > /tmp/downloads/dir1/example1.txt
$ ./create_secure_link.lua acme 2015-08-15T20:30 dir1/example1.txt
$ date
Wed Aug 12 20:27:14 CEST 2015
$ curl http://downloads.local:55080/YjZhNDAzZDY0/acme/2015-08-15T20:30/dir1/example1.txt
$ date
Wed Aug 12 20:31:40 CEST 2015
$ curl http://downloads.local:55080/YjZhNDAzZDY0/acme/2015-08-15T20:30/dir1/example1.txt
Link expired

Little video demostration


Disclaimer and gratefulness



pfSense: unlock SSH

Reading time: < 1 minute After several tries without success to pfSense's SSH server the port is blocked by a service called "sshlockout". If you need to unblock the SSH service run the command from shell:

pfctl -t sshlockout -T flush

In the end that command only removes the rules in table “sshlockout” in firewall entries.

OpenAM: some ssoadm commands for reference

Reading time: 3 – 4 minutes

OpenAM is as much powerful as complicated sometimes. In this case I spent a lot of time understanding how to set simple settings because of that I decide to take note about that in this blog entry.

First of all don’t forget to set the environment variables and go to ssoadm path:

export JAVA_HOME="/usr/lib/jvm/java-6-openjdk-amd64/jre"
export CLASSPATH="/var/lib/tomcat7/webapps/openam/WEB-INF/lib/policy-plugins.jar::/var/lib/tomcat7/webapps/openam/WEB-INF/lib/openam-core-11.0.0.jar"

cd /opt/openam/ssoadmin/openam/bin

Getting the list of user identities:

./ssoadm list-identities -u amadmin -f /tmp/oam.pwd -e / -t User -x "*"

anonymous (id=anonymous,ou=user,dc=openam)
demo (id=demo,ou=user,dc=openam)
serviceusername (id=serviceusername,ou=user,dc=openam)
amAdmin (id=amAdmin,ou=user,dc=openam)
Search of Identities of type User in realm, / succeeded.

another useful query would be:

./ssoadm list-identities -u amadmin -f /tmp/oam.pwd -e / -t Role -x "*"

No plug-ins configured for this operation

But as you can see it doesn’t work and I don’t know how to solve it.

Taking a look to GUI get to identities list with: Access Control > / (Top Level Realm) > Privileges

In this webpage you have a list of role identities, in my case I have only this: “All Authenticated Users”. Inside this identity I can set different privileges:

  • REST calls for Policy Evaluation (EntitlementRestAccess)
  • Read and write access to all log files (LogAdmin)
  • REST calls for searching entitlements (PrivilegeRestReadAccess)
  • Read access to all log files (LogRead)
  • Read and write access to all federation metadata configurations (FederationAdmin)
  • Read and write access only for policy properties (PolicyAdmin)
  • Read and write access to all configured Agents (AgentAdmin)
  • Read and write access to all realm and policy properties (RealmAdmin)
  • REST calls for managing entitlements (PrivilegeRestAccess)
  • Write access to all log files (LogWrite)

If we want to remove a privilege:

root@vm:/opt/openam/ssoadmin/openam/bin# ./ssoadm remove-privileges -u amAdmin -f /tmp/oam.pwd -e / -g EntitlementRestAccess -i "All Authenticated Users" -t role

Privileges were removed from identity, All Authenticated Users of type, role in realm, /.

or adding a privilege:

root@vm:/opt/openam/ssoadmin/openam/bin# ./ssoadm add-privileges -u amAdmin -f /tmp/oam.pwd -e / -g EntitlementRestAccess -i "All Authenticated Users" -t role

Talking about policies, exporting:

./ssoadm list-policies -u amadmin -f /tmp/oam.pwd -e / -o /tmp/policies.xml

and if we want to import the policies:

./ssoadm create-policies -u amAdmin -f /tmp/oam.pwd -e / --xmlfile /tmp/policies.xml

creating a user:

./ssoadm create-identity -u amadmin -f /tmp/oam.pwd  -e / -i serviceusername -t User --attributevalues "userpassword=servicepassword"

Useful references:

sslsnoop – hacking OpenSSH

Reading time: < 1 minute Using sslsnoop you can dump SSH keys used in a session and decode ciphered traffic. Supported algorithms are: aes128-ctr, aes192-ctr, aes256-ctr, blowfish-cbc, cast128-cbc. Basic sslsnoop information:

 $ sudo sslsnoop # try ssh, sshd and ssh-agent… for various things
 $ sudo sslsnoop-openssh live `pgrep ssh` # dumps SSH decrypted traffic in outputs/
 $ sudo sslsnoop-openssh offline –help # dumps SSH decrypted traffic in outputs/ from a pcap file
 $ sudo sslsnoop-openssl `pgrep ssh-agent` # dumps RSA and DSA keys

Take a look into the project in sslsnoop github page.

Routerboard CRS125-24G-1S-2HnD-IN (Mikrotik) Cloud Switch

Reading time: 1 – 2 minutes

I bought this product a few weeks ago and finally I can enjoy it at home. With this product you have a firewall, gateway, switch and wireless box with:

  • 25x Gigabit Ethernet ports
  • 1x Fiber channel
  • 3G, 4G or any optional USB modem
  • With RouterOS inside you can manage: gateway, firewall, VPN and ad-hoc switching and routing configurations
  • 1000mW high power 2.4GHz 11n wireless AP


The official product page is here where you can find brochure in PDF and other useful information.

If you are looking for a powerful product for your SOHO network this is the solution as I like to say ‘this is one of the best communications servers’. It will be very difficult to find some feature or functionality that you can not get from this product. The product is robust and stable with the flexibility of RouterOS.

Screencast 0x01 – Com funciona OAuth?

Reading time: 1 – 2 minutes

Després de la primera prova pilot amb el tema dels screencast presento aquesta altre entrega en la mateixa línia de la primera però amb un tema una mica més interessant i difícil d’explicar. Per si no ús sona de res OAuth, comentar que és un sistema d’autorització d’accés a una API per part d’aplicaicons i d’aplicacions web. Compte, en si mateix OAuth no és un sistema d’autenticació sinó d’autorització, si no teniu clars aquests conceptes: wikipedia: authentication vs authorization.

Bé ja em comentareu si algú ha pogut entendre algo, he de dir que m’hi he esforçat força en simplificar el tema i no ha estat fàcil fer-ho.

Prey – rastrejar el portàtil i el lladre

Reading time: 2 – 4 minutes

prey logoQuan ens roben el portàtil l’únic que ens queda fer és resar perquè siguem realistes, és molt poc provable que la policia el trobi. Així doncs, el que preten fer prey és enviar-nos tota la informació possible del portàtil després de que ens l’hagin robat.

El seu funcionament és força simple, però al mateix temps s’ha de dir que la idea sembla força eficient. En la versió per linux es tracta d’un script fet amb perl que es col·loca al crontab, de forma que cada x’s minuts es connecta a una URL del servidor de prey o del nostre propi servidor. Aquest URL sovint respon dient que tot va bé, és a dir, que el portàtil no ha estat marcat com a robat. En cas contrari, el servidor respon via HTTP dient que el dispositiu ha estat robat. En aquest moment és quan l’script es posa a treballar i es posa a recollir tot tipus d’informació per reportar-la a la pàgina web:

  • geolocalització per GPS o Wifi, si no disposem de GPS. He provat la localització per wifi i va força bé.
  • fa fotos amb la webcam del portàtil i captures de pantalla
  • reporta tota la informació que pot sobre processos que hi ha corrent al sistema, rutes, informació de les wifis veïnes, etc.
  • també podem fer sonar alarmes, borrar informació remotament, que ens enviï alguns arxius abans de ser borrats,etc.
  • a més els reports que es van reben queden arxivats en una interficie força amigable i molt senzilla d’usar
  • a més el software d’auto-actualitza

La compte gratuïta que ofereix la pàgina web permet tracejar fins a 3 dispositius, obviament si usem el nostre propi servidor HTTP podrem tracejar tots els dispositius que volem. Si volem usar més dispositius haurem d’adquirir una compte professional que tampoc sembla massa cara: per exemple, la més econòmica és la de 12€/mes que permet controlar fins a 10 dispositius amb un màxim de 25 informes per cada dispositiu.

Jo he provat la versió de Windows i la de Linux i ambdues m’han funcionat força bé a la primera, però pel que posa a la web també tenen la versió de Mac i la d’Android. Aquest última diria que és molt nova. Malgrat això en els meus dos Androids no uso prey sinó que uso WaveSecure. Pensat especialment per a dispostius mòbils, ja que tenen versions per: Blackberry, Symbian, Windows phone, Java i Android, és clar.

PAM (Pluggable Authentication Modules)

Reading time: 2 – 2 minutes

Amb les quatre notes que adjunto en aquest article es preten tenir una guia per tal de poder seguir i entendre els fitxers de configuració associats a PAM.

Quan PAM va associat a un servei aquest té un fitxer de configuració dins de /etc/pam.d sovint amb el mateix nom del servei o quelcom que ens el recorda. Dins de cada fitxer d’aquests es defineixen quatre categories pel procés d’autenticació:

  • auth – autenticació
  • account – gestió d’accés
  • password – quan i com es pot canviar la paraula de pas
  • session – entorn de configuració de l’usuari, accés al seu perfil

No és obligatori definir les quatre categories per tots els serveis, hi ha serveis que amb la categoria auth, en tenen prou. O d’altres que les requereixen totes.
PAM té una selecció de diferents models per cada categoria que s’organitzen en una pila. Cada mòdul esta etiquetat amb el que s’anomena una bandera de control. A través d’aquestes eines és com l’administrador controla el procés d’autenticació dels usuaris sobre els serveis.

Les banderes de control suportades per PAM són:

  • required
  • requisite
  • sufficient
  • optional

Si un mòdul marcat amb required, requisite o sufficient respon de forma negativa es deté l’execusió de la pila de forma inmediata.
Si la resposta és positiva en un mòdul: required, requisite o optional llavors PAM seguirà examinant la resta de mòduls.
Si un mòdul sufficient respon positivament es considera positiva la resposta a tota la categoria que s’esta examinant.

Autenticació PAM/OTP via Apache

Reading time: 4 – 6 minutes

L’autenticació d’Apache coneguda com a AuthBasic malgrat la seva inseguretat és una de les més usades, ja que ens permet de forma senzilla i ràpida protegir un directori o simplement un fitxer. La protecció d’aquest tipus d’autenticació és molt relativa perquè el password viatge en clar a través de la xarxa, a més, al viatjar a les capçaleres HTTP o fins hi tot en la propia URL de la pàgina pot arribar a ser indexat per un navegador.

Seguint la línia dels anteriors articles:

Ara el que toca és afegir a l’Apache aquest tipus d’autenticació de forma que podem donar les credencials d’accés a un directori/fitxer a algú però aquestes caducaran al cap del temps (uns 3 minuts) i els buscadors o d’altres agents amb més mala idea no podran accedir al recurs passat aquest temps. Com sempre la idea és la d’aprofitar-se del PAM/OTP.

En primera instància per aconseguir això ho he intentat amb el mòdul libapache2-mod-auth-pam però no n’he tret l’entrellat i he estat incapaç de completar la configuració. Així doncs, el que he fet és provar amb el mòdul libapache2-mod-authnz-external ambdós disponibles en l’Ubuntu 8.04 (Hardy). Aquest segon mòdul l’he combinat amb el checkpassword-pam.

Així doncs, la idea és ben senzilla configurem l’Apache perquè usi el libapache2-mod-authnz-external, en escència el que fa aquest mòdul és recolzar-se en agents externs per fer l’autenticació. Aquest agent extern és el checkpassword-pam que comentava i que com diu el seu nom el que fa és validar el password contra PAM, així doncs, malgrat no és una solució massa eficient a nivell de recursos ja que ha de carregar un segon programa per validar cada usuari considero que és una solució suficienment bona pel meu cas.

La configuració

Instal·lem el mòdul d’apache i l’activem:

apt-get install libapache2-mod-authnz-external
a2enmod authnz_external
/etc/init.d/apache2 restart

Instal·lació del checkpassword-pam

cd /var/tmp
wget "http://downloads.sourceforge.net/project/checkpasswd-pam/checkpasswd-pam/0.99/checkpassword-pam-0.99.tar.gz?r=http%3A%2F%2Fsourceforge.net%2Fprojects%2Fcheckpasswd-pam%2F&ts=1284649515&use_mirror=ignum"
tar xvfz checkpassword-pam-0.99.tar.gz
cd checkpassword-pam-0.99
mkdir -p /opt/checkpassword-pam
cp checkpassword-pam /opt/checkpassword-pam

Fitxer de configuració pel servei apache2 del PAM, /etc/pam.d/apache2:

auth    sufficient      pam_script.so onerr=fail dir=/etc/pam-script.d/
account  required       pam_script.so onerr=fail dir=/etc/pam-script.d/

Si us hi fixeu aquest fitxer és igual al que vaig usar per fer l’autenticació en l’article de PHP i PAM/OTP.

Ara anem a un dels fitxers de configuració d’Apache per un virtualhost i afegim el següent codi per protegir un directori servit per aquest virtualhost:

<Directory /var/www/virtualhost/directori_a_protegir>
  AuthType Basic
  AuthName "Restricted area for My Server"
  require user nom_usuari
  AuthBasicProvider external
  AuthExternal autenticador
AddExternalAuth autenticador "/opt/checkpassword-pam/checkpassword-pam -H --noenv -s php -- /bin/true"
SetExternalAuthMethod autenticador checkpassword

Coses importants a destacar en aquest configuració, fixeu-vos que em cal afegir ‘require user nom_usuari’, això és perquè no disposo de cap fitxer d’usuaris on Apache pugui validar quins són els meus usuaris vàlids i la directiva ‘require valid-users’ no funcionaria, així doncs, hem d’especificar quins usuaris podran fer login a través d’aquesta comanda, o bé, afegir una altre directiva que li permiti a Apache trobar un llistat d’usuaris en algún lloc.

Un altre detall important són els paràmetres que he d’usar al checkpasswords-pam perquè aquest funcioni bé:

  • -H no intenta fer un ‘chdir-home’ ja que potser l’usuari no disposa d’aquest ‘home directory’.
  • –noenv el checkpassword-pam busca certes variables d’entorn per funcionar, amb aquest paràmetre no les busca i agafa el que li cal del stdin.
  • -s apache2 especifica el nom del servei que buscarà dins de /etc/pam.d/apache2
  • — /bin/true simplement serveix perquè el checkpassword-pam no faci res després de validar un usuari, ja que podriem executar algún programa si volguessim després de fer la validació.


Autenticació PAM/OTP via PHP

Reading time: 2 – 3 minutes

Una bona forma de continuar aprofindint amb el tema OTP i també amb PAM, després de l’article: Shellinabox i OTP, és explicar-vos com m’ho he fet per afegir suport OTP al PHP, de forma que quan programem amb PHP es pugui delegar l’autenticació al sistema PAM del linux. Obviament això té certes restriccions perquè PHP corre amb els permisos de l’usuari de l’Apache, o bé, de l’usuari del FSGI, etc. L’important de fer notar és que no és habitual llençar codi PHP amb permisos de ‘root’. Així doncs, depèn de quina acció li fem fer al PAM aquest no la podrà dur a terme, per exemple, no podrà accedir al fitxer /etc/shadow per validar el password de sistema. De fet, com que el que jo vull és treballar amb OTP això no és rellevant.

El primer que s’ha de fer és instal·lar el paquet php5-auth-apm i reiniciar l’Apache:

apt-get install php5-auth-pam
/etc/init.d/apache2 restart

Ara anem al directori /etc/pam-script.d i fem:

cd /etc/pam-script.d
rm pam_script_acct
# creem fitxer pam_script_acct
echo '#!/bin/sh' > pam_script_acct
echo 'exit 0' >> pam_script_acct
chmod 755 pam_script_acct

Ara toca crear el fitxer /etc/pam.d/php, amb el següent contingut:

auth    sufficient      pam_script.so onerr=fail dir=/etc/pam-script.d/
account  required       pam_script.so onerr=fail dir=/etc/pam-script.d/

Amb això ja en tenim prou per anar a jugar amb el php, el primer és amb un phpinfo(); validar que apareix algo així:

i després podem fer un codi tan senzill com aquest:


La comanda clau com podeu veure és pam_auth, passeu com a paràmetre el nom de l’usuari, el password que ús ha donat la vostre aplicació generadora de passwords OTP i la variable que voleu que reculli els errors la passeu per referencia. En cas d’error de l’autenticació aquesta comanda contindrà la descripció de l’error. Aquesta mateixa funció retorna un codi boleà amb el resultat de l’autenticació.