web-dev-qa-db-fra.com

Cordova n'envoie pas Origin sur demande sur certains appareils Android

Il s'agit d'un problème qui se produit sur certains appareils Android.

J'ai une Samsung Galaxy A5 (2017) avec Google Chrome version 76.0.3809.89 et Android version 8.0.0.

Lorsque je déploie mon application Cordova pour la première fois sur cet appareil et que je fais une demande POST, je reçois une erreur concernant CORS:

Access to XMLHttpRequest at 'http://foo.com/bar' from Origin 'file://' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.

Je peux voir dans l'onglet réseau de l'outil de développement de Chrome que cette POST, n'a pas le paramètre Origin.

Si je ferme l'application depuis le gestionnaire de tâches et la redémarre, je peux effectuer cette demande avec succès et chrome envoie le paramètre 'Origin' sur demande.

Je peux reproduire le problème à nouveau si je supprime les données des applications des paramètres de l'appareil.

Je suis totalement sûr que ce n'est pas un problème avec Content-Security-Policy ou cordova-whitelist-plugin configuration car comme je l'ai mentionné précédemment, sur certains autres appareils Android, l'application fonctionne très bien.

Autre chose que je dois mentionner, c'est qu'avec le plugin Crosswalk, je n'ai pas eu ce problème.

10
yannisalexiou

Nous rencontrons le même problème. Nous avons d'abord essayé d'implémenter une solution de contournement où l'application détecte la Chrome. La première fois qu'elle voit la version 76, elle redémarre automatiquement l'application. La plupart des utilisateurs ne remarqueraient même pas le redémarrage. La solution de contournement était sur la base de plusieurs rapports qui ont déclaré que le problème n'apparaîtrait que lors de la première exécution de l'application après l'installation de Chroe 76 et disparaîtrait définitivement après un redémarrage. Cependant, il s'est avéré que le problème revient souvent de manière aléatoire, de sorte que le contournement n'était pas suffisant.

Heureusement, nous contrôlons également le côté serveur, nous avons donc implémenté une solution de contournement. Fondamentalement, nous acceptons simplement le file:// Origine. L'impact sur la sécurité de cette solution de contournement dépend certainement de l'application individuelle, alors réfléchissez-y attentivement au cas où vous envisageriez d'impliquer quelque chose de similaire.

Dans notre cas, nous utilisons ASP.NET où nous faisions face à un défi supplémentaire. Malheureusement, EnableCorsAttribute échoue lors de la spécification de file:// en tant qu'Origine, ce qui est conforme à la spécification CORS, qui requiert qu'un nom d'hôte soit présent dans chaque Origine (sauf lorsque vous spécifiez *). Nous avons donc finalement trouvé la solution suivante (spécifique à ASP.NET bien sûr):

Créez un ICorsPolicyProvider qui remplace la logique de validation en cas d'origine file:// et délègue à un fournisseur imbriqué (l'original) dans tous les autres cas:

    /// <summary>
    /// Object that allows clients with `file://` Origin. This is used as a workaround
    /// for issues on Android devices running Chrome 76. See
    /// https://bugs.chromium.org/p/chromium/issues/detail?id=991107#c14
    /// 
    /// Simply adding `file://` to the allowed origins list doesn't work, because by
    /// specification a hostname is required.
    /// 
    /// This workaround should be removed as soon as Chrome 76 distribution has dropped
    /// sufficiently.
    /// </summary>
    // TODO: Remove this workaround once Chrome 76 is not around anymore.
    public class CorsPolicyProviderAcceptingFileOrigin : ICorsPolicyProvider
    {
        public readonly ICorsPolicyProvider inner;

        public CorsPolicyProviderAcceptingFileOrigin(ICorsPolicyProvider inner)
        {
            this.inner = inner;
        }

        public async Task<CorsPolicy> GetCorsPolicyAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            if (
                request.Headers.TryGetValues("Origin", out IEnumerable<string> origins)
                && origins.SequenceEqual(new[] { "file://" })
                )
            {
                var policy = new CorsPolicy()
                {
                    AllowAnyHeader = true,
                    AllowAnyMethod = true,
                    AllowAnyOrigin = false,
                };
                policy.Origins.Add("file://");

                return policy;
            }

            return await this.inner.GetCorsPolicyAsync(request, cancellationToken);
        }
    }

puis l'utiliser comme ceci dans WebApiConfig.cs:

// get the original EnableCorsAttribute
ICorsPolicyProvider cors = ...;

// this is a workaround for Android devices running Chrome 76 and should be removed in future versions.
// See https://bugs.chromium.org/p/chromium/issues/detail?id=991107
cors = new CorsPolicyProviderAcceptingFileOrigin(cors);

config.EnableCors(cors);
2
MarkusM

Il s'agit d'un bogue ouvert sur la vue Web de Chromium intéressant la version 76; dans cette version spécifique, OOR-CORS reste activé lors de la première exécution.

https://bugs.chromium.org/p/chromium/issues/detail?id=991107#c14

Une liste de modifications sera directement fusionnée avec la branche 76.

7
systempuntoout

Nous rencontrons le même problème ... AJAX ne fonctionneront pas après le premier démarrage à froid de nos projets Cordova. Si nous redémarrons l'application (supprimez l'application de l'arrière-plan), alors cela fonctionne .. Il semble que ce soit un problème avec la version Chromium WebView ... J'ai trouvé une solution de contournement très laide.

https://github.com/dpa99c/cordova-diagnostic-plugin#restart

plugin et redémarrez l'application après le premier démarrage à froid. Vérifiez localStorage pour un indicateur de démarrage à froid. Si vous ne le trouvez pas, redémarrez l'application.

0
Nagy Istvan