Sécurisez votre API REST avec PHP et Yii 2

Article par Anthony Lavallée
Diplômé de la Technique informatique du Cégep de Sainte-Foy. – See more at: http://atomrace.com/blogue/techno-web/developpement-web/2015/04/creation-dun-api-restful-avec-php-et-yii-2-sur-ubuntu#sthash.Z1mJzsM1.dpuf

 

Article par Anthony Lavallée
Diplômé de la Technique informatique du Cégep de Sainte-Foy.

Avant de sécuriser votre API, je vous propose de suivre le lien suivant qui explique comment mettre en place un API REST avec PHP et Yii2 sur Ubuntu.

Les méthodes d’authentification

Dans un serveur REST, comme il est dans l’habitude de ne pas utiliser de session ou de «cookies», chaque requête doit être envoyée avec une manière d’identifier l’utilisateur. Il existe plusieurs méthodes d’authentification, par exemple:

  • HttpBasicAuth, où un «access token» est envoyé comme nom d’utilisateur dans l’en-tête de la requête HTTP.
  • QueryParamAuth, où un «access token» est envoyé comme une chaîne de caractères dans l’URL.
  • OAuth2, où un «access token» est obtenu par une autorisation du serveur. Google, Facebook et Twitter utilisent cette méthode.

On peut débuter par aller configurer le fichier config/web.php et définir la variable enableSession à false, afin que le statut d’authentification de l’utilisateur ne soit pas conservé lors des requêtes de session. Cette méthode est optionnelle, mais puisque nous travaillons avec un serveur REST, il est recommandé d’adhérer à cette pratique.

'user' => [ 
              'enableSession' => false,            
              'loginUrl' => null,  
       ],

Méthode d’authentification HttpBasicAuth

L’ «access token» est envoyé comme le nom d’utilisateur. À la place d’une session ou de cookies, HttpBasicAuth utilise un BasicAuth Header, qui est envoyé à chaque requête, afin de confirmer l’identité de l’utilisateur.

Dans le fichier controllers/CountryController.php, aller placer les lignes de codes suivantes, afin de permettre à HttpBasicAuth de s’opérer.

'authenticator' => 
[        
  'class' => HttpBasicAuth::className(), 'auth' => [$this, 'auth']                         
],
public function auth($username, $password)     
{         
     return \app\models\User::findOne
    ([                    
        'username' => $username,                       
        'password' => $password,                 
     ]);        
}

Ensuite, on peut tester la requête à l’aide de la méthode cURL.
En effectuant une requête avec un utilisateur ayant les informations suivantes:

username: admin
password: admin

La requête cURL sera donc:

$ curl --user admin:admin http://monapp.com/country/index

Si un nom d’utilisateur et un mot passe valides sont utilisés, voici la réponse JSON retournée.

[
{"code":"AU","name":"Australia","population":1000},
{"code":"BR","name":"Brazil","population":170115000},
{"code":"CA","name":"Canada","population":1147000},
{"code":"CN","name":"China","population":1277558000},
{"code":"DE","name":"Germany","population":82164700},
{"code":"FR","name":"France","population":59225700},
{"code":"GB","name":"United Kingdom","population":59623400},
{"code":"IN","name":"India","population":1013662000},
{"code":"RU","name":"Russia","population":146934000},
{"code":"US","name":"United States","population":278357000}
]

Si on entre un utilisateur ou un mot de passe invalide, la requête retourne un message d’erreur, expliquant que l’on ne dispose pas des droits nécessaires pour effectuer cette requête. Par exemple, si j’entre «test» comme mot de passe, alors que le véritable mot de passe est «admin», j’obtiens la réponse ci-dessous.

$ curl --user admin:test http://monapp.com/country/index
{
"name":"Unauthorized",
"message":"You are requesting with an invalid credential.",
"code":0,
"status":401,
"type":"yii\\web\\UnauthorizedHttpException"
}

Méthode d’authentification QueryPathAuth

L’«access token» est envoyé comme une chaîne de caractères dans l’URL.

https://example.com/users?access-token=xxxxxxxx

Afin de permettre ce type d’authentification, il faut aller définir la classe dans l’espace « authenticator » de nos « behaviors », dans notre contrôleur.

'authenticator' => [    
  'class' => QueryParamAuth::className(),          
],

Ensuite, on peut tester la requête à l’aide de la méthode cURL, en effectuant une requête avec un utilisateur ayant les informations suivantes:

access-token = 101-token

La requête cURL sera donc:

$ curl --i "http://monapp.com/country/index?access-token=101-token"

Si on utilise un jeton valide, la requête retourne un message de confirmation.

HTTP/1.1 200 OK
Date: Fri, 27 Mar 2015 15:32:15 GMT 
Server: Apache/2.4.6 (Ubuntu) 
X-Powered-By: PHP/5.5.3-1ubuntu2.6 Set-Cookie: PHPSESSID=f8oafhps; 
HttpOnly Expires: Thu, 19 Nov 1981 08:52:00 GMT 
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, 
pre-check=0 Pragma: no-cache 
X-Pagination-Total-Count: 10 
X-Pagination-Page-Count: 1 
X-Pagination-Current-Page: 1 
X-Pagination-Per-Page: 20 Link: ; 
rel=self Set-Cookie: PHPSESSID=f8o4s47uvmphpsnk7e13; path=/; 
HttpOnly 
Content-Length: 1860 
Content-Type: application/json; charset=UTF-8
[
{"code":"AU","name":"Australia","population":1000},
{"code":"BR","name":"Brazil","population":170115000},
{"code":"CA","name":"Canada","population":1147000},
{"code":"RU","name":"Russia","population":146934000},
{"code":"US","name":"United States","population":278357000}
]

Si on entre un jeton invalide, la requête retourne un message d’erreur,  expliquant que l’on ne dispose pas des droits nécessaires pour effectuer cette requête. Par exemple, si on entre «test» comme access-token, alors que le véritable access-token de l’utilisateur admin est «101-token», on obtient la réponse ci-dessous.

$ curl --i "http://monapp.com/country/index?access-token=test"
HTTP/1.1 401 Unauthorized 
Date: Fri, 27 Mar 2015 15:39:49 GMT 
Server: Apache/2.4.6 (Ubuntu) 
X-Powered-By: PHP/5.5.3-1ubuntu2.6 
Content-Length: 149
Content-Type: application/json; charset=UTF-8

{
"name":"Unauthorized",
"message":"You are requesting with an invalid credential.",
"code":0,"status":401,
"type":"yii\\web\\UnauthorizedHttpException"
}

Tests unitaires avec Guzzle

Guzzle est un client PHP HTTP qui rend l’envoi de requête simple et rapide. On peut donc aussi s’en servir afin de créer divers tests unitaires pour son serveur REST et ainsi tester nos requêtes, pour voir si elles fonctionnent correctement.

class GuzzleTest extends PHPUnit_Framework_TestCase 
{
    private $apiURL = 'http://monapp.com/';  
    
    public function test_ConnectionCountryIndex()     
    {         
       $client = new Client();         
       $response = $client->get('http://monapp.com/country/index');         
       $code = $response->getStatusCode();          
       $this->assertTrue($code === 200);    
     }

     /** @depends test_ConnectionCountryIndex */     
     public function testConnectionSiteAbout()     
     {         
        $this->client = new GuzzleHttp\Client(
                           ['base_url' => $this->apiURL], array());      
        $response = $this->client->get('site/about');         
        $code = $response->getStatusCode();         
        $this->assertTrue($code === 200);     
     }
}

On démarre les tests en utilisant la commande

$ phpunit BasicAuthTest.php

[sharethis]

 

J’obtiens les résultats suivants, qui m’expliquent que les tests ont tous passé.

PHPUNIT 3.6.10 by Sebastian Bergmann.
..
Time: 0 seconds, Memory: 2.25 Mb
OK (2 tests, 2 assertions)

Si on change le code attendu du premier test: $this->assertTrue($code === 201);
On obtient les résultats suivants, qui expliquent que certains tests ont échoué. Grâce à cette interface, on peut savoir combien de tests ont échoué, lesquels et pourquoi.

PHPUnit 3.6.10 by Sebastian Bergmann.
Time: 0 seconds, Memory: 2.25Mb

There was 1 failure:
1) BasicAuthTest::testConnectionCountryIndex
Failed asserting that false is true.
/var/www/basic/tests/BasicAuthTest.php:18
FAILURES!

Tests: 1, Assertions: 1, Failures: 1, Skipped: 1.

Si vous avez aimé le l’article d’Anthony, n’hésitez pas à le partager!

 

[sharethis]

 

Sécurisez votre API REST avec PHP ET Yii2

Références

  • http://en.wikipedia.org/wiki/Basic_access_authentication
  • http://www.yiiframework.com/doc-2.0/guide-rest-authentication.html
  • http://guzzle.readthedocs.org/en/latest/

0 réponses

Répondre

Want to join the discussion?
Feel free to contribute!

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *