web-dev-qa-db-fra.com

Comment le navigateur sait-il quand Demander à l'utilisateur de sauvegarder son mot de passe?

Ceci est lié à la question que j’ai posée ici: Comment faire en sorte que le navigateur demande à enregistrer le mot de passe?

C'est le problème: je ne peux pas obtenir mon navigateur pour me demander de sauvegarder le mot de passe pour le site que je développe. (Je parle de la barre qui apparaît parfois lorsque vous soumettez un formulaire sur Firefox, qui dit "Mémoriser le mot de passe pour yoursite.com? Oui/Pas maintenant/Jamais")

C'est super frustrant parce que cette fonctionnalité de Firefox (et de la plupart des autres navigateurs modernes, qui, je l'espère, fonctionnent de manière similaire) semble être un mystère. C'est comme un tour de magie que le navigateur fait, où il regarde votre code, ou ce que vous soumettez, ou quelque chose du genre, et s'il "ressemble" à un formulaire de connexion avec un champ de nom d'utilisateur (ou adresse e-mail) et un mot de passe, il offre sauver.

Sauf dans ce cas, où les utilisateurs ne disposent pas de cette option après avoir utilisé mon formulaire de connexion, ce qui me rend fou. :-)

(J'ai vérifié mes paramètres Firefox - je n'ai PAS dit au navigateur "jamais" pour ce site. Il devrait être incitatif.)

Ma question

Quelles sont les heuristiques utilisées par Firefox pour savoir quand demander à l'utilisateur de sauvegarder? Cela ne devrait pas être trop difficile à répondre, étant donné que cela se trouve dans le code source de Mozilla (je ne sais pas où regarder, sinon je voudrais essayer de le creuser moi-même). Je n'ai pas non plus eu la chance de trouver un article de blog ou une autre note similaire à l'intention des développeurs concernant les développeurs de Mozilla.

(Je répondrais volontiers à cette question pour Safari ou IE; j'imagine que tous les navigateurs utilisent des règles très similaires, donc si je peux le faire fonctionner dans l'un d'eux, cela fonctionnera dans les autres.)

(* Notez que si votre réponse à moi a quelque chose à voir avec les cookies, le cryptage ou toute autre chose qui concerne la façon dont je stocke les mots de passe dans ma base de données locale, il y a de fortes chances pour que vous ayez mal compris ma question. :-)

78
Eric

En me basant sur ce que j'ai lu, je pense que Firefox détecte les mots de passe par form.elements[n].type == "password" (en parcourant tous les éléments du formulaire), puis détecte le champ de nom d'utilisateur en recherchant en arrière le contenu dans les éléments de formulaire juste avant le champ de mot de passe (plus d'infos ici ). Vous pouvez essayer quelque chose de similaire en Javascript et voir si vous pouvez détecter votre champ de mot de passe.

D'après ce que je peux dire, votre formulaire de connexion doit faire partie d'un <form> sinon Firefox ne le détectera pas. Définir id="password" sur votre champ de mot de passe ne pourrait probablement pas nuire non plus.

Si cela vous pose encore beaucoup de problèmes, je vous conseillerais de vous inscrire sur l'une des listes de diffusion des développeurs du projet Mozilla (vous pouvez même obtenir une réponse du développeur qui a conçu la fonctionnalité).

51
bta

J'ai eu le même problème et j'ai trouvé une solution: 

  1. pour que le navigateur demande à stocker le mot de passe, les champs nom d'utilisateur et mot de passe doivent être dans un formulaire et ce formulaire doit être soumis. Le bouton de soumission peut renvoyer faux à partir du gestionnaire onclick (afin que la soumission ne se produise pas).

  2. pour que le navigateur restaure le mot de passe précédemment stocké, les zones de saisie doivent exister dans le formulaire HTML principal et ne pas être créées de manière dynamique via JavaScript. Le formulaire peut être créé avec display: aucun.

Il est nécessaire de noter que le mot de passe est renseigné immédiatement après le chargement de la page et qu'il y est présent pendant toute la session. Il peut donc être lu par javascript injecté: cela aggrave encore plus ces attaques. Pour éviter cela, il est raisonnable de transférer vers une page distincte pour se connecter et résout tous les problèmes pour lesquels vous avez commencé à lire cette rubrique :). En tant que solution partielle, je nettoie les champs lors de la soumission du formulaire - si l'utilisateur se déconnecte et souhaite se reconnecter, le mot de passe n'est pas renseigné par le navigateur, mais c'est mineur pour moi.

Viliam


17
user324356

Vous devriez consulter la page Mozilla Password Manager Debugging et la docs nsILoginManager pour les auteurs d'extensions (juste pour les détails techniques détaillés de la manière dont Firefox gère la gestion des mots de passe). Vous pouvez y chercher des réponses et consulter d'autres pages liées pour en savoir plus sur ce que vous avez probablement jamais voulu savoir sur la manière dont le gestionnaire de mots de passe interagit avec les sites et les extensions.

(En particulier, comme indiqué dans la documentation de débogage du gestionnaire de mots de passe, assurez-vous que la complétion automatique n'est pas désactivée dans votre code HTML, car cela supprime l'invite pour enregistrer le nom d'utilisateur et le mot de passe.)

10
Nick Bastin

Cela semble fonctionner pour Firefox, Chrome et Safari sur Mac. Non testé sous Windows. 

<form id="bridgeForm" action="#" target="loginframe" autocomplete="on">
    <input type="text" name="username" id="username" />
    <input type="password" name="password" id="password"/>
</form>

<iframe id="loginframe" name="loginframe" src="anyblankpage.html"></iframe>

Cela doit être ajouté à la page. Il ne peut pas être ajouté dynamiquement. Le formulaire et iframe peuvent être configurés pour afficher: aucun. Si vous ne définissez pas le src de l'iframe, l'invite ne s'affiche pas tant que vous n'avez pas soumis le formulaire au moins une fois. 

Ensuite, appelez le formulaire submit ():

bridgeForm.submit();

L'action peut être facultative et la saisie semi-automatique peut être facultative. Je n'ai pas testé. 

Remarque : Sur certains navigateurs, le formulaire doit être exécuté sur un serveur (et non sur hôte local ni sur le système de fichiers) avant que le navigateur ne réponde. 

Donc ça:

http://www.mysite.com/myPage.html 

pas ça: 

http://126.0.0.1/myPage.html
http://localhost/myPage.html
file://directory/myPage.html

6
1.21 gigawatts

Fonctionne pour moi avec angular, chrome, firefox: (j'ai recherché et testé pendant des heures - pour chrome, le paramètre d'action de formulaire (#) était la réponse. @ 1,21 gigawatts , merci !!! Votre réponse était inestimable.)

forme

firefox 30.0 - n'a pas besoin d'un iframe et d'un bouton d'envoi masqués (comme indiqué ci-dessous), mais nécessite la directive "login-form-autofill-fix" pour reconnaître les éléments de saisie remplis automatiquement, comme suit:

<form name="loginForm" login-form-autofill-fix action="#" target="emptyPageForLogin" method="post" ng-submit="login({loginName:grpEmail,password:grpPassword})">
<input type="text" name=username" id="username" ng-model="grpEmail"/>
<input type="password" name="password" id="password" ng-model="grpPassword"/>
<button type="submit">Login</button>
</form>

iframe caché

chrome 35.0 - n'a pas besoin de la directive ci-dessus, mais nécessite une iframe cachée et un bouton d'envoi sur le formulaire réel. L'iframe caché ressemble à

<iframe src="emptyPageForLogin.html" id="emptyPageForLogin" name="emptyPageForLogin" style="display:none"></iframe>

directive angulaire (utilisant jqLite)

Cela fonctionne avec 1.2.18 angulaire

module.directive('loginFormAutofillFix', function() { 
            return function(scope, elem, attrs) {
        if(!attrs.ngSubmit) {
            return;
        }
        setTimeout(function() {
            elem.unbind("submit").bind("submit", function(e) {
                //DO NOT PREVENT!  e.preventDefault(); 
                elem.find("input").triggerHandler("input");
                scope.$apply(attrs.ngSubmit);
            });
        }, 0);
});

amendement

  • après quelques essais, je me suis rendu compte que chrome avait besoin d’un peu de temps d’attente de la méthode de connexion angulaire (200 ms) - il semble que la redirection soit parfois tout simplement trop rapide pour le gestionnaire de mots de passe.
  • un navigateur plus clair… à chaque changement
5
110maor

J'ai également remarqué que Chrome ne proposerait pas de retenir un mot de passe si le formulaire de connexion est toujours présent après la demande de connexion, même s'il est masqué sur la page.

Je suppose qu'il pense que l'action de connexion a échoué et refuse donc de stocker des informations d'identification non valides.

Vu sur Chrome 34.0.

3
ZeWaren

Eh bien, sur notre site , un champ de formulaire portant le nom "nom d'utilisateur" tapez "texte" immédiatement suivi d'un champ portant le nom "mot de passe" et tapez "mot de passe" semble faire l'affaire.

3
spender

Si vous utilisez la connexion AJAX, consultez le code source: https://Gist.github.com/968927

Il consiste à soumettre un formulaire de connexion à une iframe masquée, de sorte que IE et Chrome puissent détecter la connexion réelle, sans avoir à recharger la page.

3
Adrien Joly

Je recommande de regarder le code source de Firefox . C'est en fait un code assez simple.

Les méthodes que vous souhaitez examiner sont _onFormSubmit, _getFormFields et _getPasswordFields

Vous pourriez même trouver que le problème que vous rencontrez est un bogue non découvert dans Firefox;) https://bugzilla.mozilla.org/show_bug.cgi?id=1211780

3
WoodenKitty

Les heuristiques sont assez simples ici: détecter les champs avec certains noms dans un certain ordre. Lesquels, je ne peux pas le dire, mais cela a bien fonctionné pour moi dans Chrome et IE:

Username field: name "login", type "text";
Password field: name "password", type "password"
Submit button: element "input", type "submit". 
Element "button" type "submit" did not work.
2
user19878

Si vous avez par exemple deux types = texte dans votre formulaire avant type = mot de passe, le navigateur .__ détecte le type d’entrée le plus proche = texte pour votre nom d’utilisateur.

Ce n'est pas grave, une autre entrée a est = nom d'utilisateur et nom = nom d'utilisateur

pour résoudre ce problème, vous devez entrer votre nom d'utilisateur que vous souhaitez enregistrer exactement avant votre mot de passe

Bonne chance :-)

1
keivan kashani

En plus de tout ce qui a été dit, je me suis rendu compte que les champs de saisie ne devaient pas être "désactivés". Nous avons eu une connexion en plusieurs étapes qui demande d'abord le nom d'utilisateur, puis le mot de passe sur l'écran suivant. Sur ce deuxième écran, nous avons répété le courrier électronique, mais nous l'avons désactivé, ce qui a empêché Chrome et. Al. de reconnaître comme un champ valide pour le nom d'utilisateur.

Puisque nous voulions vraiment conserver ce champ de saisie désactivé, nous avons abouti à cette solution de contournement:

<input type="text" name="display-username" id="display-username" value="ENTERED_USERNAME" placeholder="Username" disabled="disabled">
<input type="text" name="username" id="username" value="ENTERED_USERNAME" placeholder="Username" style="display: none;">
<input type="password" name="password" id="password" value="" autofocus="autofocus" autocomplete="on" placeholder="Password" required="required">

Je n'irais pas aussi loin pour le recommander, mais peut-être que cela indique à quelqu'un quelque chose dans son propre code:

  1. Le premier élément affiche le nom d'utilisateur dans un champ de saisie désactivé. Disabled ne soumet pas dans le cadre du formulaire et disabled n'est pas reconnu par le navigateur.
  2. Le deuxième élément est un champ de saisie approprié, avec type = "text" et name/id = "username". Ceci est reconnu par le navigateur. Afin d'empêcher l'utilisateur de le modifier, nous le cachons avec CSS (display: none).
0
hendrikbeck