Ça dépend comment c’est fait. La méthode classique aujourd’hui c’est d’avoir un sel aléatoire pour chaque hash, et du coup, le sel est stocké dans le hash, par exemple en utilisant le format MCF ou PHC, puisqu’il y en a besoin pour ensuite vérifier le hash.
Voilà par exemple 3 hash d’un même mot de passe avec la fonction password_hash de PHP, le premier en imposant le sel, les deux autres en laissant password_hash tirer un sel aléatoire :
$2y$10$012345678901234567890uHIlLXgSTdYTWM7ZF7pewbPCpXRHjYFa
$2y$10$SGPegcCvoy.8RKPVvnP0EeGFD.58VCyBWWeokVeVKR9/LRkXjbXM2
$2y$10$xbAW5sdbQOQWSDQqpQXSI.F8ym8BJFNdJIOXLAXcHj0N1wLrSomcK
C’est ça qui est ensuite stocké en base. Pour vérifier le hash, il suffit d’appeler password_verify avec le mot de passe à vérifier et le hash, aucune autre info à fournir, parce que le hash est autoportant : $2y$10$ ça indique l’algorithme utilisé et ses paramètres (2y, c’est l’implémentation de bcrypt de PHP, 10 c’est la valeur de coût), ensuite, dans le cas de bcrypt, les 22 caractères suivants sont le sel (qui doit faire 22 caractères base64 exactement, si on met un sel plus court il le refuse, si on met un sel plus long il le tronque, si on met un sel contenant des caractères n’existant pas en base64 il le convertit en base 64 et garde les 22 premiers caractères résultats), et le reste c’est le « vrai » hash du mot de passe salé.
Du coup, celui qui a réussi à voler la base de données, il a aussi les sels.
Par contre, à moins d’avoir utilisé le même sel partout (ce qui serait une grosse ânerie… au point que dans PHP ils ont maintenant carrément retiré l’option sel de password_hash, ça génère d’office un sel aléatoire), et c’est là que le sel joue son rôle de complexification, même s’il est connu : le brute force doit être fait indépendamment sur chaque mot de passe de la base de données.
Alors que s’il n’y a pas de sel ou un sel identique sur tous les mots de passe, le brute force peut s’appliquer à tous les mots de passe de la base en même temps.
Pour que le sel empêche complètement le brute force, il faut que l’attaquant n’ait pas connaissance du sel. Ça peut se faire en ayant par exemple un sel qui est lui même calculé à partir du mot de passe, mais ça complexifie le code.
Par exemple, en PHP, au lieu de faire simplement password_hash($pass) / password_verify($pass, $hash), tu peux faire password_hash($salted_pass) / password_verifiy($salted_pass, $hash) en calculant au préalable le mot de passe salé avec une autre méthode (par exemple, $salted_pass pourrait être un hash de mot de passe salé avec l’identifiant du compte). Là tu bloques effectivement le brute force… à condition que ton attaquant n’ait pas eu accès à ton code pour voir comment tu sales…