La sécurité
Introduction
Vous ne pouvez pas faire l’impasse sur la sécurité d’une application, d’autant plus si vous avez une partie administration de votre site.
Rassurez-vous, la mise en place de la sécurité sous Symfony n’est pas très compliquée. Tout est déjà installé par défaut.
Il existe deux parties distinctes en matière de sécurité :
-
l’authentification : comment un utilisateur peut s’authentifier pour accéder à une partie sécurisée de l’application
-
l’autorisation : comment définir les droits pour un utilisateur d’accéder à certaines ressources : routes, contrôleurs, méthodes, vues, entités…
Nous allons commencer par l’authentification d’un utilisateur.
L’authentification
Toute la sécurité de Symfony est concentrée dans un seul fichier : config/packages/security.yaml
Ouvrez ce fichier :
security:
# https://symfony.com/doc/current/security.html#registering-the-
user-hashing-passwords
password_hashers:
Symfony\Component\Security\Core\User\PasswordAuthenticated
UserInterface: 'auto'
# https://symfony.com/doc/current/security.html#loading-the-user-
the-user-provider
providers:
users_in_memory: { memory: null }
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
lazy: true
provider: users_in_memory
# activate different ways to authenticate
# https://symfony.com/doc/current/security.html#the-firewall
# https://symfony.com/doc/current/security/
impersonating_user.html
# switch_user: true
# Easy way to control access for large sections of your site
# Note: Only the *first* access control that matches will be used
access_control:
# - { path: ^/admin, roles: ROLE_ADMIN }
# - { path: ^/profile, roles: ROLE_USER }
when@test:
security:
password_hashers:
# By default, password hashers are resource intensive and
take time. This is
# important to generate secure password hashes. In tests
however, secure hashes
# are not important, waste resources and increase test times.
The following
# reduces the work factor to the lowest possible values.
Symfony\Component\Security\Core\User\
PasswordAuthenticatedUserInterface:
algorithm: auto
cost: 4 # Lowest possible value for bcrypt
time_cost:...
L’autorisation
Une fois qu’un utilisateur est défini comme ayant les droits de s’authentifier, encore faut-il lui préciser quelles sont les ressources auxquelles il a accès.
Actuellement, le firewall défini (main) laisse passer tout le monde :
main:
lazy: true
provider: app_user_provider
custom_authenticator: App\Security\CustomAuthenticator
logout:
path: app_logout
lazy : true signifie simplement qu’il n’y a pas besoin de démarrer une session d’autorisation dans le cas où il n’y a pas une demande explicite d’autorisation. La session qui permettra d’avoir un identifiant de session pour la sécurité sera créée dynamiquement lors de l’accès aux ressources qui sont protégées.
Autrement dit, tout le monde a accès à toutes les ressources de notre application pour l’instant. En effet, nous souhaitons donner accès aux pages Front de notre application sans activer la sécurité. Ce sont uniquement les pages d’administration qui doivent être protégées.
Nous allons définir des autorisations d’accès à certaines ressources.
Il y a plusieurs types d’autorisations :
-
access_control : permet de définir des autorisations au niveau des routes.
-
accès contrôleur : permet de définir des autorisations au niveau d’un contrôleur.
-
accès action : permet de définir des autorisations au niveau des méthodes d’un contrôleur.
-
accès vue : permet de définir des autorisations au niveau des vues.
Nous allons commencer par les autorisations access_control.
1. access_control
Pour l’instant, tous nos utilisateurs ont accès aux routes insert, update et delete.
Pour utiliser l’identification mise en place sur ces routes, nous allons nous servir des access_control.
Les access_control sont définis dans le fichier config/packages/security.yaml. En bas du fichier, vous trouvez ces lignes :
access_control:
# - { path: ^/admin, roles: ROLE_ADMIN }
# - { path: ^/profile, roles: ROLE_USER }
Il suffit de les décommenter et de définir les routes et les rôles nécessaires pour y accéder.
Nous pouvons écrire, par exemple :
access_control:
- { path: ^/insert, roles: ROLE_ADMIN }
- { path: ^/update, roles: ROLE_ADMIN }
- { path: ^/delete, roles: ROLE_ADMIN }
Il y a un moyen plus simple pour définir un access_control sur un ensemble de routes.
Par exemple, pour définir un access_control sur toutes les routes qui pointent vers le contrôleur...
La sécurité d’une API
Il y a beaucoup d’autres possibilités de configuration de sécurité sous Symfony. Je vous laisse vous rendre sur la page de la documentation si vous souhaitez aller plus loin : https://symfony.com/doc/current/security.html
Il y a une sécurité particulière à mettre en place lorsque votre application Symfony est une API.
Qu’est-ce qu’une API ?
Une API (Application Programming Interface) permet aux développeurs de pouvoir utiliser une fonctionnalité (une classe PHP) sans avoir à se soucier de son fonctionnement complexe. C’est ce qu’on appelle des services externes. Une API permet d’offrir un service, via un serveur distant, à un programme PHP.
Les API peuvent, par exemple, être utilisées pour déclencher des campagnes publicitaires d’e-mailing de façon automatique, accéder à des données d’une base de données…
L’accès à une API se fait simplement par une requête HTTP, mais ne retourne pas une page HTML comme une application standard. Une API retourne généralement des données (soit un code retour indiquant si le service s’est bien exécuté, soit des informations dans le cas d’une recherche sur une base de données, par exemple).
Le format de données retourné par une API est généralement le format JSON. On utilise des API dites de type REST, c’est-à-dire basée sur des requêtes HTTP. Il existe d’autres types d’API, comme les API de type Soap, basées sur un échange de données à partir d’un fichier XML.
Voici un exemple de format JSON :
{
"espèce": "Dog",
"race": "Labrador Retriever",
"couleur": "Yellow",
"âge": 6
}
Ce format est tiré directement de l’aspect des objets en JavaScript.
Votre navigateur peut lire des fichiers JSON, mais est généralement incapable d’exécuter une API (il n’est pas fait pour ça : une API est censée être utilisée par un programme).
Une API utilise plusieurs modes de connexion HTTP en fonction de ce qu’elle fait. Ce sont des conventions, mais que toutes les API adoptent.
Les principaux modes sont :
-
GET : pour récupérer des informations
-
POST : pour créer des informations
-
PUT : pour mettre à jour des informations
-
DELETE : pour supprimer des informations
Vous pouvez créer un programme PHP pour accéder à une API suivant les différents modes (nous appelons cela des verbes, puisqu’ils correspondent à des actions différentes).
Vous avez également des outils comme Insomnia qui vous permettent de tester des API distantes directement. Je vous conseille de le télécharger : https://insomnia.rest/
Pour vous exercer à utiliser une API distante, vous pouvez tester celle-ci, qui vous donne la météo d’une ville donnée :
api.openweathermap.org/data/2.5/weather?q=votre ville&appid=votre...