par , 06/01/2017 à 20h21 (2058 Affichages)
Aujourd’hui la surveillance des événements en réseaux et bases de données constitue la base des SIEM. En revanche peu de choses existent pour le code source des applications. Aussi dans ce billet nous verrons comment auditer les événement durant l’exécution d’un code source en Java.
J’ai choisi d’illustrer cette thématique sécuritaire à l’aide d’un exemple simple : une application médicale. Cette application permet (entre autre) de lire des dossiers des patients. Ces dossiers médicaux sont confidentiels, seuls les personnels autorisés peuvent y accéder. Bien entendu, cette application fait l’objet de mesures d’authentification et de gestion des droits permettant de s’assurer que personne n’accède aux dossiers médicaux s’il n’y est pas autorisé. Mais si un paparazzi réussissait à violer ces mesures de confidentialité pour accéder au dossier d’une rock-star, Il serait alors intéressant de savoir comment il s’y est pris et de mettre en place une mesure de sécurité contre la faille exploitée par le hacker. On remarque que dans cet exemple la menace est réelle, l’exploit est sans doute réalisable mais surtout très opportun.
Pour détecter une menace, ou si elle est déjà détectée (parution des informations dans la presse à scandale) pour connaître le mode opératoire du hacker, il faut disposer d’informations brutes relatives à cet incident.
Bien entendu ces données d’incident peuvent être obtenues en dehors de l’application (vidéosurveillance de l’hôpital, interrogatoire en garde à vue…), mais si le code source possède son propre système d’enregistrement des événements, la couverture sécuritaire est beaucoup complète.
Nous manipulerons 2 types d'objets métier : le dossier médical (classe Dossier) et le personnel médical (classe Personnel).
L'objet dossier sera muni d'une méthode lire qui ne pourra qu'être invoquer par un objet personnel. L'objet de cet exemple est de surveiller comme unique événement : qui lit un dossier et quand. Dans la réalité ce genre de log serait croisé avec des informations horaires de présence du personnel qui permettraient de mettre en lumière une usurpation d’identité.
Voici un code naïf de la classe Dossier et Personnel :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| public class Personnel {
private int id;
private String name;
private String role;
public Personnel(int ident, String nom, String fonction) {
this.setId(ident);
this.setName(nom);
this.setRole(fonction);
}
public void lire(Dossier dossier) {
dossier.lire(this);
}
// getter et setter
}
public class Dossier {
private int id;
private String nomPatient;
private String maladie;
private String traitement;
public Dossier(int ident, String nom, String mal, String trait){
this.setId(ident);
this.setNomPatient(nom);
this.setMaladie(mal);
this.setTraitement(trait);
}
// getter et setter
public void lire(Personnel pers){
System.out.println(this.getNomPatient() + " a été admis pour " + this.getMaladie() + " et a recu comme traitement : " + this.getTraitement());
}
} |
Le développeur est très fier de ce code car seul un personnel autorisé peut invoquer la méthode lire sur un dossier. Mais voilà, un paparazzi à usurpé l'identité d'une infirmière absente et ainsi pu voler des informations qui lui rapporteront une jolie prime.
Voici le code du scenario de test qui nous servira pour tout l'exercice :
1 2 3 4 5 6 7 8 9
| public static void main(String[] args) {
System.out.println("début d'execution du code");
Personnel paparazzi = new Personnel(1, "Joelle", "infirmière");
Personnel carter = new Personnel(2, "carter", "Medecin");
Dossier dossier = new Dossier(1, "RockStar", "addiction à la cocaine", "repos et vitamine");
paparazzi.lire(dossier);
carter.lire(dossier)*;
System.out.println("fin d'execution du code");
} |
Modifions maintenant ce code pour mettre sous surveillance la méthode lire de notre dossier.
L'idée sera de créer un objet (classe Enregistreur) qui journalisera tous les personnels qui lisent un dossier. Nous utiliserons le Design pattern Observateur qui permettra d'abonner les objets dossier à l'enregistreur.
Notre enregistreur sera mis en place au démarrage du système et possèdera une méthode audit que l'administrateur pourra invoquer pour visualiser le log. Pour les besoins de ce billet notre enregistreur stockera les données dans une collection (List) mais dans la réalité un fichier ou une table de la base sera utilisé. Dans le même esprit, la méthode audit ne fera que lister à l'écran le contenu du log.
Mais revenons à notre code source, on remarquera que pour s'assurer que chaque objet dossier s'abonne à un gestionnaire de log, on l'imposera dans le constructeur de la classe.
Voici le code de classe Enregistreur :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| public class Enregistreur implements Observer {
private List<String> evenements;
public Enregistreur() {
this.evenements = new ArrayList<String>();
}
public void update(Observable o, Object arg) {
if (o instanceof Dossier)
this.evenements.add("Dossier N° " + ((Dossier) o).getId() + " lu par " + ((Personnel) arg).getName() + " " + ((Personnel) arg).getRole() + " à " + new Date());
}
public void audit(){
Iterator<String> it = this.evenements.iterator();
while (it.hasNext())
System.out.println(it.next());
}
} |
et de la classe Dossier modifiée :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| public class Dossier extends Observable{
private int id;
private String nomPatient;
private String maladie;
private String traitement;
public Dossier(int ident, String nom, String mal, String trait, Observer o){
this.setId(ident);
this.setNomPatient(nom);
this.setMaladie(mal);
this.setTraitement(trait);
this.addObserver(o);
}
public void lire(Personnel pers){
System.out.println(this.getNomPatient() + " a été admis pour " + this.getMaladie() + " et a recu comme traitement : " + this.getTraitement());
setChanged();
notifyObservers(pers);
}
// getter et setter
} |
Voici maintenant la code du test de cette nouvelle architecture :
1 2 3 4 5 6 7 8 9 10 11
| public static void main(String[] args) {
Enregistreur recorder = new Enregistreur(); // mis en place au lancement de l'application
System.out.println("début d'execution du code surveillé");
Personnel carter = new Personnel(2, "carter", "Medecin");
Personnel paparazzi = new Personnel(1, "Joelle", "infirmière");
Dossier dossier = new Dossier(1, "RockStar", "addiction à la cocaine", "repos et vitamine", recorder);
paparazzi.lire(dossier);
carter.lire(dossier);
System.out.println("fin d'execution du code");
recorder.audit(); // à l'initiative de l'administrateur SSI
} |
l'exploitation des logs dans le cas présent pourrait détecter une possible intrusion rien qu'en identifiant un personnel qui aurait lu de nombreux dossiers médicaux en rupture avec les habitudes de l'établissement.
Si vous utilisez vous aussi des outils ou des méthodes pour sécuriser le code source, n'hésitez pas à laisser un commentaire sur ce billet.
Mis à jour 06/01/2017 à 20h44 par autran
- Catégories
-
Java