Sécurité Shiny : renforcez votre application contre les menaces réelles

Validez les entrées, bloquez les injections, protégez les secrets, chiffrez les données et servez en HTTPS — en déléguant à des outils éprouvés, sans jamais bricoler la cryptographie.

Programming
Shiny

Renforcez une application Shiny de production comme il faut. Validez chaque entrée, bloquez l’injection SQL avec des requêtes DBI paramétrées, gardez les secrets dans des variables d’environnement, chiffrez les données sensibles avec une primitive éprouvée comme sodium, et terminez HTTPS avec des en-têtes de sécurité à un reverse proxy. Déléguez à des outils audités au lieu de bricoler la cryptographie, et respectez les bases pratiques de protection des données du GDPR et de HIPAA.

Date de publication

16 juillet 2026

Modifié

16 juillet 2026

AstucePoints clés
  • Déléguez, ne bricolez pas. Chaque contrôle ci-dessous est un outil éprouvé que vous configurez — requêtes paramétrées, chiffrement audité, magasin de secrets de votre plateforme, un reverse proxy pour HTTPS. Écrire votre propre cryptographie ou construire vos requêtes à la main, c’est ainsi que les failles sont livrées.
  • Ne collez jamais l’entrée utilisateur dans une requête. Construisez le SQL avec des marqueurs ? et params = list(...) ; la base de données traite l’entrée comme une valeur, pas comme du code, et la charge utile d’injection ne fait rien.
  • Gardez les secrets hors du code source. Lisez chaque mot de passe, clé et jeton depuis une variable d’environnement avec Sys.getenv() ; ajoutez .Renviron et *.pem à .gitignore pour qu’un secret n’atterrisse jamais dans git.
  • Validez avant de calculer. Vérifiez le type, la plage et une liste d’autorisation avec validate(need(...)) et rejetez tout ce qui est inattendu — la première ligne de défense contre l’injection et les données erronées.
  • HTTPS se termine au proxy, pas dans Shiny. Placez nginx, Traefik ou Caddy en frontal pour gérer le TLS (Transport Layer Security) et définir les en-têtes de sécurité ; chiffrez les données sensibles au repos avec sodium.

Introduction

Votre application est en ligne sur une URL publique — vous l’avez conteneurisée ou déployée sur un serveur — et elle fait un vrai travail : elle prend des entrées depuis un formulaire, interroge une base de données, détient une clé d’API (application programming interface), et touche peut-être des données personnelles. Cette surface est exactement ce qu’un attaquant sonde. Les menaces sont concrètes : l’injection (fournir à votre requête ou au code de votre page quelque chose de déguisé en entrée), les secrets divulgués (un mot de passe validé dans git), les données non chiffrées (lisibles dès qu’un disque ou une sauvegarde s’en va), et l’écoute du trafic (une connexion envoyée en clair).

La règle qui les gouverne toutes est la même que celle de l’authentification : déléguez à un outil éprouvé, ne bricolez jamais la partie critique pour la sécurité. Concrètement, cinq contrôles renforcent une application Shiny, et cette leçon les parcourt un à un : validez chaque entrée, paramétrez chaque requête, gardez les secrets dans l’environnement, chiffrez les données sensibles avec une primitive auditée, et placez HTTPS avec des en-têtes de sécurité en frontal. C’est la moitié « garder l’application sûre » du durcissement ; sa leçon d’authentification compagne couvre la moitié « qui entre » — connexion, rôles et authentification unique — de sorte que cette leçon ne les réenseigne pas.

NotePrérequis

Il vous faut une application déployée à renforcer — si vous n’en avez pas, construisez votre première application Shiny, puis conteneurisez-la ou servez-la avec ShinyProxy. Les exemples R utilisent DBI pour l’accès à la base de données et sodium pour le chiffrement (install.packages(c("DBI", "sodium"))) ; la section HTTPS suppose un reverse proxy (nginx, Traefik ou Caddy) en frontal de l’application.

NoteCopiez n’importe quel bloc et exécutez-le en local

Le code de cette page n’est pas exécuté ici — une application Shiny et une base de données active ont besoin d’une session R qu’une page web statique ne peut pas héberger. Copiez n’importe quel bloc dans votre application et exécutez-le en local pour reproduire le comportement. Le vrai test, c’est ce qui se passe quand vous tentez vous-même l’attaque : envoyez la charge utile d’injection à travers une requête paramétrée et regardez-la ne rien renvoyer. The runtime is the judge.

Validez chaque entrée

Traitez chaque valeur venant du navigateur comme hostile jusqu’à preuve du contraire. Les entrées Shiny arrivent telles que le client les envoie — un curseur peut être falsifié, une zone de texte peut contenir n’importe quoi. Validez le type, la plage et une liste d’autorisation avant de calculer, et refusez tout ce qui est inattendu. La fonction validate() / need() propre à Shiny est le garde-fou idiomatique : elle arrête le réactif et affiche un message au lieu de laisser une mauvaise valeur atteindre votre logique.

observeEvent(input$go, {
  n <- suppressWarnings(as.integer(input$n))
  validate(need(!is.na(n) && n > 0 && n <= 1000,
                "Enter a whole number between 1 and 1000."))
  # ... only runs on valid input
})

as.integer() convertit l’entrée brute ; la vérification need() confirme qu’il s’agit d’un nombre entier dans la plage autorisée et bloque tout le reste. Appliquez le même schéma à chaque entrée : convertissez au type attendu, bornez la plage, et pour les entrées catégorielles vérifiez l’appartenance à une liste d’autorisation (input$region %in% valid_regions) plutôt que d’essayer de mettre les mauvaises valeurs sur liste noire. Pour les téléversements de fichiers, ne faites jamais confiance au nom fourni par le client — validez la taille et l’extension (et, pour des contrôles plus stricts, le type MIME du fichier, car une extension est facile à falsifier), générez votre propre nom de fichier, et écrivez dans un répertoire temporaire, pas dans un chemin servi sur le web :

observeEvent(input$file, {
  up <- input$file
  ext <- tolower(tools::file_ext(up$name))
  validate(need(ext %in% c("csv", "txt"), "Upload a .csv or .txt file."))
  validate(need(up$size <= 10 * 1024^2, "File must be under 10 MB."))
  dest <- file.path(tempdir(), paste0("upload_", as.integer(Sys.time()), ".", ext))
  file.copy(up$datapath, dest)
})

La validation n’est pas qu’une défense — c’est le premier geste qui réduit tous les autres risques, car une entrée malformée est la porte d’entrée de l’injection et de la corruption.

Bloquez l’injection SQL avec des requêtes paramétrées

L’attaque classique sur les bases de données : vous construisez une requête en collant l’entrée utilisateur dans une chaîne, et une valeur forgée réécrit la requête. Le remède : ne construisez jamais de SQL (Structured Query Language) à partir de chaînes — passez l’entrée utilisateur comme paramètre. Avec DBI, cela signifie des marqueurs ? et une liste params ; le pilote de la base de données envoie votre entrée comme une valeur littérale, de sorte qu’elle ne peut jamais être interprétée comme du SQL (OWASP : injection SQL).

library(DBI)

# NEVER build SQL by pasting user input — this is injectable:
#   dbGetQuery(con, paste0("SELECT * FROM users WHERE name = '", input$name, "'"))

# SAFE: pass user input as a PARAMETER; the database treats it as a literal value, not SQL.
safe <- dbGetQuery(con, "SELECT * FROM users WHERE name = ?", params = list(input$name))

La différence n’est pas cosmétique. Envoyez la charge utile d’injection alice' OR '1'='1 — conçue pour rendre la clause WHERE toujours vraie et vider toute la table — à travers la requête paramétrée, et elle renvoie 0 ligne : la base de données cherche un utilisateur littéralement nommé alice' OR '1'='1, n’en trouve aucun, et l’attaque s’effondre. La version paste0() mise en commentaire, en revanche, renverrait chaque ligne. Paramétrez chaque requête qui touche l’entrée utilisateur ; il n’existe aucune quantité sûre de SQL construit à partir de chaînes.

Le XSS — cross-site scripting — est la même idée dirigée vers la page plutôt que vers la base de données : un attaquant fait afficher son balisage ou son script dans le navigateur d’un autre utilisateur. Shiny s’en défend par défaut — textOutput() et consorts échappent leur contenu, de sorte que le texte de l’utilisateur s’affiche comme du texte, pas comme du HTML. Le risque n’apparaît que lorsque vous rendez délibérément du HTML brut : htmlOutput()/renderUI() alimenté par une valeur construite à partir de l’entrée utilisateur, ou en enveloppant l’entrée utilisateur dans HTML(). Quand vous devez le faire, échappez-la d’abord avec htmltools::htmlEscape(), ou mieux, évitez tout bonnement d’injecter l’entrée utilisateur dans du HTML brut. La règle reflète celle du SQL : ne concaténez jamais une entrée non fiable dans quelque chose qui sera interprété (OWASP : XSS).

Gardez les secrets hors de votre code

Un mot de passe de base de données, une clé d’API ou une phrase secrète de chiffrement ne doivent jamais résider dans votre code source — un seul commit et c’est dans votre historique git pour toujours, lisible par quiconque clone un jour le dépôt. Lisez chaque secret depuis une variable d’environnement avec Sys.getenv(), et définissez la valeur dans la plateforme où l’application s’exécute, pas dans le code :

con <- DBI::dbConnect(
  RPostgres::Postgres(),
  host     = Sys.getenv("DB_HOST"),
  dbname   = Sys.getenv("DB_NAME"),
  user     = Sys.getenv("DB_USER"),
  password = Sys.getenv("DB_PASSWORD")   # from the environment, never in code
)

api_key <- Sys.getenv("API_KEY")

L’endroit où vous définissez ces variables dépend de votre hébergeur : sur shinyapps.io, utilisez le Settings → Variables du tableau de bord ; dans un conteneur, passez -e DB_PASSWORD=... ou un secret Docker/Kubernetes ; sur un serveur ordinaire, utilisez un fichier .Renviron que R lit au démarrage. Quel que soit votre choix, la règle d’or tient : ne validez jamais un secret dans git. Ajoutez .Renviron, *.pem et tout fichier de clé à .gitignore, et si un secret finit malgré tout par être validé, renouvelez-le — supprimer la ligne ne suffit pas, car il vit dans l’historique. Les leçons ShinyProxy et Docker montrent où définir les variables d’environnement dans chaque déploiement.

Chiffrez les données sensibles avec une primitive éprouvée

Quand vous stockez des données personnelles ou confidentielles, chiffrez-les au repos — pour qu’un disque volé, une sauvegarde ou un export de base de données soit illisible. N’inventez pas de chiffrement. Utilisez une primitive auditée : sodium (liaisons vers libsodium) ou openssl, tous deux maintenus et revus. Voici un aller-retour avec sodium, avec une clé issue d’une variable d’environnement pour que la clé elle-même ne soit jamais dans le code source :

library(sodium)

key <- hash(charToRaw(Sys.getenv("APP_ENC_KEY")))   # key from an env var, never in code
ct  <- data_encrypt(serialize(secret_value, NULL), key)
pt  <- unserialize(data_decrypt(ct, key))            # round-trips back to secret_value

serialize() transforme n’importe quel objet R en octets bruts, data_encrypt() les chiffre sous la clé, et data_decrypt() plus unserialize() récupère exactement la valeur d’origine. La clé est dérivée de APP_ENC_KEY — définie dans l’environnement comme tout autre secret — de sorte que perdre le code source ne perd pas les données, et perdre l’environnement ne les expose pas. Utilisez une valeur à forte entropie pour cette clé (par exemple openssl rand -hex 32) ; si vous devez la dériver d’une phrase secrète choisie par un humain, passez-la d’abord par une fonction de dérivation de clé comme argon2 plutôt que de la hacher directement. C’est tout l’intérêt de déléguer à une bibliothèque éprouvée : le chiffrement authentifié, la gestion correcte du nonce et la comparaison à temps constant sont fournis gratuitement et correctement. N’écrivez jamais à la main un « chiffrement » XOR, un schéma maison ou un condensé rapide non salé en l’appelant chiffrement.

Le chiffrement en transit est l’autre moitié — et vous l’obtenez de HTTPS, juste après.

Placez HTTPS et des en-têtes de sécurité en frontal

Shiny parle du HTTP simple ; il ne sert pas lui-même le HTTPS (HTTP over TLS). Ainsi, une connexion ou toute donnée envoyée à une application Shiny nue voyage en clair, lisible par quiconque se trouve sur le chemin. Le remède standard est un reverse proxy — nginx, Traefik ou Caddy — placé en frontal de l’application : il termine le TLS sur le port 443 et transmet du HTTP simple à Shiny à l’intérieur. C’est le même reverse proxy que la leçon ShinyProxy place en frontal pour une équipe ; Traefik et Caddy peuvent même récupérer et renouveler automatiquement des certificats Let’s Encrypt gratuits.

Le proxy est aussi l’endroit où vous définissez les en-têtes de sécurité — des instructions qui disent au navigateur de se durcir lui-même. Définissez-les une seule fois au proxy pour que chaque réponse les porte. Avec nginx :

# inside the server { } block that proxies to Shiny
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "DENY" always;
add_header Content-Security-Policy "default-src 'self'" always;

Chaque en-tête ferme une classe d’attaque (documentation de add_header nginx, sécurité web MDN) :

  • HSTS (HTTP Strict Transport Security)Strict-Transport-Security force le navigateur à utiliser HTTPS pour les prochaines visites, déjouant une rétrogradation vers du HTTP simple.
  • X-Content-Type-Options: nosniff empêche le navigateur de deviner le type d’une réponse, un vecteur pour le tromper et lui faire exécuter des données comme du script.
  • X-Frame-Options: DENY empêche votre application d’être intégrée dans une <iframe> sur un autre site (clickjacking) ; une directive CSP frame-ancestors fait de même, avec plus de souplesse.
  • CSP (Content-Security-Policy) restreint les emplacements d’où les scripts, styles et autres ressources peuvent être chargés, limitant fortement le XSS. Commencez strict (default-src 'self') et n’assouplissez que ce dont votre application a réellement besoin — les applications Shiny ont souvent besoin d’autoriser des styles en ligne ou des CDN spécifiques, alors testez soigneusement.

L’équivalent sous forme de middleware Traefik, si vous routez avec Traefik (documentation des en-têtes Traefik) :

http:
  middlewares:
    secure-headers:
      headers:
        stsSeconds: 31536000
        stsIncludeSubdomains: true
        contentTypeNosniff: true
        frameDeny: true
        contentSecurityPolicy: "default-src 'self'"

À retenir : le TLS se termine au reverse proxy, pas dans Shiny, et le proxy est le seul endroit où définir les en-têtes pour chaque réponse.

Protection des données : les bases du GDPR et de HIPAA

Si votre application touche des données personnelles, deux réglementations s’appliquent le plus souvent : le GDPR (General Data Protection Regulation — le règlement général sur la protection des données de l’UE) et, pour les données de santé américaines, l’HIPAA (Health Insurance Portability and Accountability Act). Cette section est une liste de contrôle d’ingénierie pratique, pas un conseil juridique — consultez un professionnel qualifié et les sources primaires pour vos obligations : le texte officiel du GDPR (gdpr.eu) et la règle de sécurité HIPAA du HHS.

Les contrôles techniques que les deux régimes récompensent correspondent directement à ce que vous avez déjà construit :

  • Collectez le minimum. Ne demandez que les PII (personally identifiable information — données à caractère personnel) dont vous avez réellement besoin — une donnée que vous ne détenez jamais ne peut pas fuiter. Le GDPR appelle cela la minimisation des données.
  • Chiffrez au repos et en transit. Le chiffrement sodium et le proxy HTTPS ci-dessus en sont les mises en œuvre concrètes ; les deux réglementations attendent que les données sensibles soient protégées sur le disque et sur le fil.
  • Contrôlez et journalisez les accès. Protégez l’application par authentification, restreignez qui voit quoi selon le rôle, et tenez un journal des accès pour pouvoir répondre à qui a vu ceci, et quand — la règle de sécurité HIPAA attend des contrôles d’audit.
  • Honorez la suppression et la conservation. Soyez en mesure de supprimer les données d’un utilisateur sur demande (un droit du GDPR) et ne conservez pas les données plus longtemps que votre durée de conservation annoncée.
  • Obtenez le consentement et soyez transparent. Enregistrez le consentement pour le traitement que vous effectuez, et dites aux utilisateurs ce que vous collectez et pourquoi.

Ce sont des principes, pas une garantie de conformité — les exigences complètes des réglementations relèvent de la gouvernance, des contrats et de l’examen juridique, bien au-delà du code de l’application. Construisez correctement les contrôles techniques et vous disposez du socle d’ingénierie sur lequel repose le reste.

Quel contrôle arrête quelle menace

Faites correspondre chaque risque au contrôle qui le ferme — et notez que chaque contrôle est une délégation à un outil éprouvé, jamais un schéma bricolé maison :

Menace Contrôle Comment
Entrée malformée / hostile Validation des entrées validate(need(...)), type + plage + liste d’autorisation
Injection SQL Requêtes paramétrées marqueurs ? de DBI + params = list(...)
XSS Échappement par défaut + CSP Laissez Shiny échapper ; htmlEscape() pour le HTML brut
Identifiants divulgués Secrets dans l’environnement Sys.getenv() ; .gitignore sur les fichiers de clé
Vol de données au repos Chiffrement sodium/openssl, clé depuis une variable d’env
Écoute du trafic HTTPS à un reverse proxy nginx/Traefik termine le TLS + définit les en-têtes
Accès non autorisé Authentification Déléguez la connexion et les rôles (leçon compagne)

Problèmes fréquents

Un secret fonctionne en local mais l’application déployée ne peut pas se connecter. Sys.getenv("DB_PASSWORD") renvoie "" en production parce que la variable n’est pas définie dans l’environnement déployé — un .Renviron sur votre portable ne voyage pas avec l’application. Définissez chaque secret dans les paramètres d’environnement/de secrets de votre plateforme (Variables shinyapps.io, un drapeau -e ou un secret de conteneur, le .Renviron du serveur) et confirmez avec une vérification rapide nchar(Sys.getenv("DB_PASSWORD")) > 0 au démarrage.

Une requête « parfois » échoue sur certains noms. Un nom avec une apostrophe (O'Brien) casse une requête construite par chaîne — c’est exactement la faille d’injection qui se manifeste avec des données bénignes. Le remède est le même que pour l’attaque : passez à une requête paramétrée avec ? et params, et l’apostrophe (comme toute charge utile) est traitée comme une valeur littérale.

L’application se charge en HTTPS mais le navigateur signale du « contenu mixte » ou bloque des ressources. Votre Content-Security-Policy est trop stricte pour ce que l’application charge (un style en ligne, un script de CDN, une police web), ou une ressource est demandée en http://. Lisez la console du navigateur pour l’URL exacte bloquée, puis assouplissez la directive CSP pour cette source spécifique (jamais en unsafe-inline à l’échelle globale) et servez chaque ressource en HTTPS.

Questions fréquentes

Superposez cinq contrôles, chacun délégué à un outil éprouvé : validez chaque entrée avec validate(need(...)) ; bloquez l’injection SQL en utilisant des requêtes DBI paramétrées (marqueurs ? + params) ; gardez les secrets dans des variables d’environnement lues avec Sys.getenv(), jamais dans le code ; chiffrez les données sensibles avec une bibliothèque auditée comme sodium ; et placez un reverse proxy (nginx, Traefik, Caddy) en frontal pour HTTPS et les en-têtes de sécurité. Ajoutez l’authentification pour le contrôle d’accès. Ne bricolez jamais la cryptographie et ne construisez pas de SQL à partir de chaînes.

Ne collez jamais l’entrée utilisateur dans une chaîne de requête. Utilisez une requête paramétrée : dbGetQuery(con, "SELECT * FROM users WHERE name = ?", params = list(input$name)). Le ? est un marqueur et la base de données traite input$name comme une valeur littérale, de sorte qu’une charge utile comme alice' OR '1'='1 renvoie 0 ligne au lieu de vider la table (OWASP : injection SQL). Paramétrez chaque requête qui touche l’entrée utilisateur.

Dans des variables d’environnement, jamais dans le code source. Lisez-les avec Sys.getenv("API_KEY") / Sys.getenv("DB_PASSWORD"), et définissez les valeurs dans votre plateforme : shinyapps.io Settings → Variables, une variable d’environnement ou un secret de conteneur, ou un .Renviron ignoré par git sur un serveur. Ajoutez .Renviron et tout fichier de clé à .gitignore pour qu’un secret n’atteigne jamais git ; si l’un d’eux est un jour validé, renouvelez-le.

Aucun framework ne rend une application automatiquement conforme — la conformité tient à la façon dont vous traitez les données, pas à l’outil que vous utilisez. Techniquement, vous collectez le minimum de PII, les chiffrez au repos (sodium) et en transit (HTTPS), contrôlez et journalisez les accès, et prenez en charge la suppression et le consentement. Mais les exigences complètes sont juridiques et organisationnelles, alors traitez ceci comme un travail d’ingénierie de fond, pas un conseil juridique — consultez le texte officiel du GDPR, la règle de sécurité HIPAA du HHS, et un professionnel qualifié.

Shiny ne sert pas le TLS lui-même — placez un reverse proxy en frontal. Faites tourner nginx, Traefik ou Caddy sur le port 443 pour terminer HTTPS et transmettre du HTTP simple à Shiny en interne ; Traefik et Caddy peuvent récupérer et renouveler automatiquement des certificats Let’s Encrypt gratuits. Définissez vos en-têtes de sécurité (HSTS, X-Content-Type-Options, X-Frame-Options, CSP) à ce proxy pour que chaque réponse les porte. Voyez la leçon ShinyProxy pour le schéma du proxy.

Testez vos connaissances

Cette recherche colle l’entrée utilisateur directement dans la chaîne SQL — elle est grande ouverte à l’injection. Réécrivez-la pour que l’entrée ne puisse jamais être interprétée comme du SQL.

# UNSAFE — do not ship this
result <- dbGetQuery(
  con,
  paste0("SELECT * FROM orders WHERE customer = '", input$customer, "'")
)

Remplacez la valeur collée par un marqueur ? et passez input$customer via l’argument params sous forme de liste à un élément. La chaîne SQL ne doit contenir aucune entrée utilisateur.

result <- dbGetQuery(
  con,
  "SELECT * FROM orders WHERE customer = ?",
  params = list(input$customer)
)

Le texte de la requête est désormais figé et ne porte aucune entrée utilisateur ; input$customer est envoyé séparément comme paramètre, de sorte que la base de données le traite comme une valeur littérale à comparer, jamais comme du SQL à exécuter. Envoyez la charge utile x' OR '1'='1 et elle correspond à un client littéralement nommé x' OR '1'='1 — zéro ligne — au lieu de renvoyer chaque commande. Faites-le pour chaque requête qui touche l’entrée utilisateur.

Vous devez stocker une clé d’API que votre application Shiny utilise pour appeler un service externe. Quelle est la bonne approche ?

A. L’assigner à une variable en haut de app.R pour la retrouver facilement.
B. La lire avec Sys.getenv("API_KEY") et définir la valeur dans l’environnement de votre plateforme, avec .Renviron dans .gitignore.
C. Écrire votre propre fonction pour chiffrer la clé et stocker le texte chiffré dans le dépôt.
D. La mettre dans un fichier de configuration validé à côté de l’application pour que les déploiements restent synchronisés.

B. Les secrets ont leur place dans l’environnement, lus avec Sys.getenv() et définis là où l’application s’exécute — jamais dans le code source. A et D valident tous deux la clé dans git, où elle vit dans l’historique pour toujours même supprimée plus tard. C bricole la cryptographie (un non catégorique) et livre malgré tout un secret chiffré plus, inévitablement, sa clé dans le même dépôt. Gardez la clé entièrement hors du contrôle de version et mettez sur .gitignore les fichiers qui la contiennent.

Conclusion

Durcir une application Shiny est une série de délégations, pas un projet de cryptographie. Validez chaque entrée avec validate(need(...)) et refusez l’inattendu. Bloquez l’injection en paramétrant chaque requête — marqueurs ? et params, jamais de SQL construit par chaîne — et laissez l’échappement par défaut de Shiny (plus une CSP) gérer le XSS. Gardez chaque secret dans une variable d’environnement lue avec Sys.getenv(), et mettez sur .gitignore les fichiers qui les contiennent. Chiffrez les données sensibles au repos avec une bibliothèque auditée comme sodium, avec une clé issue de l’environnement, et terminez HTTPS avec des en-têtes de sécurité à un reverse proxy en frontal de l’application. Associez cela à l’authentification pour le contrôle d’accès, suivez les bases du GDPR/HIPAA là où elles s’appliquent, et vous obtenez une application Shiny de production qui résiste aux menaces réelles — parce qu’à chaque étape vous avez configuré un outil éprouvé au lieu d’en inventer un. Avant de passer en production, parcourez cette liste une fois de plus comme une liste de contrôle de déploiement : entrées validées, requêtes paramétrées, secrets dans l’environnement, données chiffrées, HTTPS et en-têtes en frontal.

Leçons connexes

Cette page vous a-t-elle été utile ?

Prouvez que vous savez le faire. Maîtrisez toute la série Shiny en production — suivez votre parcours, construisez des projets et obtenez un certificat.

Commencer gratuitement →

Passez à Pro — Prova illimité sur vos propres données et un certificat vérifiable qui atteste la compétence.

dès 15 $/mois facturé annuellement

Passer à Pro →

✓ Vous êtes Pro — continuez. The runtime is the judge.

Recevez les nouvelles leçons R & Python par e-mail

Pratique, reproductible, sans spam. Désinscription à tout moment.

Double opt-in. Nous ne partageons jamais votre e-mail.

Partager cette pageXLinkedInRedditHN

Réutilisation

Citation

BibTeX
@online{2026,
  author = {},
  title = {Sécurité Shiny : renforcez votre application contre les
    menaces réelles},
  date = {2026-07-16},
  url = {https://www.datanovia.com/learn/programming/shiny/production/security},
  langid = {fr}
}
Veuillez citer ce travail comme suit :
“Sécurité Shiny : renforcez votre application contre les menaces réelles.” 2026. July 16. https://www.datanovia.com/learn/programming/shiny/production/security.