L’API reste accessible dans l’environnement de test, mais une erreur réseau apparaît dès que l’archive est transmise à l’équipe de validation. Le scénario inverse est encore plus dangereux : pour contourner temporairement un problème de certificat, quelqu’un laisse NSAllowsArbitraryLoads dans la configuration de distribution. L’application semble alors fonctionner de nouveau, mais toutes les connexions qu’ATS devrait bloquer sont autorisées. Pour éviter ces deux incidents, il ne suffit pas d’inspecter le fichier Info.plist du dépôt : il faut contrôler l’application réellement compilée sur le Mac cloud.
Définir d’abord ce que le contrôle doit vérifier
Un contrôle ATS exploitable doit couvrir au moins trois niveaux : la configuration statique, la négociation TLS côté hôte et les requêtes au niveau de l’application. Chaque niveau répond à une question différente ; la réussite d’une commande curl ne remplace donc pas l’ensemble des vérifications.
| Niveau | Élément contrôlé | Priorité de diagnostic en cas d’échec |
|---|---|---|
| Configuration statique | Fichier Info.plist final dans l’application | Configuration de compilation, modifications par script, exceptions de domaine |
| Sonde TLS | Connexion entre le Mac cloud et le point de terminaison cible | DNS, chaîne de certificats, version du protocole, redirections |
| Requête applicative | Comportement réel de URLSession | ATS, configuration de session, authentification et analyse de la réponse |
Commencez par formaliser la politique : NSAllowsArbitraryLoads est interdit dans l’artefact distribué ; seuls les domaines approuvés peuvent figurer dans NSExceptionDomains ; toute exception temporaire doit indiquer un responsable et une condition de suppression ; les réglages nécessaires au débogage local ne doivent jamais se retrouver dans Release.
Une exception ATS n’est pas un interrupteur générique destiné à « faire fonctionner le réseau pour l’instant », mais une modification de sécurité dont il faut documenter le périmètre, la justification et le plan de retrait.
Auditer l’artefact de compilation final
Le plist source peut être remplacé par INFOPLIST_KEY_*, par différents fichiers xcconfig ou par des scripts de compilation. Effectuez d’abord une compilation Release, puis récupérez le chemin de l’artefact produit :
set -euo pipefail
xcodebuild \
-scheme "$SCHEME" \
-configuration Release \
-sdk iphonesimulator \
-derivedDataPath "$PWD/.derived-data" \
build
APP_PATH="$(find "$PWD/.derived-data/Build/Products" \
-type d -name '*.app' -path '*Release-*' -print -quit)"
test -n "$APP_PATH"
PLIST="$APP_PATH/Info.plist"
plutil -lint "$PLIST"
plutil -extract NSAppTransportSecurity json -o - "$PLIST" \
> "$PWD/ats-effective.json" 2>/dev/null || printf '{}
' > "$PWD/ats-effective.json"
Le contrôle doit considérer comme normaux l’absence de dictionnaire ATS et la présence d’un dictionnaire vide. Seules une autorisation trop large ou une exception non approuvée doivent provoquer un échec. Le script suivant reçoit la liste autorisée par l’intermédiaire d’une variable d’environnement, afin de ne pas coder en dur les domaines internes de l’équipe dans un script public :
import json
import os
import sys
with open(sys.argv[1], encoding="utf-8") as f:
ats = json.load(f)
if ats.get("NSAllowsArbitraryLoads") is True:
raise SystemExit("NSAllowsArbitraryLoads is forbidden")
approved = {
item.strip().lower()
for item in os.getenv("ATS_APPROVED_DOMAINS", "").split(",")
if item.strip()
}
exceptions = ats.get("NSExceptionDomains", {})
unknown = sorted(set(map(str.lower, exceptions)) - approved)
if unknown:
raise SystemExit("Unapproved ATS domains: " + ", ".join(unknown))
Exécutez-le avec python3 ci/audit_ats.py ats-effective.json. Les journaux CI peuvent conserver les noms des clés et les résultats des contrôles, mais ils ne doivent pas afficher les jetons de requête, les Cookie ni les en-têtes d’authentification complets.
Établir un registre d’exceptions vérifiable
Comparer uniquement les domaines ne suffit pas. Pour chaque exception, il faut consigner les clés ATS autorisées, l’environnement concerné, la justification et la condition de réexamen. Une attention particulière doit être portée à NSIncludesSubdomains : cette clé étend la portée à tous les sous-domaines et ne doit pas être activée par défaut sous prétexte qu’une seule API est actuellement utilisée.
Il est recommandé de conserver ce registre au format JSON ou YAML dans le dépôt et de vérifier les points suivants pendant la revue :
- le domaine doit être précis, sans description générique utilisant des caractères génériques ;
- il est interdit d’abaisser TLS à une version qui ne respecte pas le niveau de référence du projet ;
- il est interdit d’autoriser tout un domaine parent pour gérer une seule redirection ;
- les API de débogage doivent être limitées à la configuration Debug ;
- après la suppression d’une exception, la compilation et le test de requête doivent être réexécutés.
Vérifier l’absence de mélange entre les configurations
Compilez séparément Debug et Release, puis exportez deux fichiers ats-effective.json afin de comparer leurs différences. Si Release contient une clé destinée uniquement à l’interception du trafic ou à un service local, le contrôle doit échouer immédiatement. Ne comparez pas seulement les fichiers sources : un même plist peut recevoir des valeurs différentes selon les réglages de compilation.
Sonder TLS et la chaîne de redirections
Une fois l’audit statique validé, sondez l’adresse cible depuis le Mac cloud chargé de la compilation. nscurl produit une matrice de diagnostic ATS utile pour identifier les problèmes de protocole, de chaîne de certificats et de confidentialité persistante :
test -n "${API_URL:-}"
/usr/bin/nscurl --ats-diagnostics "$API_URL" \
> "$PWD/ats-diagnostics.txt" 2>&1
Cette sortie est adaptée au diagnostic, mais elle ne doit pas servir à une règle simpliste telle que « le fichier contient PASS ». Le mode de diagnostic essaie en effet plusieurs combinaisons d’exigences assouplies. La décision bloquante dans la CI doit reposer sur une requête contrôlée vers l’URL réelle du projet, avec des limites pour le délai d’attente, le nombre de redirections et les codes de réponse :
curl --fail --silent --show-error \
--proto '=https' \
--tlsv1.2 \
--max-time 15 \
--max-redirs 3 \
--output /dev/null \
"$API_URL"
La réussite de curl indique uniquement que la connexion est disponible côté hôte. Cette commande n’applique pas la configuration ATS de l’application iOS et ne prouve pas que le proxy de session, les en-têtes de requête ou la logique d’authentification de l’application sont corrects.
Ajouter un test de non-régression au niveau applicatif
Ajoutez enfin une cible de test légère utilisant la pile réseau de production. Le test doit lire l’URL injectée par l’environnement de test, effectuer un contrôle d’état avec URLSession, puis vérifier que la réponse arrive à son terme, que le code d’état respecte la convention prévue et qu’aucune redirection ne mène vers une adresse non HTTPS. N’inscrivez aucun identifiant fixe dans le code de test.
Conserver des preuves suffisantes, sans excès
En cas d’échec, il suffit d’archiver le dictionnaire ATS final, le résultat de la comparaison avec la liste des domaines, la sortie de nscurl, le code d’état de la requête, le nom d’hôte de la destination de redirection et le nom de la configuration de compilation Xcode. Le contenu des certificats, les jetons d’accès et le corps complet des réponses n’ont généralement pas leur place dans les journaux conservés à long terme.
Fixez l’ordre d’exécution suivant : « compilation Release → audit du plist final → sonde TLS → test URLSession ». Cet enchaînement permet à la fois de détecter les dérives de configuration et de distinguer un refus imposé par la politique de l’application d’une modification de la chaîne de certificats, du DNS ou des redirections du point de terminaison cible.
Liste de contrôle avant la mise en production
Avant la fusion, vérifiez que l’artefact distribué n’autorise pas arbitrairement toutes les connexions réseau, que chaque exception de domaine figure dans le registre approuvé, que la portée concernant les sous-domaines a fait l’objet d’une revue explicite, que la sonde TLS utilise l’adresse cible réelle et que le test applicatif passe par la configuration URLSession effective. En cas d’échec, conservez d’abord l’artefact et les fichiers de diagnostic avant de modifier la configuration, afin de ne pas masquer un problème de certificat ou de redirection par l’ajout d’une nouvelle exception.
Ce contrôle n’a pas pour objectif de faire disparaître automatiquement toutes les pannes réseau. Il doit les localiser à un niveau exploitable et garantir qu’un réglage de débogage temporaire ne se retrouve pas discrètement dans la prochaine version distribuée.
Questions fréquentes
Pourquoi ne pas vérifier uniquement le fichier Info.plist source ?
Les réglages de compilation et les scripts peuvent modifier les valeurs finales. Le fichier intégré au paquet compilé constitue la référence réelle.
Un diagnostic nscurl réussi garantit-il la connexion de l’application ?
Non. Il faut aussi tester une requête URLSession afin de couvrir la politique ATS, les redirections et le parcours d’authentification.
Quels réglages ATS doivent faire échouer la CI ?
NSAllowsArbitraryLoads, les exceptions absentes de la liste approuvée et toute autorisation de débogage présente dans le paquet de distribution.
Utilisez un Mac mini dans le cloud pour votre prochain développement ou build
Choisissez parmi deux configurations M4, quatre durées de location et cinq nœuds disponibles à la vente. La disponibilité réelle est indiquée en temps réel dans la console.