security – Sam & Max http://sametmax.com Du code, du cul Wed, 30 Oct 2019 15:34:04 +0000 en-US hourly 1 https://wordpress.org/?v=4.9.7 32490438 Quelques outils pour gérer les clés secrètes en Django http://sametmax.com/quelques-outils-pour-gerer-les-cles-secretes-en-django/ http://sametmax.com/quelques-outils-pour-gerer-les-cles-secretes-en-django/#comments Thu, 23 Feb 2017 15:05:16 +0000 http://sametmax.com/?p=22504 On ne veut pas mettre sa SECRET_KEY en prod, et utiliser un service pour générer la clé, ça va deux minutes.

Générer une clé secrète:

import random
import string

def secret_key(size=50):
    pool = string.ascii_letters + string.digits + string.punctuation
    return "".join(random.SystemRandom().choice(pool) for i in range(size))

Générer une clé secrete avec une commande manage.py:

from django.core.management.base import BaseCommand, CommandError
from polls.models import Question as Poll

class Command(BaseCommand):
    help = 'Generate a secret key'

    def add_arguments(self, parser):
        parser.add_argument('size', default=50, type=int)

    def handle(self, *args, **options):
        self.stdout.write(secret_key(options['size']))

A mettre dans ./votreapp/management/command/generate_secret_key.py :)

Une fonction pour lire la clé depuis un fichier texte ou générer la clé si elle n’existe pas:

import io
import os

try:
    import pwd
except ImportError:
    pass

try:
    import grp
except ImportError:
    pass


def secret_key_from_file(
        file_path, 
        create=True, 
        size=50, 
        file_perms=None, # unix uniquement
        file_user=None, # unix uniquement
        file_group=None # unix uniquement
    ):
    try:
        with io.open(file_path) as f:
            return f.read().strip()
    except IOError as e:
        if e.errno == 2 and create:
            with io.open(file_path, 'w') as f:
                key = secret_key(size)
                f.write(key)

            if any((file_perms, file_user, file_group)) and not pwd:
                raise ValueError('File chmod and chown are for Unix only')

            if file_user:
                os.chown(file_path, uid=pwd.getpwnam(file_user).pw_uid)

            if file_group:
                os.chown(file_path, gid=grp.getgrnam(file_group).gr_gid)

            if file_perms:
                os.chmod(file_path, int(str(file_perms), 8))

            return key

        raise

Et une fonction pour récupérer la clé depuis une variable d’environnement ou un fichier:

def get_secret_key(
        file_path=None, 
        create=True, 
        size=50, 
        file_perms=None, 
        file_user=None, 
        file_group=None,
        env_var="DJANGO_SECRET_KEY"
    ):
    try:
        return os.environ[env_var]
    except KeyError:
        if file_path:
            return secret_key_from_file(file_path, create=create, size=size)
        raise

Le but de cette dernière est d’avoir ça dans son fichier de settings:

SECRET_KEY = get_secret_key('secret_key')

Et de foutre ‘secret_key’ dans son .gitignore.

Comme ça:

  • Si on n’a pas de clé secrète, on en génère une.
  • Si on a une, elle est dans un fichier qui n’est PAS dans settings.py.
  • On peut commiter settings.py. Chaque env de dev et prod a sa clé secrète automatiquement.
  • On peut overrider la clé avec une variable d’environnement si on le souhaite.

En attendant, j’ai proposé qu’on ajoute ça a django extensions. Et qui sait, dans le core peut être un jour ?

]]>
http://sametmax.com/quelques-outils-pour-gerer-les-cles-secretes-en-django/feed/ 10 22504
Desactiver la validation des mots de passe en mode DEBUG sous Django http://sametmax.com/desactiver-la-validation-des-mots-de-passe-en-mode-debug-sous-django/ http://sametmax.com/desactiver-la-validation-des-mots-de-passe-en-mode-debug-sous-django/#comments Fri, 08 Jan 2016 10:29:10 +0000 http://sametmax.com/?p=17508 Django 1.9 rajoute la validation de “sécurité” des mots de passe comme corde à son arc.

Personnellement je trouve ça naze.

Je suis pour permettre aux utilisateurs de mettre le password qu’ils veulent, même tout pourri. De toute façon les gens qui ne font pas attention à leur sécurité ne vont jamais se souvenir du mot de passe compliqué et faire un « j’ai oublié mon mot de passe » à chaque fois.

Pire, la complexité ajoutée va faire fuir les nouveaux utilisateurs qui ne vont pas vouloir se faire chier à remplir le formulaire. Ou alors ils vont faire « login with facebook ».

Mais le plus naze dans tout ça c’est que la validation est tout ou rien : on peut pas mettre de la validation juste pour les comptes admin par exemple. Ce qui aurait du sens.

Alors, oui à la mise en oeuvre d’un indicateur de force de mot de passe, mais pas un refus catégorique de s’inscrire comme le système actuel le fait.

Dans tous les cas, vous voudrez au moins le désactiver en mode DEBUG car devoir taper un mot de passe compliqué en dev sur votre machine en local pour accéder à une base de données sqlite de test, c’est relou.

Car oui, ./manage.py createsuperuser refuse votre password si il n’est pas “sécurisé” par défaut. En prod, ça a du sens, mais quand je veux tester une merde sur mon laptop, “admin/admin” est généralement ce je veux.

Donc:

AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
        'OPTIONS': {
            'min_length': 9,
        }
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]

if DEBUG:
    AUTH_PASSWORD_VALIDATORS = []

Enfin, franchement, un validateur de mot de passe basé sur la présence de chiffres. Sérieux ? On a des validateurs basés sur une entropie générale depuis longtemps.

]]>
http://sametmax.com/desactiver-la-validation-des-mots-de-passe-en-mode-debug-sous-django/feed/ 4 17508
On a tenté de nous hacker 0bin http://sametmax.com/on-a-tente-de-nous-hacker-0bin/ http://sametmax.com/on-a-tente-de-nous-hacker-0bin/#comments Sun, 20 Dec 2015 09:36:38 +0000 http://sametmax.com/?p=17160 En me baladant dans l’arbo de 0bin.net pour retirer un dox qu’on m’avait signalé je suis tombé sur un dossier au nom bizarre :

# ls -l
total 4
4 drwxr-xr-x 7 root root 4096 sept. 24  2014 --

Hum, voilà qui n’est pas pratique à analyser depuis le bash. Et pourquoi j’ai ce dossier-là d’ailleurs ?

Regardons ce qu’il y a dedans :

# python -c "import os; os.rename('--', "strange_dir")"
# ls strange_dir/
3Q  Dk  k5  Oh  -u

Oh, y a un dossier nommé “-u”…

A ce stade-là, j’ai juste supprimé le truc.

Et j’ai réalisé : on crée les dossiers de l’arbo en fonction du nom du paste, qui est une clé générée côté client, et donc fournie par un code JavaScript non trusté.

Du coup l’attaqueur nous a sans doute passé une commande bash comme nom de fichier. J’imagine, espérant qu’on fabriquait le fichier avec une exécution shell. Comme on utilise le module os pour le faire, je pense que ça n’a eu aucun impact.

J’espère :)

]]>
http://sametmax.com/on-a-tente-de-nous-hacker-0bin/feed/ 8 17160