Rails est un framework de développement d'applications Web écrit dans le langage de programmation Ruby. Rendu des modèles HTML, mise à jour des bases de données, envoi et réception d'e-mails, maintenance des pages en direct via WebSockets, mise en file d'attente des travaux pour un travail asynchrone, stockage des téléchargements dans le cloud. Ce framework a de nombreuses options de sécurité intégrées, mais elles peuvent être désactivées par les développeurs :)
- Le code source ne repose pas sur des informations d'identification et des secrets codés en dur.
- L'application n'utilise pas d'échappement de caractères HTML comme
brut
,html_safe
,content_tag
etc. L'application n'a pas d'indicateur de sécurité défini surActiveSupport ::escape_html_entities_in_json = faux
, ce qui peut conduire à XSS lors de l'utilisationto_json()
méthode. - Le
protect_from_forgery
réglage est défini dans les contrôleurs, le<%= csrf_meta_tags %>
paramètre est défini dans les modèles HTML. - Les utilisateurs n'ont aucun contrôle direct sur le rendu des modèles ERB.
- L'application valide l'entrée de l'utilisateur et ne l'envoie pas aux fonctions dangereuses telles que
eval
. - L'application utilise la paramétrisation au lieu de la concaténation lors de la création de requêtes SQL.
- L'application utilise
config.force_ssl = vrai
. Assurez-vous que l'application utilise un algorithme de hachage fort pour les signatures de cookies dans leRails.application.config.action_dispatch.signed_cookie_digest = "SHA256"
paramètre. Les environnements doivent utiliser une clé aléatoire présente dansconfig/credentials.yml.enc
et la clé doit être cryptée. - Les URL contrôlées par l'utilisateur ne sont pas autorisées à demander des ressources internes et à rediriger un utilisateur vers des services tiers.
- L'application utilise
\A \z
pour définir le début et la fin de la chaîne ou spécifiermultiligne : **vrai
.** - L'application n'utilise pas
Maréchal
bibliothèque pour sérialiser et désérialiser des objets. - L'application a appliqué une liste de paramètres autorisés dans
permis
méthode, qui limite les paramètres à modifier par un utilisateur. - L'application n'a pas d'indicateur de sécurité défini sur
config.active_record.whitelist_attributes=false
, qui signifie affectation de masse. - L'application n'utilise pas
URI#ouvert
méthode deopen-uri
bibliothèque.
Les applications Web RoR suivent l'architecture MVC (modèle, vue et contrôleur). La plupart des vulnérabilités côté client apparaissent dans le composant de vue. Les vues sont construites avec le moteur de modèle ERB, donc même les vulnérabilités SSTI sont assez courantes. Toute la logique métier côté serveur est gérée par le composant contrôleur. Les développeurs doivent être conscients de la sécurité des applications RoR, car la plupart des vulnérabilités apparaissent dans des spécificités uniques considérées uniquement pour les applications RoR. La section suivante décrit les pièges de sécurité courants et la façon dont leurs modèles peuvent être identifiés lors de l'examen du code source. Ils se produisent généralement lorsque les développeurs désactivent les options de sécurité intégrées ou ne suivent pas les pratiques de codage de sécurité.
Architecture cadre
L'application RoR (Ruby on Rails) a la structure de base de code suivante :
.├── Dockerfile #version du logiciel, informations d'identification codées en dur├── Gemfile #versions du logiciel├── Gemfile.lock #versions du logiciel├── app│ ├── actifs # images, vidéo, etc│ ├── contrôleurs #toute la logique d'application situé ici│ │ ├── admin_controller.rb│ │ ├── users_controller.rb│ ├── helpers #helper - méthode qui est (principalement) utilisée pour partager du code réutilisable│ │ ├── admin_helper.rb│ ├── expéditeurs #permet d'envoyer des e-mails depuis votre application à l'aide de classes de messagerie│ │ └── user_mailer.rb│ ├── models #Classe Ruby utilisée pour représenter les données │ │ ├── user.rb│ └── vues # Modèles HTML│ ├ ── admin│ │ ├── get_all_users.html.erb├── config #configuration de l'application, doit être revue car les développeurs peuvent désactiver les fonctionnalités de sécurité│ ├── application.rb #application configuration│ ├── boot.rb│ ├─ ─ database.yml #configuration de la base de données, peut contenir des identifiants codés en dur│ ├── environment.rb│ ├── environnements│ │ ├── development.rb #application configuration│ ├── initializers│ │ ├── constants.rb # hardcoded indementings│ │ ├── filter_parameter_logging.rb # logging│ │ ├── html_entities.rb #enables ou désactive l'échappement des entités HTML dans la sérialisation JSON│ │ ├fique_TOKE.RB #hardcoded .rb #signature de cookies│ │ ├── session_store.rb #comment le magasin de session est organisé│ ├── locales│ │ └── en.yml #informations d'identification codées en dur│ ├── routes.rb #Première chose à étudier, le routage des applications │ ├── secrets.yml #Les identifiants/secrets sont-ils chiffrés ?│ └── secrets2.yml #Les identifiants/secrets sont-ils chiffrés ?├── db│ ├── schema.rb #schéma de la base de données│ └── seeds.rb # données de base de données, peuvent contenir des identifiants codés en dur├── lib #extended modules│ ├── encryption.rb #encryption├── log #log files├── public #static files et compiled assets│ ├── 404.html│ └── robots.txt├── script├── spec #à des fins de test└── fournisseur #code tiers
[Comprendre la structure de votre application Rails [Guide du débutant] | HackerNoon](https://hackernoon.com/understanding-your-rails-application-structure-r8w32xj)
Premiers pas avec Rails - Guides Ruby on Rails
Fichiers sensibles
/config/database.yml-Maycontainproductioncredentials./config/initializers/secret_token.rb-Containsasecretusedtohashsessioncookies./db/seeds.rb-Maycontainseeddata includingbootstrapadminuser./db/development.sqlite3-Maycontainrealdata.
Architecture MVC
Les routes, les contrôleurs, les actions, les vues et les modèles sont des éléments typiques d'une application Web qui suit leMVC (Modèle-Vue-Contrôleur)modèle. MVC est un modèle de conception qui divise les responsabilités d'une application pour faciliter le raisonnement. Rails suit ce modèle de conception par convention.
Itinéraires
Nous vous recommandons de commencer l'examen de sécurité avec le routage de l'application, car il permet de mapper les routes avec ses gestionnaires pour comprendre la structure de l'API de l'application. Le routeur détermine quel type de contrôleur et d'action doit réellement exécuter le code. Le routage des applications est décrit dans/config/routes.rb
déposer.
La base de code ci-dessous traiterait la demande des utilisateurs, s'ils demandent lehttps://app.domain.com/patients/
URL. Lorsque le serveur RoR reçoit la demande de l'utilisateur, il sait qu'il doit exécuter du code dans le contrôleurles patients
et actionsmontrer
.
obtenir '/patients/:id', en : 'patients#show'
On pourrait aussi trouver quelque chose comme ça :
Déclarez toutes les routes communes pour un contrôleur ingénieux donné comme
indice
,montrer
,nouveau
,modifier
,créer
,mise à jour
, etdétruire
Actions.ressources :photos
Limitez les actions qui peuvent être utilisées pour le contrôleur ingénieux.
ressources :comments, only: [:show, :edit, :update, :destroy]
Organisez les ressources sous l'espace de noms "admin" et accédez-y comme /admin/posts ou /admin/comments.
espace de noms "admin" do resources :posts, :commentsend
Suivez la documentation pour d'autres mappages de routes possibles :
ActionDispatch::Routage::Mappeur
Routage des rails de l'extérieur vers l'intérieur - Guides Ruby on Rails
Contrôleurs et actions
Les contrôleurs sont une logique métier d'application réelle, chaque contrôleur peut être trouvé dans leapp/controllers/..
dossier. Exemple:
├── app│ ├── contrôleurs #toute la logique d'application située ici│ │ ├── admin_controller.rb
Exemple de contrôleur simple. Un contrôleur est une classe Ruby qui hérite de baseContrôleur d'application
classe et toutes ses méthodes. Le<
chanter est un héritage.
class ClientsController < ApplicationController def new endend
Par exemple, si un utilisateur se rend sur/clients/nouveau
path dans votre application pour ajouter un nouveau client, Rails créera une instance deClientsContrôleur
contrôleur et exécuter sonnouveau
méthode. Ce qui vaut la peine d'être mentionné, c'est que la méthode vide de l'exemple ci-dessus fonctionnerait. Parce que Rails rendrait lenouveau.html.erb
view par défaut, sauf si la méthode définit une logique différente. En créant un nouveauClient
, lenouveau
méthode peut faire un@client
variable d'instance accessible dans la vue :
def new @client = Client.newend
Présentation du contrôleur d'action - Guides Ruby on Rails
Présentation du contrôleur d'action - Guides Ruby on Rails
Vues
Les vues sont stockées dans les éléments suivantsapp/views/[controller]/[view_name].html.erb
chemin du motif. View est une simple page HTML gérée par le moteur de modèle ERB, qui affiche les valeurs renvoyées par le contrôleur.
Articles
<% @articles.each font |article| %> - <%= article.title %>
<% end %>
La méthodologie de mappage des routes vers les vues est la suivante :
L'action du contrôleur a le même nom dans le fichier de routes qu'un nom de vue.
- Si la
ressources
spécifié, un nom de vue correspond à l'action d'un contrôleur. Par exemple,POSTE
appels de méthodecréer
action et la vue app/views/[controller]/create.html.erb s'affiche.
- Si la
Rendre
est utilisée dans le code ou le modèle du contrôleur lui-même pour afficher une vue.
Dispositions et rendu dans les rails - Guides Ruby on Rails
Des modèles
Amodel est une classe Ruby utilisée pour représenter des données. De plus, les modèles peuvent interagir avec la base de données de l'application via une fonctionnalité de Rails appelée Active Record.
Exemple de modèle utilisateur situé sousapplication/modèles
:
classe User < ApplicationRecord valide :nom, présence : trueend
Le modèle est utilisé pour décrire l'objet et l'utiliser via l'application.
Principes de base de l'enregistrement actif - Guides Ruby on Rails
XSS
Par défaut, RoR échappe les entités HTML, mais il propose quelques méthodes pour désactiver l'échappement des caractères HTML commebrut
,html_safe
,content_tag
etc.
La variable sans échappement entre dans le moteur de modèle dans le code Ruby
html = "
#{nom}".html_safecontent_tag :p, "Bonjour, #{nom}"
raw @user.name
config.active_support.escape_html_entities_in_json = faux
Cela conduit à XSS, quandHachage#to_json()
utilisé.
Contournement du moteur de template
ERB.new("
#{@user.name}").resultrendu en ligne : "
#{@user.name}"texte de rendu : "
#{@user.name}"
Modèles : Variable explicitement unescape
<%= nom.html_safe %>
<%= content_tag :p, "Bonjour, #{nom}" %>
<%= raw @user.name =>
<%== @nom.utilisateur %>
Modèles : variable dans un endroit dangereux
Prévention XSS pour Ruby on Rails | SemgrepName
Injection de commande
Liste des récepteurs d'injection de commande :
eval("code ruby ici")system("commande os ici")`ls -al /` # (les raccourcis contiennent la commande os)exec("commande os ici")spawn("commande os ici")open("| os commande ici")URI#open de open-uriProcess.exec("commande os ici")Process.spawn("commande os ici")IO.binread("| commande os ici")IO.binwrite("| commande os ici") ", "foo")IO.foreach("| commande os ici") {}IO.popen("commande os ici")IO.read("| commande os ici")IO.readlines("| commande os ici" )IO.write("| commande os ici", "foo")syscall%x() %x %x{} %x-os-popenexecOpen3.popen3()fork()PTY.spawn()constantize
Injection SQL
La concaténation de l'entrée utilisateur avec le paramètre de requête SQL entraînera une injection SQL. Exemple:
User.where("name = '#{params[:name]}'") # SQL Injection !
Pour atténuer le risque de ce type d'injection SQL, l'application doit utiliser la paramétrisation, il y en a 2 exemples :
User.where(["nom = ?", "#{params[:nom]}"])
User.where({ nom : params[:nom] })
Dans ces 2 exemples, il n'y a pas d'opérations directes avec requête SQL, colonnenom
est défini explicitement sur lenom
clé.
Méthodes potentiellement vulnérables
Méthodes de calcul
Calculer
fonction prend une opération et uncolonne
nom pour calculer un montant ou trouver une valeur maximum/minimum/moyenne. Lecolonne
value est un paramètre contrôlé par l'utilisateur :
Order.calculate(:sum, params[:column])
Étant donné que la paramétrisation et la désinfection manquent, l'utilisateur peut manipuler une valeur de colonne et obtenir une injection SQL limitée. Un attaquant pourrait calculer des valeurs à partir des autres tables :
params[:column] = "age) FROM utilisateurs WHERE nom = 'Bob';"
La requête SQL finale additionne un âge d'utilisateurs nommé Bob à partir de la table des utilisateurs :
QuerySELECT SUM(age) FROM utilisateurs WHERE nom = 'Bob';Result76
Supprimer par méthode
Ledelete_all
prend le même type d'arguments de conditions queoù
.L'argument peut être une chaîne, un tableau ou un hachage de conditions. Les chaînes ne seront pas du tout échappées. Utilisez un tableau ou un hachage pour paramétrer les arguments.
User.delete_by("id = #{params[:id]}")
Cet exemple ignore toutes les conditions et supprime tous les utilisateurs.
params[:id] = "1) OR 1=1--"
La requête SQL finale supprime tous les utilisateurs et le résultat renvoie un nombre d'utilisateurs supprimés :
RequêteDELETE FROM "utilisateurs" WHERE (id = 1) OR 1=1--)Result6
Détruire par méthode
Ledestroy_by
prend le même type d'arguments de conditions queoù
.L'argument peut être une chaîne, un tableau ou un hachage de conditions. Les chaînes ne seront pas du tout échappées. Utilisez un tableau ou un hachage pour paramétrer en toute sécurité les arguments.
User.destroy_by(["id = ? AND admin = '#{params[:admin]}", params[:id]])
Cet exemple ignore toutes les conditions et supprime tous les utilisateurs.
params[:admin] = "') OR 1=1--'"
La requête SQL finale détruit tous les utilisateurs et le résultat renvoie un nombre d'utilisateurs détruits :
RequêteDELETE FROM "utilisateurs" WHERE "utilisateurs"."id" = ?
Guide d'injection SQL Rails : exemples et prévention
Rails Exemples d'injection SQL
SSTI
Se produit lorsqu'un attaquant peut manipuler directement le modèle ERB comme ceci :
ERB.new("
#{@user.name}").result
Séances
Détournement de session
Le vol de l'identifiant de session d'un utilisateur permet à un attaquant d'utiliser l'application Web au nom de la victime.
Voici quelques façons de détourner une session et leurs contre-mesures :
- Sniffez le cookie dans un réseau non sécurisé. C'est pourquoi la connexion doit être sécurisée. Dans Rails 3.1 et versions ultérieures, cela peut être accompli en forçant toujours la connexion SSL dans le fichier de configuration de votre application :
config.force_ssl = vrai
- Au lieu de voler un cookie inconnu de l'attaquant, ils corrigent l'identifiant de session d'un utilisateur (dans le cookie) connu d'eux.
Stockage des sessions
Utilisations des railsActionDispatch::Session::CookieStore
comme stockage de session par défaut.
Des railsCookieStore
enregistre le hachage de session dans un cookie côté client. Le serveur récupère le hachage de session à partir du cookie et élimine le besoin d'un ID de session. Cela augmentera considérablement la vitesse de l'application, mais il s'agit d'une option de stockage controversée et vous devez penser à ses implications en matière de sécurité et à ses limites de stockage :
- L'expiration des cookies doit être en place
- Aucune information sensible ne doit se trouver dans les cookies
- L'application doit invalider les anciens cookies de session pour éviter une réutilisation malveillante
- Les cookies doivent être cryptés. Rails chiffre les cookies par défaut
LeCookieStore
utilise lecryptécookie jar pour fournir un emplacement sécurisé et crypté pour stocker les données de session.
La clé de cryptage des cookies est dérivée de lasecret_key_base
valeur de configuration.
Les secrets doivent être longs et aléatoires(poubelle/rails secrets
doit être utilisé pour obtenir de nouveaux secrets uniques).
Différentes valeurs de sel pour les cookies cryptés et signés doivent être utilisées.
Les environnements doivent utiliser une clé aléatoire présente dansconfig/credentials.yml.enc
, montré ici dans son état déchiffré :secret_key_base : 492f...
Configurations des cookies signés
Exemple de spécification du condensé utilisé pour les cookies signés :
Rails.application.config.action_dispatch.signed_cookie_digest = "SHA256"
Un algorithme cryptographique fort doit être en place.
Rejouer les attaques pour les sessions CookieStore
Si le cookie stocke des informations sensibles telles que le solde créditeur, un attaquant peut réutiliser les anciens cookies sur ce solde plus important et abuser du système.
Aucune information sensible ne doit être dans les cookies ou un nonce (valeur aléatoire) doit être en place pour empêcher les attaques par rejeu. Un nonce n'est valide qu'une seule fois et le serveur doit garder une trace de tous les nonces valides.
Fixation de session
L'attaque se concentre sur la réparation de l'ID de session d'un utilisateur connu de l'attaquant et force le navigateur de l'utilisateur à utiliser cet ID. Il n'est donc pas nécessaire qu'un attaquant vole l'identifiant de session par la suite.
La contre-mesure la plus efficace consiste àémettre un nouvel identifiant de sessionet déclarer l'ancien invalide après une connexion réussie. De cette façon, un attaquant ne peut pas utiliser l'identifiant de session fixe. C'est également une bonne contre-mesure contre le détournement de session. Voici comment créer une nouvelle session dans Rails :
réinitialiser_session
Concevoirgem pour la gestion des utilisateurs, il expirera automatiquement les sessions lors de la connexion et de la déconnexion pour vous.
Applications de sécurisation des rails - Guides Ruby on Rails
CSRF
Par défaut, Rails inclut unadaptateur de script discret, qui ajoute un en-tête appeléJeton X-CSRF
avec le jeton de sécurité sur chaque appel Ajax non-GET et non-HEAD. Sans cet en-tête, les requêtes Ajax non-GET et non-HEAD ne seront pas acceptées par Rails.
protect_from_forgery
dans application_controller<%= csrf_meta_tags %>
dans le modèle
SSRF
Pour trouver les vulnérabilités SSRF lors de l'examen du code source, les premières bibliothèques utilisées par l'application doivent être identifiées, puis les fonctions dangereuses correspondantes à l'aide de la liste de contrôle suivante doivent être trouvées :
réseau/http
bibliothèque:nécessite 'net/http'
Net ::HTTP.get()
ouNet ::HTTP.get_print()
ouNet ::HTTP.get_response()
- faire une requêteNet ::HTTP.start(uri.hostname, uri.port)
- crée une connexion à l'hôteNet :: HTTP :: Get.new uri
-Obtenir
demande dans le cadre de la connexion
Contournement de la redirection - recherchez
Net :: Redirection HTTP
et décidez si les redirections se produisent.OpenURI
bibliothèque:URI.open()
httppartie
bibliothèque:nécessite 'httppartie'
HTTParty.get
- faire une requête
http
bibliothèque:nécessite 'http'
HTTP.get
ouHTTP.follow.get
- faire une requêteHTTP.persistant
- session persistante
Contournement de redirection -
HTTP.follow.get
effectuera la redirection d'emplacement.Faraday
bibliothèque:exiger 'faraday'
Faraday.get
ouHTTP.follow.get
- faire une requêteFaraday.nouveau
- création de demande
Contournement de redirection -
.response :follow_redirects
Httpx
bibliothèque:nécessite "httpx"
HTTPX.get
ouHTTPX.post
rest-client
bibliothèque:nécessite 'rest-client'
RestClient.get
,RestClient.post
,RestClient::Request.execute
,RestClient.delete
,RestClient::Resource.new
Excon
bibliothèque:exiger 'excon'
Excon.get
,Excon.nouveau
,Excon.post
typhon
bibliothèque:rechercher "typhon"
Typhoeus ::Demande.nouveau
,Typhée ::Hydra.hydra
Trottoir
bibliothèque:besoin de « freiner »
Curl.get
,Curl.post
,Boucle ::Easy.perform
,Curl ::Easy.new
,Curl ::Easy.http_post
De plus, toutes les méthodes et fonctions qui peuvent faire des requêtes HTTP doivent être analysées pour déterminer si elles utilisent l'entrée de l'utilisateur et comment cela peut affecter les requêtes.
Redirections
Étonnamment, mais la plupart des applications RoR testées présentent des vulnérabilités de redirection HTTP ouvertes, pourquoi ? Le cadre RoR a des méthodes spéciales pour la redirection commerediriger vers
,redirect_back
et les développeurs ne valident pas le domaine avant de rediriger un utilisateur.
paramètres redirect_to[:to]
redirect_back
,redirect_back_or_to
-> prend l'URL du référent et redirige un utilisateur vers celle-ci
Commentaire:
À partir de Rails 7.0, protection de redirection ouverteraise_on_open_redirects
a lieu dans le dossierconfig/initialiseurs/new_framework_defaults_7_0.rb
. Ainsi, pour autoriser la redirection ouverte, elle doit être explicitement autorisée comme (ou activée globalement) :
redirect_to "https://rubyonrails.org", allow_other_host : vrai
Logique métier
RegExp
Chose très amusante, mais les règles d'expression régulière courantes ne fonctionnent pas dans RoR, mais pourquoi ? La chaîne RoR semble être multiligne, donc/^https?:\/\/[^\n]+$/i
ne vérifiera que la première ligne en laissant les autres. Cela peut être un puits pour de nombreuses autres vulnérabilités comme SQLi, les injections de commandes, XSS, etc. La bonne façon de vérifier la chaîne avec regexp est/\Ahttps?:\/\/[^\n]+\z/i
(\A \z
) ou activermultiligne : vrai
.
\UN
- début de ligne
\z
- fin de la ligne
Affectation de masse
C'est une vulnérabilité assez courante et elle se produit lorsqu'un développeur réécrit l'action par défaut commecréer
,mise à jour
et ne valide pas les paramètres à accepter.
def créer un utilisateur = User.new(user_params)def user_params params.require(:user).permit!end
De plus, un développeur peut ajouter ce paramètre àattr_protected
, donc l'affectation en masse ne fonctionnera pas ici. Sinon, cela peut être fait globalement via flagconfig.active_record.whitelist_attributes = vrai
, où un fichier spécifique est créé avec des attributs disponibles pour une affectation en masse.
Contournement de la TÊTE
Le routeur RoR traite la méthode HEAD comme GET. Par exemple, le fichier routes contientobtenir 'application/index'
et les requêtes HTTP peuvent être faites commeOBTENIR l'application/l'index
etApplication/index HEAD
. Ainsi, le routeur Rails ne distingue pas les méthodes HEAD et GET, mais les contrôleurs peuvent le faire. Si le contrôleur vérifie la méthode GET, la méthode HEAD peut être utilisée pour contourner les vérifications :
si request.get? #faire autre chose (la méthode HEAD y va) #accorder l'autorisationend
Contourner le flux OAuth de GitHub
Désérialisation non sécurisée
Ruby utilise leMaréchal
bibliothèque pour sérialiser et désérialiser des objets. Le marshalling est un moyen dangereux de désérialiser les données fournies, car leMarshal.load()
La méthode peut désérialiser n'importe quelle classe chargée dans le processus Ruby, ce qui peut conduire à des attaques d'exécution de code à distance (RCE).
Marshal.load()
ActiveSupport::MessageVerifier.new(clé)
- Par défaut, le sérialiseur Marshall est utilisé, si aucun autre n'est spécifiéRails.application.message_verifier()
- Pour ce cas particulier, il n'y a pas d'option pour spécifier un sérialiseur
Le vérificateur de message est utilisé pour calculer une signature et empêcher la falsification des données transmises. Pour exploiter la désérialisation non sécurisée et réaliser RCE, un attaquant devrait obtenir une clé utilisée pour le calcul de la signature.
Mauvaises configurations
Ce groupe comprendra des drapeaux intégrés RoR, qui peuvent être désactivés par les développeurs et poser un régal pour les applications :
config.active_record.whitelist_attributes=false
→ affectation en masseActiveSupport ::escape_html_entities_in_json = faux
→ XSS quand to_json()
Ruby on Rails - Série de feuilles de triche OWASP
Applications de sécurisation des rails - Guides Ruby on Rails