Java et la sécurité

La bibliographie est http://www.javasoft.com/sfaq/verifier.html

La sécurité dans Java est implantée à différent niveaux :

au niveau du langage :

- Tous les types primitifs ont même taille, pas d'arithmétique sur les pointeurs (et donc pas de parcours de la mémoire).

- Les références aux méthodes et aux instances ne peuvent être manipulés que par des noms symboliques.

- Le langage est fortement typé et intransigeant sur les conversions illégales (entier converti en objets ou vice versa interdit).

- La libération de la mémoire n'est pas à la charge du programmeur mais est géré par le ramasse-miettes.

Pendant et après le chargement

Le code Java a pu éventuellement être généré par compilateur "hostile" et les browsers n'ont pas de moyen pour le savoir. Aussi d'autres barrières de sécurité ont été mises après la compilation.

L'interpréteur ne peut exécuter que du code déjà compilé et pas de fichier source.

Le chargeur de classes (ClassLoader), le format des classes

Les classes sont rangées dans des zones propres à leur origine => les classes locales et fondamentales sont d'abord utilisées.

Le byte code des classes suivent un format décrit par le langage. Ce format contient en en-tête un tableau où les entrées décrivent les entités manipulées par le byte code (chaîne unicode, nom de classe ou d'interface, référence sur un champ ou une méthode, valeur numérique, une String constante). Il n'y a pas de référence à ces entités ailleurs dans le byte-code. Chaque champ de donnée et méthode sont accompagnés de leur signature.

Le "Verifier"

Le "Verifier" est une partie intégrée dans l'interpréteur.

Il fonctionne en 4 passes :

passe 1 : vérification du bon format de la classe

passe 2 : vérification plus poussée : sémantique de final, les classes sauf Object ont une super classe, ...

passe 3 : la plus importante : le byte code verifier
Le byte code de chaque méthode est vérifié. Ce code est découpé en suite d'instructions. Cette passe vérifie alors que tout branchement débute au début d'une instruction (ni au milieu, ni avant ou après le code).
Chaque exécution est d'abord "émulé" avant d'être effectuée :
- si une instruction a besoin de valeurs dans la pile, cette passe vérifie que ces valeurs (de bons type) y sont
- idem pour les registres
- si l'instruction doit empilé, cette passe vérifie que la pile a assez de place.

passe 4 : passe d'optimisation entre le premier chargement d'une classe et les chargements suivants. Lors du déroulement du code, il faut vérifié si la classe où la méthode référencé est véritablement accessible (visibilité), si les méthodes ou champ demandé ont la bonne signature. Par la suite ce n'est plus nécessaire (et new est remplacé par new_quick).