cs_sjon
Messages postés
861
Date d'inscription
mardi 26 mars 2002
Statut
Membre
Dernière intervention
29 novembre 2006
1
3 juin 2005 à 21:00
Sael og blesud
>> Antho <<< end_antho
Tout d'abord merci pour le Post. Le but était tout naturellement d'expliquer le mécanisme usé lors d'authentification PHP qui est relativement faible côté sécurité quand ce dernier est de type "Basic" puisqu'il ne s'agît que d'un encodage base64 en non pas de chiffrement ... Afin de montrer à Floxone que cela n'était pas aussi sécurisé qu'il voulait bien le croire ;-). Ensuite j'ai montré le mécanisme lorsque le type est "Digest" qui est un peu mieux mais non sans exception ... Comme vous dîtes cela dépend de la façon dont c'est codé. Mais cela dépend aussi de la façon dont le dit server est configuré et maintenu. J'ai vu en effet certains administrateurs qui ne voulant pas bloquer la moindre requête DNS de leur réseau interne par exemple ouvrait volontairement le port 53 UDP partout sur tous les server ;-O et cela par pure incompétence qu'elle soit dûe au laxisme ou à l'ignorance ... ;-). Cependant j'aurais aussi pu aborder l'authentification HTTPS.
Au niveau du .htaccess je suis relativement d'accord avec vous mais là encore j'ajouterai un bémol ... ;-) ... En effet combien de webmaster use de ce procédé pour du RewritingURL par exemple mais sans maitriser les expressions régulière ( Perl est très bien pour apprendre leurs fonctionnements ;-) ). Ce qui fait que cela fonctionne pour ce qu'il souhaite et c'est là la seule chose qu'ils testent alors que comme leurs expressions ne sont pas "blindées" cela ouvre de multiples possibilités. Enfin le discours pourrait être long encore à ce sujet ... Mais merci bien ...
PS : Vous avez vu ma signature n'est pas si longue que cela en fait ( cf : post précédent ) ;-)
end_antho
>>floxone <<<end_floxone
Bah merci bien pour le Post. Je ne pense pas que vous trouverez votre solution dans l'authentification PHP mais via des sessions cela peut apporter un niveau de sécurité suffisament important. Mais c'est comme pour tout il faut que cela soit bien codé et propre surtout, ne rien laissé au hasard ( si je fais cela qu'est-ce qui peut en découler ? ... etc ... ). Merci ...
end_floxone
Oh et puis après tout ;-)
>> Antho Bah heu comment dire heu ...désolé
>> Floxone cela peut vous correspondre ... à vous de voir
Authentification HTTPS :
Le protocole HTTPS met en oeuvre des services d'authentification des parties (unilatérale ou mutuelle, à partir du protocole SSLv3), d'authenticité et de confidentialité des données pendant toute une session SSL/TLS (la session «multiplexant » les connexions TCP et requêtes HTTP associées).
La méthode d'authentification HTTP de type Basic est le plus souvent utilisée conjointement à SSL/TLS, afin d'assurer la confidentialité des accréditations.
Le protocole HTTPS introduit, par l'intermédiaire des protocoles SSLv3/TLS, une méthode d'authentification du client par certificat X.509v3.
Mécanisme :
Observons déjà le format du fichier openssl.conf
Il faut se référer au fichier openssl.cnf par défaut pour avoir le format général. Seules les extensions v3 seront manipulées, respectant la syntaxe : extension_name=[critical,] extension_options
Ces extensions sont introduites car les bi-clés générés peuvent être de divers usages (bi-clé de chiffrement, bi-clé de signature et bi-clé d'échange de clés) et les exigences en terme de sécurité différentes (recouvrement pour un bi-clé de chiffrement, auquel un service de non répudiation ne peut donc être associé).
Outre des informations sur le bi-clé, ces extensions permettent d'imposer des contraintes sur l'itinéraire de certification à parcourir
(autrement dit la chaîne à parcourir pour valider un certificat), renseigner sur la politique de certification concernant le certificat
présenté, ou encore sur la façon d'accèder aux listes de révocation.
Les plus courantes sont brièvement abordées :
* basicConstraints
- pathlen : nombre de CA pouvant apparaître sous (autrement signés par) le certificat
- CA : TRUE pour une autorité, inutile pour une entité terminale (mais à FALSE pour compatibilité)
* keyUsage
- digitalSignature (RSA/DSA) : pour la signature (en tant que mécanisme, autrement dit le chiffrement d'une empreinte avec une clé privée)
- nonRepudiation (RSA/DSA) : idem, mais en tant que service (autrement dit la volonté d'ajouter un service de non répudiation à une signature). Pour du S/MIME, bit positionné avec digitalSignature typiquement
- keyEncipherment (RSA) : chiffrement de clé (clé secrète d'algorithme symétrique généralement, ou premaster secret ou encore clé RSA éphémère en SSL/TLS)
- dataEncipherment (RSA) : chiffrement de données (hors clé de session, crl, certificat)
- keyCertSign (RSA/DSA) : signature de certificats (pour les CA donc)
- cRLSign (RSA/DSA) : signature de listes de révocation
- keyAgreement (DH) : pour la négociation d'une clé de session
- encipherOnly et decipherOnly (DH) : positionnés conjointement à keyAgreement
* nsCertType
- client ou server : pour une authentification client ou serveur en SSL/TLS
- email : pour du S/MIME
- objsign : pour la signature de code (applet java typiquement)
- sslCA, emailCA, objCA : pour délivrer des certificats ayant les propriétés précédentes
* extendedKeyUsage
serverAuth, clientAuth, codeSigning, emailProtection, pour les plus courantes.
Les noms sont suffisamment explicites.
* subjectAltName
Utiles pour les hôtes virtuels par nom, ou encore les adresses emails multiples associées à un même certificat. Malheureusement, c'est le commonName qui est généralement utilisé.
* crlDistributionPoints
Indique le(s) façon(s) de télécharger les listes de révocation, via LDAP ou HTTP.
Maintenant voyons la génération des certificats
Le fichier de configuration openssl.cnf, est supposé situé dans le répertoire courant.
On crée les fichiers et répertoires nécessaires :
$ mkdir -p ca/newcerts # Répertoire recueillant les certificats émis par CA ROOT
$ touch ca/index.txt # Base de données des certificats émis
$ echo '01' > ca/serial # Numéro de série, initialisé à 1. Incrémenté par la suite
$ mkdir -p cassl/newcerts #idem, pour CA SSL
$ touch cassl/index.txt
$ echo '01' > cassl/serial
Génération du certificat de l'autorité racine
Il s'agit du CA racine, par conséquent autosigné.
* Génération du bi-clé RSA, protégé par une passphrase
$ openssl genrsa -out ca/ca.key -des3 2048
* Génération du certificat auto-signé
$ openssl req -new \
-x509 \ # Génération d'un certificat autosigné, et non d'une simple requête
-key ca/ca.key \ # La clé publique est extraite du bi-clé précédente
-out ca/ca.pem \ # Le certificat est copié
-config ./openssl.cnf \ # Le fichier de configuration n'est pas celui par défaut
-extensions CA_ROOT # La section CA_ROOT est utilisée (cf Annexe)
Pour vérifier le bon usage du certificat :
$ openssl x509 -in ca/ca.pem -text -noout
$ openssl x509 -purpose -in ca/ca.pem -noout
Génération du certificat de l'autorité intermédiaire SSL
Il s'agit d'un CA intermédiaire, dont le certificat est signé par le CA ROOT.
$ openssl genrsa -out cassl/cassl.key -des3 2048
Génération de la demande de certificat :
$ openssl req -new \ # Génération d'une demande de certificat
-key cassl/cassl.key \
-out cassl/cassl.crs \
-config ./openssl.cnf
Signature de la demande de certificat par le ca root (CA par défaut dans openssl.cnf) :
$ openssl ca -out cassl/cassl.pem \
-config ./openssl.cnf \
-extensions CA_SSL \
-infiles cassl/cassl.crs # Demande de certificat à signer
Ainsi :
* Le certificat signé est crée dans cassl/cassl.pem
* Une copie est réalisée dans ca/newcerts/01.pem
* Les fichiers ca/serial et ca/index.txt sont mis à jour
Génération d'un certificat serveur SSL
# openssl genrsa -out cassl/serverssl.key -des3 1024
$ openssl req -new \
-key cassl/serverssl.key \
-out cassl/serverssl.crs \
-config ./openssl.cnf
$ openssl ca -config ./openssl.cnf \
-name CA_ssl_default \ # Le certificat utilisé pour signer la requête est celui de CA SSL
-extensions SERVER_RSA_SSL \
-infiles cassl/serverssl.crs
Dans ce cas, l'autorité signataire est ca_ssl Si tout se déroule correctement :
Le certificat serveur est renvoyé sur la sortie standard, et copié dans cassl/newcerts/01.pem Les fichiers cassl/serial et cassl/index.txt sont mis à jour.
Remarque : pour générer un certificat client, il faut reproduire la procédure ci-dessus, avec l'extension CLIENT_RSA_SSL (voir le fichier de configuration en annexe). Généralement, on l'exporte avec la clé privée dans un fichier pkcs#12, suivant la syntaxe :
$ openssl pkcs12 -export \
-inkey clientssl.key \
-in clientssl.pem \
-out clientssl.p12 \
-name "Certificat client"
Enfin on importe le fichier obtenu dans son navigateur.
Configuration
Les paramètres généralement rencontrés sont les suivants :
(1) Le certificat X.509 à présenter pour l'authentification :
Il doit s'agir du certificat dont on possède la clé privée. Ce certificat doit être au format PEM (DER encodé en base64).
(2) La clé privée correspondant à la clé publique renfermée dans le certificat :
Au format PEM encore une fois. Il est généralement recommandé de chiffrer cette clé (mais ce n'est pas le cas généralement).
(3) La liste des certificats des autorités reconnues :
Dans ce cas, deux possibilités pour la configuration,
- Utilisation d'un répertoire (-CApath) : L'ensemble des certificats, au format PEM, doit être placé dans le répertoire passé en paramètre. Les certificats sont recherchés suivant le "subject name hash value" (en premier lieu). Celui-ci est calculé via l'option hash d'openssl. Pour accélérer la recherche, un lien pointant vers le certificat est crée, dont le nom est "hash.0"
Exemple :
$ openssl x509 -hash -in certificat.pem -noout
22f2539e
$ ln -s certificat.pem 22f2539e.0
Si deux certificats ont le même 'subject name hash value', ils seront distingués suivant la valeur de l'extension, typiquement : 9d66eef0.0, 9d66eef0.1
Les liens peuvent être crées automatiquement avec l'utilitaire c_rehash:
$ c_rehash .
Doing .
certificat.pem => 22f2539e.0
- Utilisation d'un fichier (-CAfile) : Dans ce cas, les certificats des autorités de confiance doivent être concaténés dans un seul et même fichier, au format PEM. Seuls les champs situés entre les balises -----BEGIN CERTIFICATE----- et -----END CERTIFICATE----- sont considérés. Le reste est du commentaire.
A partir de ce fichier est construite la chaîne de certification présentée au client, ainsi que les certificats proposés pour son
authentification. Il est recommandé d'utiliser l'option CAfile :
- D'une part, le fichier est lu à l'initialisation du programme, et peut par conséquent être placé hors d'une cage, dans le cas d'un chroot() par exemple bien que ce ne pas là la seule façon d'isolé un service. L'utilisation la plus courante concerne Postfix-SSL.
- D'autre part, la liste des certificats présentés au client pour authentification est souvent constituée des certificats de ce fichier
uniquement (la documentation n'est pas extrêmement claire à ce sujet) : ces certificats sont en effet chargés par la fonction
SSL_CTX_set_client_CA_list(), dont le prototype est :
void SSL_CTX_set_client_CA_list(SSL_CTX *ctx, STACK_OF(X509_NAME) *list);
Or, dans le patch pour Postfix :
$ grep 'SSL_CTX_set_client_CA_list' pfixtls.diff
SSL_CTX_set_client_CA_list(ctx, SSL_load_client_CA_file(CAfile));
de même dans apps/s_server.c (archive openssl) :
$ grep SSL_CTX_set_client_CA_list s_server.c
SSL_CTX_set_client_CA_list(ctx,SSL_load_client_CA_file(CAfile));
La liste des certificats présentés au client provient uniquement de la liste pointée par l'option CAfile dans les 2 cas. Les deux options ne sont donc pas strictement équivalentes, dans ces cas là.
Le cas du serveur Apache est différent :
$ grep 'SSL_CTX_set_client_CA_list' pkg.sslmod/ssl_engine_init.c
SSL_CTX_set_client_CA_list(sc->pSSLCtx, skCAList);
où skCAList est initialisé ainsi :
(skCAList = ssl_init_FindCAList(s, p, sc->szCACertificateFile,
sc->szCACertificatePath)
Je ne montrerai pas d'exemple ici mais à la demande ...
Dans ce cas, le serveur et l'application peuvent s'appuyer sur la session SSL/TLS mutuellement authentifiée pour assurer un suivi de session authentifiée de l'utilisateur, au niveau applicatif par conséquent et non plus au niveau HTTP.
Suivi de session authentifiée
Dans le cas d'une authentification du client par certificat X.509, un certain nombre de paramètres discriminants permettent d'identifier l'utilisateur authentifié. Ces paramètres discriminants sont, à titre d'exemple, les champs DN (distinguishedName), CN (commonName) ou encore l'adresse de courrier électronique dérivés du certificat présenté lors de la négociation des
paramètres de la session SSL/TLS.
La liste des variables d'environnement initialisées par mod_ssl, dérivant du certificat client, est la suivante :
SSLPassPhraseDialog, SSLMutex, SSLRandomSeed, SSLSessionCache, SSLSessionCacheTimeout, SSLEngine, SSLProtocol, SSLCipherSuite, SSLCertificateFile, SSLCertificateKeyFile, SSLCertificateChainFile, SSLCACertificatePath, SSLCACertificateFile, SSLCARevocationPath, SSLCARevocationFile, SSLVerifyClient, SSLVerifyDepth, SSLLog, SSLLogLevel, SSLOptions, SSLRequireSSL, SSLRequire, Additional Features, Environment Variables, Custom Log Formats
Dans le cas où le client n'est pas authentifié par certificat X.509, le paramètre discriminant, dont pourrait être dérivé un identifiant de session au niveau de l'application, ne peut plus plus provenir du certificat client. Les seuls paramètres « candidats » sont ceux négociés lors du handshake SSL/TLS, et plus particulièrement le session_id sur 32 bits (variable d'environnement SSL_SESSION_ID pour mod_ssl, initialisé par le serveur).
Le standard RFC2246 (« The TLS Protocol Version 1.0 ») stipule, à propos de la durée de vie de cet identifiant :
« An upper limit of 24 hours is suggested for session ID lifetimes, since an attacker who obtains a master_secret may be able to impersonate the compromised party until the corresponding session ID is retire ».
La limite supérieure de durée de vie de cet identifiant est donc proposée à 24 heures - ce qui est a priori largement suffisant pour suivre une session authentifiée. Cependant, certaines versions d'Internet Explorer (IE 5.0/5.01(SP1)/5.5(SP1) 9x/NT4) renégocient ce paramètre toutes les 2 minutes.
Ce comportement peut être modifié dans la base de registres : HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\SecurityProviders\SCHANNEL
La clef ClientCacheTime est positionnée à 120000 (ms) par défaut.
Le suivi de session fondé sur le session_id SSL/TLS uniquement est donc, malheureusement, inexploitable en pratique.
La solution, lorsque l'authentification par certificat client n'est pas mise en oeuvre, repose donc sur les mécanismes usuels utilisés dans HTTP - qui seront brièvement abordés par la suite, avec la notion d'identifiant de session authentifiée (cookie ou autre).
Remarque : outre le suivi de session authentifiée au niveau « applicatif », ce renouvellement fréquent du session_id SSL/TLS pose le problème de l'équilibrage de charge sur des flux HTTPS (pour s'appuyer sur d'autres paramètres que l'adresse IP notamment). À cet effet, la bibliothèque OpenSSL 0.9.7 introduit la fonction SSL_CTX_set_generate_session_id(), permettant au serveur HTTPS de générer des sessions id SSL dont le préfixe est statique et exploitable au niveau de l'équipement de répartition de charge, pour peu que celui-ci permette un tel paramétrage.
Voilà ... On peut aussi regarder du côté de l'authentification "applicative"
L'authentification entendue au sens « applicatif » consiste en la vérification par l'application elle-même des accréditations présentées par le client. Il ne s'agit plus, pour cette dernière, de s'appuyer sur une authentification réalisée au niveau HTTP ou SSL/TLS, par l'intermédiaire des variables d'environnement initialisées par le serveur par exemple : REMOTE_USER pour une
authentification HTTP, SSL_CLIENT_DN pour une authentification par certificat client etc.
Les accréditations ne sont donc plus transmises via les entêtes HTTP (méthodes d'authentification HTTP précédemment décrites), mais par un mécanisme indiqué par la « requête simple » de la requête. La méthode utilisée peut être GET (via
la QUERY_STRING, concaténée à l'URI) ou POST (dans le corps de la requête), indifféremment.
Remarque : il est clair que les langages de scripts, comme PHP par exemple, permettent également de mettre en oeuvre des mécanismes d'authentification de type HTTP « Basic », dans la mesure où ils peuvent également lire/écrire les requêtes/réponses.
Les accréditations sont généralement transmises via un tunnel chiffré/authentifié unilatéralement (SSL/TLS avec authentification du serveur par certificat), afin d'assurer la confidentialité des accréditations transmises.
Remarque : une solution alternative, et rarement employée, consiste à utiliser un mécanisme local au client, de type javascript, pour générer des accréditations à « usage unique » à partir des paramètres d'authentification, et envoyer ces accréditations au serveur (à travers un canal non chiffré). À titre d'exemple, la mise en oeuvre d'une authentification de type CHAP, par un
javascript côté client et des scripts ASP côté serveur.
Suivi de session authentifiée
Le suivi de session est à la charge de l'application. Dans les cas HTTP « Basic » et « Digest » (avec ou sans surcouche SSL/TLS), il y a authentification à chaque requête, avec une gestion d'état (ensemble de variables associées à une « session » applicative, à un ensemble de requête provenant d'un même utilisateur) côté serveur. Le même principe peut être adopté pour une application.
Mais le processus est tout autre, en pratique : l'utilisateur commence par s'authentifier au niveau d'un formulaire, les paramètres sont transmis (via la méthode GET ou la méthode POST) pour validation, puis un identifiant de session est attribué et sera utilisé pour lier les requêtes suivantes au contexte initialisé côté serveur -- d'où la notion de session applicative.
Les méthodes de passage d'identifiant de session sont multiples.
À titre d'exemple, une liste non exhaustive de techniques rencontrées :
- cookie - géré par le serveur HTTP :
- Fixé côté serveur, par l'entête Set-Cookie ou via javascript :
Set-Cookie: SESSIONID=e3e5f57ca9adbbb19a21b1c2a22be987; path=/
- Émis par le client, par l'entête Cookie :
Cookie: SESSIONID=e3e5f57ca9adbbb19a21b1c2a22be987
Le cookie est intéressant d'un point de vue « sécurité », avec l'introduction de fonctionnalités via les paramètres «secure» (permettant la transmission du cookie via un tunnel SSL/TLS uniquement, afin d'éviter son interception « passive » par écoute du trafic) ou encore « httponly » (introduit par le Service Pack 1 d'IE 6, protégeant ce navigateur contre les attaques de type XSS en interdisant la manipulation du cookie par des scripts, type javascript notamment -- tout en demeurant vulnérable à un usage détourné de la méthode HTTP TRACE qu'il convient donc de désactiver au niveau des serveurs HTTP).
- méthode GET :
GET /page.php?SESSIONID=e3e5f57ca9adbbb19a21b1c2a22be987
- méthode POST :
POST /page.php
Content-type: application/x-www-form-urlencoded
Content-length: 42
SESSIOND=e3e5f57ca9adbbb19a21b1c2a22be987
- insertion dans la REQUEST_URI (mod_rewrite + PHP4 ) :
GET /SESSIOND=e3e5f57ca9adbbb19a21b1c2a22be987/index.php
- réécriture d'URL
GET /index.php
Host: e3e5f57ca9adbbb19a21b1c2a22be987.webserver.tld
La sécurité relative à la génération d'un cookie (ou d'un identifiant de session plus généralement) d'une part, et à son suivi d'autre part sont deux sujets non triviaux qui débordent du cadre de ce post. Le point essentiel est qu'il convient d'identifier les requêtes (indépendantes les unes des autres, dans la mesure où HTTP est « sans état ») d'un même utilisateur authentifié, et les associer à un contexte unique géré côté serveur et initialisé suite à une phase d'authentification.
Certaines suites logicielles de SSO, par exemple, mettent en oeuvre des mécanismes tout à fait satisfaisants, en générant par exemple un nouvel identifiant de session à chaque requête et permettant de se prémunir contre les attaques de type XSS. La gestion correcte de cet identifiant assurera la sécurité du service d'authentification, mais cet identifiant devra par la suite être correctement corrélé avec les habilitations des utilisateurs, afin de mettre un place une véritable gestion des autorisations, et non une simple « personnalisation » des menus affichés à l'utilisateur... Le manque de cloisonnement entre les contextes utilisateurs au niveau applicatif sont aussi dangereux que les vols de session par XSS, et leur résolution ne passe pas forcément par l'ajout d'options diverses à un cookie, ou encore à un filtrage systématique du contenu des pages renvoyées au client, mais à une conception sécurisée de l'application même, qu'une solution de filtrage ou de SSO ou autre, aussi évoluée soit-elle, ne remplacera pas.
Voili voilou ...
Bon courage ...
NB : Si la réponse vous convient merci de l'accepter pour fermer ce thread ...
Sigurjón Bírgir Sigurðssón aka Sjón
HARDWARE : Partie de l'ordinateur qui reçoit les coups quand se plante le software ...