web-dev-qa-db-fra.com

Chrome Autofill/Autocomplete aucune valeur pour le mot de passe

Lorsque vous avez enregistré le nom d'utilisateur et le mot de passe de certains sites, Chrome les remplit automatiquement, mais si vous essayez d'obtenir la valeur du champ de saisie du mot de passe, la chaîne est vide même s'il existe une valeur ******.

Si vous cliquez quelque part sur la page, il n'y a pas de lieu où la valeur du input type="password" sera renseignée.

Ceci est Fiddle user/pass de la structure du code HTML et de la commande console.log. Il ne peut pas être vu ici, mais il peut être reproduit sur chaque page comportant un formulaire de connexion. Le nom d'utilisateur et le mot de passe sont automatiquement renseignés lors du chargement de la page. Si vous inspectez la valeur du champ avant de cliquer n'importe où sur le site, la chaîne sera vide.

Ce n'est pas le cas dans Firefox ou Internet Explorer, la valeur de l'élément input sera renseignée avec le mot de passe.

J'utilise le système d'exploitation Windows 7 Ultimate 64 bits et la version de Google Chrome est 48.0.2564.97 m

Est-ce un comportement normal, un bug ou?

METTRE À JOUR:

Si vous cliquez sur F5 pour recharger la page et inspecter le champ du mot de passe, la valeur du mot de passe sera là. Si vous cliquez sur le bouton de rechargement dans Chrome en haut à gauche, la valeur du champ du mot de passe sera une chaîne vide.

42
onetwo12

Cela semble être un bug dans Chrome. Lorsque Chrome remplit automatiquement un mot de passe lors du chargement initial d'une page (mais pas d'une actualisation), la valeur apparaît dans le champ de formulaire à l'écran, mais l'interrogation de passwordField.value en Javascript renvoie une chaîne vide. Si vous comptez sur l'affichage de cette valeur en Javascript, cela vous empêche de le faire. Une fois que l'utilisateur a effectué une autre action sur la page, telle que cliquer n'importe où sur la page, la valeur devient soudainement visible en Javascript.

Je ne suis pas vraiment sûr à 100% s'il s'agit d'un bogue ou s'il existe une raison de sécurité, telle qu'empêcher un cadre masqué de voler votre mot de passe en poussant le navigateur à le remplir.

Une solution de contournement que nous avons utilisée consiste à détecter le changement de couleur d'arrière-plan effectué par Chrome dans les champs remplis automatiquement. Chrome colore l'arrière-plan des champs remplis automatiquement en jaune. Cette modification est toujours visible en Javascript, même lorsque la valeur ne l'est pas. Détecter ceci en Javascript nous permet de savoir que le champ a été rempli automatiquement avec une valeur, même si nous voyons la valeur vide en Javascript. Dans notre cas, nous avons un formulaire de connexion dans lequel le bouton d'envoi n'est pas activé jusqu'à ce que vous remplissiez quelque chose dans le champ du mot de passe, et la détection d'une valeur ou de la couleur d'arrière-plan à remplissage automatique suffit pour déterminer qu'il y a quelque chose dans le champ. . Nous pouvons ensuite activer le bouton Envoyer. En cliquant sur le bouton (ou en appuyant sur Entrée), la valeur du champ du mot de passe est immédiatement visible en Javascript, car le fait d'interagir avec la page corrige le problème, ce qui nous permet de procéder normalement.

35
Adam Hamilton

Réponse fonctionnelle au 8 juillet 2016

Adam a correctement déclaré ceci est un bogue (ou un comportement prévu). Toutefois, aucune des réponses précédentes ne dit réellement comment résoudre ce problème. Il existe donc une méthode permettant de forcer Chrome à traiter la valeur autocompleted comme une valeur réelle.

Plusieurs choses doivent se passer dans l’ordre, et cela ne doit s’exécuter que dans Chrome et pas dans Firefox, d’où la variable if.

Nous nous concentrons d'abord sur l'élément. Nous créons ensuite une nouvelle TextEvent et exécutons initTextEvent, qui ajoute une chaîne personnalisée que nous spécifions (j'ai utilisé "@@@@@") au début de la valeur. Cela déclenche le comportement de Chrome comme si la valeur était réelle. Nous pouvons ensuite supprimer la chaîne personnalisée que nous avons ajoutée, puis nous déconcentrer.


Code:

input.focus();

var event = document.createEvent('TextEvent');

if ( event.initTextEvent ) {

    event.initTextEvent('textInput', true, true, window, '@@@@@');

    input.dispatchEvent(event);

    input.value = input.value.replace('@@@@@','');

}

input.blur();

Modifier le 10 août 2016

Cela ne fonctionne actuellement que dans Chrome sous Windows et Android. Ne fonctionne pas sur OSX. De plus, il cessera définitivement de fonctionner en septembre 2016, selon:

https://www.chromestatus.com/features/5718803933560832

De plus, j'ai ouvert un ticket Chromium.

https://bugs.chromium.org/p/chromium/issues/detail?id=636425

À compter du 12 août, un membre de l'équipe de Chrome a déclaré sur le ticket ci-dessus que le comportement ne changerait pas car ils ne le considéraient pas comme un bogue.

Suggestion de contournement à long terme:

Cela dit, le comportement actuel a été modifié depuis sa mise en œuvre initiale. L'utilisateur n'a plus besoin d'interagir avec l'entrée du mot de passe pour que la valeur soit rapportée. L'utilisateur doit maintenant simplement interagir (envoyer un événement de souris ou de clavier) avec n'importe quelle partie de la page. Cela signifie que bien que l'exécution de la validation sur pageload ne fonctionne toujours pas, un clic sur le bouton d'envoi SOUMETTRE à Chrome de signaler correctement la valeur du mot de passe. La solution consiste alors à revalider toutes les entrées pouvant être complétées automatiquement, si c'est ce que vous essayez de faire, lors de la soumission.


Edit 13 décembre 2016:

Un nouveau ticket Chromium a été ouvert et est mieux reçu. Si vous souhaitez modifier le comportement de Google Chrome, veuillez créer ce nouveau ticket:

https://bugs.chromium.org/p/chromium/issues/detail?id=669724

23
Andy Mercer

Pour reprendre ce que Andy Mercer a dit , voici mon travail. Comme beaucoup de gens, je n'ai pas besoin du mot de passe réel. J'ai juste besoin de savoir que la boîte de saisie du mot de passe a été remplie automatiquement pour pouvoir afficher les messages de validation appropriés.

Personnellement, je n’utiliserais pas la solution suggérée pour détecter le changement de couleur d’arrière-plan causé par le remplissage automatique de Chrome. Cette approche semble fragile. Cela dépend de cette couleur jaune qui ne change jamais. Mais cela pourrait être modifié par une extension et être différent dans un autre navigateur basé sur Blink (ie. Opera). De plus, rien ne promet que Google n'utilisera pas de couleur différente à l'avenir. Ma méthode fonctionne quel que soit le style.

Premièrement, dans CSS, je définis le contenu de la variable INPUT lorsque la pseudo-classe -webkit-autofil lui est appliquée:

input:-webkit-autofill {
  content: "\feff"
}

Ensuite, j'ai créé une routine pour vérifier le contenu à définir:

const autofillContent = `"${String.fromCharCode(0xFEFF)}"`;
function checkAutofill(input) {
    if (!input.value) {
        const style = window.getComputedStyle(input);
        if (style.content !== autofillContent)
            return false;
    }

    //the autofill was detected
    input.classList.add('valid'); //replace this. do want you want to the input
    return true;
}

Enfin, j'ai interrogé la input pour permettre au temps de remplissage automatique de se terminer:

const input = document.querySelector("input[type=password]");

if (!checkAutofill(input)) {
    let interval = 0;
    const intervalId = setInterval(() => {
        if (checkAutofill(input) || interval++ >= 20)
            clearInterval(intervalId);
    }, 100);
}
6
Ben

Une autre option à partir du 16 décembre/Chrome 54

Je ne peux pas obtenir la valeur du champ mot de passe, mais après "quelques instants", je peux obtenir la longueur du mot de passe en le sélectionnant, ce qui me suffit pour activer le bouton d'envoi.

setTimeout(function() {
  // get the password field
  var pwd = document.getElementById('pwd');
  pwd.focus();
  pwd.select();
  var noChars = pwd.selectionEnd;
  // move focus to username field for first-time visitors
  document.getElementById('username').focus()
  if (noChars > 0) {
    document.getElementById('loginBtn').disabled = false;
  }
}, 100);
4
crsw

Voici ma solution à ce problème:

$(document).ready(function(){
  if ( $("input:-webkit-autofill").length ){
    $(".error").text("Chrome autofill detected. Please click anywhere.");
  }
});

$(document).click(function(){
  $(".error").text("");
});

Fondamentalement, cliquer rend l’entrée visible à l’utilisateur. Je demande donc à l’utilisateur de cliquer et quand ils le font, je cache le message.

Pas la solution la plus élégante mais probablement la plus rapide.

4
SamJakob

J'ai trouvé une solution à ce problème qui fonctionne au moins pour mes besoins.

J'ai un formulaire de connexion que je souhaite simplement appuyer sur Entrée dès son chargement, mais je rencontrais le problème du mot de passe vide dans Chrome.

Ce qui suit semble fonctionner, permettant à la touche d'entrée initiale d'échouer et de réessayer une fois que Chrome se réveille et fournit la valeur du mot de passe.

$(function(){

    // bind form submit loginOnSubmit
    $('#loginForm').submit(loginOnSubmit);

    // submit form when enter pressed on username or password inputs
    $('#username,#password').keydown(function(e) {
        if (e.keyCode == 13) {
            $('#loginForm').submit(e);
            return false;
        }
    });

});

function loginOnSubmit(e, passwordRetry) {

    // on submit check if password is blank, if so run this again in 100 milliseconds
    // passwordRetry flag prevents an infinite loop
    if(password.value == "" && passwordRetry != true)
    {
        setTimeout(function(){loginOnSubmit(e,true);},100);
        return false;
    }

    // login logic here
}
3
bbeckford

Je viens d'écrire une directive angulaire liée à cela. Nous avons fini avec le code suivant:

if ('password' == $attrs.type) {
      const _interval = $interval(() => { //interval required, chrome takes some time to autofill
          if ($element.is(':-webkit-autofill')) { //jQuery.is()
              //your code
              $interval.cancel(_interval);
          }
      }, 500, 10); //0.5s, 10 times
}

ps: il ne détectera pas 100% des cas, chrome peut prendre plus de 5 secondes pour remplir l'entrée.

3
Ian Luca

La solution de contournement spécifiée par Adam:

... détecte le changement de couleur d'arrière-plan que Chrome apporte aux champs remplis automatiquement. Chrome colore l'arrière-plan des champs remplis automatiquement en jaune. Cette modification est toujours visible en Javascript, même lorsque la valeur ne l'est pas. Détecter cela en Javascript nous permet de savoir que le champ a été rempli automatiquement avec une valeur, même si la valeur est vide en Javascript

J'ai fait comme ça: -

getComputedStyle(element).backgroundColor === "rgb(250, 255, 189)"

où rgb (250, 255, 189) est la couleur jaune que Chrome applique aux entrées à remplissage automatique.

3
Frozen Crayon

Le comportement souhaité de Chrome est qu'un mot de passe à remplissage automatique ait une value vide dans le DOM jusqu'à ce que l'utilisateur interagisse avec le cadre d'une manière ou d'une autre, auquel cas chrome remplit réellement la valeur. Jusqu'à ce point, toute validation côté client ou tentative d'ajax d'envoi du formulaire verra le mot de passe vide.

Ce comportement 'renseigner le mot de passe sur l'interaction de la trame' est incohérent. J'ai constaté que lorsque le formulaire est hébergé dans une iframe de même origine, il ne fonctionne que lors du premier chargement et jamais lors des chargements suivants.

Ceci est particulièrement évident sur les formulaires ajax où le mot de passe de saisie semi-automatique est renseigné lors du premier chargement. Toutefois, si ce mot de passe est invalide et que la soumission d'ajax rend à nouveau le formulaire DOM, le mot de passe de saisie semi-automatique réapparaît de manière visuelle mais la value n'est jamais renseignée, quelle que soit l'interaction .

Aucune des solutions de contournement mentionnées, telles que le déclenchement d'événements blur ou input, n'a fonctionné dans ce scénario. La seule solution que j'ai trouvée consiste à réinitialiser la valeur du champ de mot de passe une fois que le processus ajax a restitué le formulaire, par exemple:

$('input[type="password"]').val("");

Après ce qui précède, Chrome complète à nouveau automatiquement le mot de passe, mais avec la variable value réellement remplie.

Dans mon cas d'utilisation actuel, j'utilise Ajax.BeginForm d'ASP.NET et j'utilise la solution de contournement ci-dessus dans le rappel AjaxOptions.OnSuccess.

1
James Martin

Avec Angular, le nouveau comportement de Chrome (autorisant uniquement la lecture de valeurs remplies automatiquement après que l'utilisateur a interagi avec la page) se révèle être un problème lorsque vous utilisez la fonctionnalité de validation d'Angular dans certains scénarios (par exemple, en utilisant des attributs de méthode/action standard Sur le formulaire). Étant donné que le gestionnaire d'envoi est exécuté immédiatement, il ne permet pas aux validateurs de formulaires de capturer les valeurs à remplissage automatique à partir de Chrome.

Une solution que j'ai trouvée pour cela appelle explicitement la fonction $commitViewValue du contrôleur de formulaire dans le gestionnaire d'envoi à déclencher une revalidation avant de vérifier form.$valid ou form.invalid etc.

Exemple:

function submit ($event) {
    // Allow model to be updated by Chrome autofill
    // @see http://stackoverflow.com/questions/35049555/chrome-autofill-autocomplete-no-value-for-password
    $scope.loginModule.$commitViewValue();

    if ($scope.loginModule.$invalid) {
        // Disallow login
        $scope.loginModule.$submitted = true;
        $event.preventDefault();
    } else {
        // Allow login
    }
}

Bien que cela fonctionne pour nous jusqu'à présent, je serais très intéressé si quelqu'un a trouvé un autre travail, plus élégant, autour de la question.

1
drewzh

Ce n'est pas un bug. C'est un problème de sécurité. Imaginez si vous pouviez simplement utiliser javascript pour récupérer des mots de passe remplis automatiquement sans accusé de réception des utilisateurs.

0
Timothy Law
$element.is("*:-webkit-autofill")

travaille pour moi

0
harry

La fonctionnalité de saisie semi-automatique a bien été désactivée . Cela fonctionne!

[HTML]

<div id="login_screen" style="min-height: 45px;">
   <input id="password_1" type="text" name="password">
</div>

[JQuery]

$("#login_screen").on('keyup keydown mousedown', '#password_1', function (e) {
    let elem = $(this);

    if (elem.val().length > 0 && elem.attr("type") === "text") {
        elem.attr("type", "password");
    } else {
        setTimeout(function () {
            if (elem.val().length === 0) {
                elem.attr("type", "text");
                elem.hide();
                setTimeout(function () {
                    elem.show().focus();
                }, 1);
            }
        }, 1);
    }

    if (elem.val() === "" && e.type === "mousedown") {
        elem.hide();
        setTimeout(function () {
            elem.show().focus();
        }, 1);
    }

});
0
EngineerCoder
var txtInput = $(sTxt);
txtInput.focus();
txtInput.select();

Cette solution a fonctionné dans mon cas… .. utilisant jQuery 3.1.1.

0
CornyVanBeck

Si vous voulez que l'entrée soit considérée comme remplie, essayez de déclencher blur dessus: $('input[type="password"]').blur();

0
gregmatys