Search code examples
djangoadminmd5

Change the default md5 salting of django


I want to change the salting of md5 to be the same as the one I defined in my apapplication. That way I will be able to create users via the django administration page for those who have the same salting as those who will register in my application. Here is my settings.py

# Password hashers

PASSWORD_HASHERS = [
    'django.contrib.auth.hashers.MD5PasswordHasher',
]

My forms.py

SEL = 'TD-TP 430';
class InscriptionForms(forms.Form):
    # code here
    # Pour valider le champ Mot de passe
    def clean_mdp(self):
        mdp = self.cleaned_data['mdp'];

        if len(mdp) == 0:
            raise forms.ValidationError(
                ("Mot de passe ne peut etre vide."),
                code='Mot_de_passe_vide'
                );
        else:
            validate_password(mdp);
            mdp_crypte_md5  = make_password(password=mdp, salt=SEL, hasher='md5');
            return mdp_crypte_md5;

class ConnexionForms(forms.Form):
    # code here
    # Pour de le mot de passe
    def clean_mdp(self):
        mdp     = self.cleaned_data['mdp'];

        if len(mdp) == 0:
            raise forms.ValidationError(
                ("Mot de passe incorrect."),
                code='Mot de passe_est_vide'
                );
        else:
            mdp_crypte_md5  = make_password(password=mdp, salt=SEL, hasher='md5');
            return mdp_crypte_md5;

views.py

SEL = 'TD-TP 430'

# La page index qui est la page de connexion de site.
def index(request):

    if request.method == 'POST':

        connexion_form = ConnexionForms(request.POST);
        if connexion_form.is_valid():
            identifiant = connexion_form.clean_identifiant();
            mdp         = make_password(password=request.POST.get('mdp'), salt=SEL, hasher='md5')
            user        = authenticate(username=identifiant, password=mdp);
            if user is not None:
                login(request, user)
                 # ....

def inscription(request):

    if request.method == 'POST':    # S'il s'agit d'une requete "post" pour se connecter

        inscription_form        = InscriptionForms(request.POST);
        if inscription_form.is_valid():
            #....
            mdp             = inscription_form.clean_mdp();

            """ Créons le niveau de l'étudiant. pour cela nous devons obtenir l'identifiant de la filière 
                de ce dernier  """
            #id_filiere      = list(Filiere.objects.filter(nom_filiere=filiere).values_list('id', flat=True));
            fil             = Filiere.objects.get(nom_filiere=filiere);
            niv             = Niveau.objects.create(niveau=niveau, filiere=fil);

            # Créons l'utilisateur dont hérite l'étudiant
            utilisateur     = User.objects.create(username=nom_utilisateur, first_name=prenom,last_name=nom, \
                                email=mail, password=mdp);

            #Créons l'étudiant en question
            Etudiant.objects.create(matricule_etudiant=matricule, user=utilisateur, numero_tel=tel, \
                                niveau=niv);

            return redirect('index');
           #....

When I create an user via the django administration page I get a salting which is different of 'SEL'. I want that the users created via the django administration page have the same salting as those who will register in my application.


Solution

  • First of all, please start writing Python rather than whatever other language you are trying to write here. Python lines don't end with semicolons, and the way to test if a variable is empty is to do if not <var>.

    Second, stop using MD5. As I mentioned, it's horribly insecure and its vulnerabilities have been known for years. There shouldn't be any reason to be using it in your own code. And you're making it much much worse by using a static salt; the whole point of a salt is that it's different each time, to prevent the use of rainbow tables.

    Thirdly, you should never call the clean_ methods directly. Get the data from the form.cleaned_data dict - eg mdp = inscription_form.cleaned_data['mdp'].

    And finally, just stop doing all of this. All you have succeeded in doing is bypassing the things that Django does for you, making your code much less secure, maintainable and usable. There's no reason, for example, to call make_password in your clean_mdp method; even less reason to then call it again in the view against the raw POST data. Both of these are pointless because that's already what authenticate does; that's the whole point of the auth framework. The reason your login doesn't work is that the result is that the password to be checked is hashed twice.

    And similarly, when you're creating the user, don't hash the password explicitly; pass the unhashed version to user.set_password, or just call User.objects.create_user in the first place.

    So. Remove your forms' clean_mdp methods. Remove the PASSWORD_HASHERS setting. Remove that SEL constant. The login view should be:

        if connexion_form.is_valid():
            identifiant = connexion_form.cleaned_data['identifiant']
            mdp         = connexion_form.cleaned_data['mdp']
            user        = authenticate(username=identifiant, password=mdp)
            if user is not None:
                login(request, user)
    

    and your signup view should be:

        if connexion_form.is_valid():
            mdp         = connexion_form.cleaned_data['mdp']
            ...
            utilisateur  = User.objects.create_user(username=nom_utilisateur, first_name=prenom,last_name=nom, \
                                email=mail, password=mdp)
    

    and everything should work.