Exemple : création d'une méthode synthétique
Cet exemple illustre la création d'une méthode synthétique. Dans cette méthode synthétique, nous rendons d'abord une zone de classe vulnérable aux taches, puis nous ajoutons un appel à une méthode dans le code de l'utilisateur et nous transmettons enfin le résultat de cet appel de méthode à un collecteur.
- Scénario d'application
- Composants modélisés dans la méthode synthétique
- Etape 1 : créer une méthode synthétique vide
- Etape 2 : modéliser la vulnérabilité aux taches d'une zone de classe
- Etape 3 : modélisation de l'appel de la méthode createUser()
- Etape 4 : modéliser le renvoi de données au client
Scénario d'application
Dans cet exemple, createUser
est une API REST implémentée dans la structure JAX-RS. Un utilisateur peut appeler cette API via une adresse URL telle que http://host:port/users/createUser
. L'exécution de la structure délègue cet appel à UserRestService.createUser()
, étant donné que le chemin correspond. En outre, il initialise la variable de classe urlInfo
des données client avant d'appeler createUser()
. Finalement, les données retournées par createUser()
sont renvoyées au client par l'environnement d'exécution.
Composants modélisés dans la méthode synthétique
Pour la capture du Scénario d'application dans une méthode synthétique, les éléments suivants sont modélisés :
- la vulnérabilité aux taches de la variable de classe
urlInfo
deUserRestService
. - L'appel de
UserRestService.createUser()
. - Le renvoi de données au client.
Voici le code de la méthode createUser()
:
import java.io.BufferedWriter;
@Path("users")
public class UserRestService {
@Context
UriInfo urlInfo;
@Path("/createUser")
public User createUser(){
MultivaluedMap<String, String> queryParams =
urlInfo.getQueryParameters();
String name = queryParams.getFirst("name");
User user = new User(name);
return user;
}
}
Etape 1 : créer une méthode synthétique vide
22 public class JAXRSHandler extends F4FHandler{
23 @Override
public void handleApp(F4FApp app, F4FActions actions) {
24 HighLevelSyntheticMethod synthMethod = HighLevelSyntheticMethod.make();
- L'objet de méthode synthétique est initialisé à la ligne 24.
Etape 2 : modéliser la vulnérabilité aux taches d'une zone de classe
Le fragment de code ci-dessous illustre la manière dont des zones de classe spécifiques peuvent être rendues vulnérables aux taches. Dans cet exemple, l'utilisateur souhaite rendre vulnérables aux taches les zones de classes dotées de l'annotation @Context
.
27 // create a local variable of the appropriate type
28 Local userRestServiceClazzInstance =
synthMethod.newLocal("com.ibm.appscan.UserRestService");
29
30 // get all the class fields
31 for(IField field: app.getIClass
("com.ibm.appscan.UserRestService").getDeclaredInstanceFields()){
32
33 //get all the annotations associated with the field
34 Collection<Annotation> fieldAnnotations = app.getFieldAnnotations(field);
35
36 //for each annotation of the field check if it is an @Context annotation
37 for (Annotation annotation : fieldAnnotations) {
38
39 if (annotation.getType().getName().toString().equals
("Ljavax/ws/rs/core/Context")) {
40
41 // call the F4F API to assign taint to the field
43 synthMethod.addInstanceVariableWrite(
userRestServiceClazzInstance /*Variable representing
class instance*/,
44 field /*field to taint */,
Taint.taint() /* taint */,
null);
45 }
46 }
47 }
L'API Framework for Frameworks addInstanceVariableWrite
prend quatre arguments :
- Le premier argument est la référence de classe dont nous souhaitons rendre la zone vulnérable aux taches. Dans l'exemple, la variable locale
userRestServiceClazzInstance
fait référence à cet argument. - Le second argument est la zone de classe que nous souhaitons rendre vulnérable aux taches.
- Le troisième argument est la nouvelle valeur qui va être affectée au champ de variable de classe. Dans l'exemple, cette variable doit être rendue vulnérable aux taches pour transmettre
Taint.taint()
. - Le dernier argument est
FilePositionInfo
qui a la valeurnull
dans l'exemple.
Etape 3 : modélisation de l'appel de la méthode createUser()
Au cours de cette étape, nous simulons l'appel dans notre méthode synthétique.
50 // call createUser() and store the returned value to a local variable
51 Local returnObj = synthMethod.addCall(
52 "com.ibm.appscan.UserRestService.createUser():com.ibm.appscan.User"
/* signature of the method to be called */,
null, /* FilePositionInfo */
53 userRestServiceClazzInstance /* Object on which the method
will be called */);
L'API de haut niveau addCall
présente trois arguments :
- Le premier argument est la signature de la méthode que nous souhaitons appeler. Dans ce cas,
User.createUser()
doit être appelée, sa signature est donc utilisée. - Le deuxième argument est
FilePositionInfo
. Il est transmis avec la valeurnull
car il n'est pas obligatoire pour cet exemple. - Le dernier argument représente la liste des paramètres requis pour appeler la méthode
createUser()
.
Etant donné que createUser()
n'admet aucun argument, le seul argument transmis à cet appel est l'objet this
, une variable Local
(userRestServiceClazzInstance
) du type User
. La méthode createUser()
renvoie un nouvel élément User
créé et stocké dans une nouvelle variable Local
nommée returnedObj
(voir ligne 51).
Etape 4 : modéliser le renvoi de données au client
Lors de cette dernière étape, nous créons un collecteur afin de modéliser le renvoi de données au client.
58 // create a PrintWriter object
59 Local printWriterObj = synthMethod.newLocal("java.io.PrintWriter");
60
61 // we want to call the print API on the PrintWriter object.
// The print API takes a single argument of Object type returns void
62
63 // we create a param list of size 2. The first item in this list is always the
// 'this' object and rest are actual method arguments.
64 Param[] printWriterObjParam = new Param[2];
65 printWriterObjParam[0] = printWriterObj; // The "this" object
// the value returned by the call to the createUser method
66 printWriterObjParam[1] = returnObj;
67
68 // Now add a call to the print method
69 synthMethod.addCall("java.io.PrintWriter.print(java.lang.Object):void",
null, printWriterObjParam);
70 }
- A la ligne 59, un objet
Local
est créé pour la classePrintWriter
dans la méthode synthétique. - De la ligne 64 à la ligne 66, la liste des paramètres requis pour appeler la méthode
print
sur l'instance de classePrintWriter
est préparée (printWriterObj
) :- Le premier paramètre est la référence d'objet (
printWriterObj
). - Le deuxième paramètre est l'argument de la méthode
print
. Il faut transmettre la valeur de renvoi stockée dans la variable LocalreturnObj
.
- Le premier paramètre est la référence d'objet (
- A la ligne 69, un appel de méthode
PrintWriter.print
est ajouté pour modéliser le renvoi des données au client.