Sicherheitsimplikationen beim Einsatz von Test Doubles zur automatisierten Bewertung studentischer Java- Programme mit Graja und mockito Robert Garmann Hochschule Hannover Fakultät IV - Wirtschaft und Informatik Ricklinger Stadtweg 120 30459 Hannover robert.garmann@hs-hannover.de Zusammenfassung setzt, die z. B. mittels der Bibliothek mockito [Ka13] erstellt wer- Wir demonstrieren, dass der Einsatz von Test Doubles bei der den. An einer Beispielaufgabe verdeutlichen wir in Abschnitt 2, automatisierten Bewertung studentischer Java-Programme wie der JUnit-basierte Autobewerter Graja und mockito zur Be- besondere Sicherheitsfragen aufwirft. Wie skizzieren kurz eine obachtung interner Programmschnittstellen genutzt werden mögliche Antwort auf diese Fragen. können. Das studentische Programm wird bei der dynamischen Analyse Im ersten Teil demonstrieren wir die Erstellung eines sog. ausgeführt. Sicherheitsmaßnahmen auf dem Bewertungsrechner AssignmentGraders, der in der Lage ist, interne Programm- sind notwendig, um ungewolltes oder böswilliges Fehlverhalten schnittstellen eines maschinell zu bewertenden Java-Programms des studentischen Programms zu unterbinden. In Abschnitt 3 zu beobachten. Beispielhaft nutzen wir den Autobewerter Graja in stellen wir das betrachtete Modell eines Bewertungssystems vor Verbindung mit mockito Test Doubles. Wir zeigen, wie man und diskutieren relevante Sicherheitsaspekte. Leistungsaspekte einer studentischen Lösung einzeln und gezielt automatisiert bewertet. Bei einer Beschränkung auf die Bibliotheken wie mockito wurden nicht für die automatisierte Beobachtung externer Programmschnittstellen würden sich diese Programmbewertung entworfen. Die Sicherheit der Aspekte der gezielten Bewertung entziehen. Im zweiten Teil Testumgebung spielt beim (Regressions-)Test großer beleuchten wir Bedrohungen des das zu bewertende Programm Softwaresysteme meist eine untergeordnete Rolle. Im ausführenden Systems und gewichten ausgewählte Ursachen. Wir Bewertungsszenario jedoch wirft der Einsatz einer solchen konzentrieren uns auf Bedrohungen, die mit Mitteln der Java-2- Bibliothek essentielle Sicherheitsfragen auf, für die wir in Sicherheitsarchitektur beherrschbar sind und liefern einige Abschnitt 4 eine mögliche Lösung vorstellen. Beispiele zur Abgrenzung. Die Eigenheiten der Java-2- Sicherheitsarchitektur werfen im Kontext des Test Double 2. Beobachtung programminterner Einsatzes Fragen auf, die wir im dritten Teil erörtern. Test Schnittstellen Doubles sollten in einem anderen Schutzbereich der Java-2- Die Frage, wann ein studentisches Programm gut ist, ist nicht Sicherheitsarchitektur als der studentische Code liegen. Um eine leicht zu beantworten. Neben dem Kriterium der funktionalen privilegierte Ausführung der Test Doubles auch dann zu forcieren, Korrektheit muss das Programm nichtfunktionale Kriterien wenn der Aufruf aus studentischem Code erfolgt, schlagen wir erfüllen (Effizienz, Änderbarkeit, …). Einige dieser Kriterien den Einsatz von Proxy-Objekten vor. Um auch Nicht-Spezialisten lassen sich recht gut automatisiert untersuchen. Grundsätzlich gibt der beschriebenen Sicherheitsbelange die Autorenschaft von es zwei Herangehensweisen bei der maschinellen Untersuchung AssignmentGradern zu ermöglichen, entwickeln wir eine eines Bewertungsobjektes [SL05]: die statische Code-Analyse Wrapper-Bibliothek für mockito, deren zentrale Entwurfsideen (bspw. in [SBG10]) und die dynamische Code-Analyse (bspw. in wir kurz skizzieren. [KSZ02], [Ed03]). In diesem Aufsatz befassen wir uns mit der letztgenannten Herangehensweise, der Beobachtung des 1. Einleitung Verhaltens eines studentischen Java-Programms durch Tests. Automatisierte Bewertung studentischer Programme wird in der Informatik-Lehre zurzeit überwiegend im formativen Assessment Bei der dynamischen Code-Analyse beobachtet man das eingesetzt. Zeit- und ortsunabhängiges, maschinell erstelltes, Laufzeitverhalten des Bewertungsobjekts an beobachtbaren quantitatives und qualitatives Feedback soll Studierende in die Schnittstellen. Hervorragend geeignet für die Überprüfung der Lage versetzen, ihre (Teil-)lösungen zu Programmierübungen funktionalen Korrektheit des Bewertungsobjekts sind Ein- und schrittweise zu verbessern. Ausgabeschnittstellen des Benutzers, die auch leicht einer maschinellen Bedienung bzw. Abfrage zugänglich sind. Studentische Programme müssen funktionale und nichtfunktionale Interessante Schnittstellen für die Bewertung des studentischen Anforderungen erfüllen, die mit statischen oder dynamischen Programmverhaltens sind u. a.1 Tastatureingabe, Consolenaus- Analyseverfahren untersucht werden können. Für die Analyse der gabe, Mauseingabe, GUI-Ausgabe [TE08], Kommandozeilen- „inneren Qualität“ des Bewertungsobjekts spielt die dynamische argumente beim Programmstart, Dateiein-/-ausgabe. Allen Analyse an internen Programmschnittstellen (Methodenaufruf) genannten Schnittstellen gemein ist, dass sie prinzipiell auch vom eine wichtige Rolle. Unittest-Frameworks wie JUnit wurden dazu entwickelt, kleinste Einheiten eines Testobjekts durch 1 Methodenaufruf und Verifizierung des Ergebnisses dynamisch zu Über diese nicht abschließende Aufzählung hinaus sind selbst- untersuchen. Um die zu untersuchende Einheit für die Dauer des verständlich viele weitere Schnittstellen denkbar (Umgebungs- Tests vom Restsystem zu isolieren werden Test Doubles einge- variable, Audio/Video, Netzwerk, etc.). Benutzer des studentischen Programms bedient werden können. Berechnen Sie die Länge der Hypotenuse eines rechtwinkligen Um ein Bewertungsobjekt nun automatisiert mit Eingaben über Dreiecks. Teilen Sie den Programmcode auf zwei Klassen auf: die genannten Schnittstellen zu versorgen und die Ausgaben ma- QuadratImpl implementiere das folgende vorgegebene schinell auszuwerten, werden Autobewerter wie der hier Interface: eingesetzte Graja [St13] verwendet. package de.hsh.prog; public interface Quadrat { Ein automatisiertes Bewertungsverfahren nimmt bei Nutzung der double quadrat(double v); // berechnet v² oben genannten Schnittstellen das Bewertungsobjekt als „black } box“ wahr und kann wenig über die Qualität der inneren Struktur Schreiben Sie eine weitere Klasse Hypo mit einer statischen des Bewertungsobjekts erfahren. Gut überprüfbar ist die Methode hypo, die als ersten Parameter ein Quadrat-Objekt und funktionale Korrektheit und die Überprüfung einiger als zwei weitere Parameter die Längen zweier Katheten erhält. nichtfunktionaler Eigenschaften (z. B. Ressourcenverbrauch). Um Gewünschter Rückgabewert ist die Länge der Hypotenuse. mehr über die „innere Qualität“ des Bewertungsobjekts zu Quadrierungen soll hypo an das Quadrat-Objekt delegieren. erfahren, ist es hilfreich, das studentische Programm an internen Abbildung 1: Stark vereinfachte Beispielaufgabe Programmschnittstellen zu beobachten. Eine geeignete Schnittstelle ist der Methodenaufruf mit Methodenparametern als 2.3 Bewertung mit Graja Eingabe und Methodenrückgabe als Ausgabe. Den Bewertungsaspekt (1) überprüft der in Abbildung 2 dar- Im Folgenden geben wir einen kurzen Überblick über die gestellte, mit Graja kompatible Code. Funktionen von Graja und stellen eine Beispielaufgabe vor. Der Aufruf der internen Programmschnittstelle des studentischen Danach zeigen wir, wie studentische Lösungsversuche für diese Codes ist in Programmzeile 06 zu finden. Davor wird eine Instanz Aufgabe mit Graja unter Einsatz von Test Doubles bewertet der studentischen Klasse erzeugt und danach das beobachtete werden können. Ergebnis überprüft. Diese Art von Bewertungscode ist dem in der 2.1 Graja professionellen Softwareentwicklung verbreiteten Testcode für Modultests sehr ähnlich. Spezialitäten der hier betrachteten Graja (“Grading Java programs”) ist i. w. ein Überbau über dem Programmbewertung sind die in Zeile 01 vergebenen Teilpunkte JUnit2-Testframework und hat seine Charakterzüge von seinem und der in Zeile 08f zu findende ausführliche Fehlerhinweis. Vorbild WebCAT [Ed03] geerbt. Graja bietet u. a. folgende Weiterhin besonders ist die von Graja angebotenen Reflection- Funktionen: Bibliothek (Zeile 04f), die etwaige Exceptions in verständliche  Extrahieren und Übersetzen von Code aus einem ZIP-Archiv, Fehlermeldungen verwandelt.  Umleitung von Standard-Ein/Ausgabeströmen zur Verein- 01 @Test @ScoringWeight(35.0) fachung der maschinellen Steuerung des Bewertungsobjekts, 02 public void pruefeQuadratMethode() {  intelligente Vergleiche von erwarteter und beobachteter Aus- 03 double a= 3, expected= a*a; gabe eines Bewertungsobjekts, 04 Quadrat studentImpl= ReflectionSupport.create( 05 getSubclassForName("QuadratImpl",Quadrat.class));  bequeme „reflection“-basierte Analyse studentischen Codes, 06 double observed= studentImpl.quadrat(a);  Generierung formatierter, zielgruppenorientierter, und nach 07 org.junit.Assert.assertEquals( Kritikalität abgestufter Bewertungskommentare, 08 "quadrat("+a+")="+observed+" (erwartet :"+expected 09 +")", expected, observed, 1E-5);  abgestufte Punktevergabe für verschiedene vom Dozenten 10 } festzulegende Bewertungsaspekte,  Übersetzung und Ausführung von „on the fly“ generiertem Abbildung 2: Bewertung des Aspekts (1) Java-Code während der Bewertung, 11 @Test @ScoringWeight(25.0)  Begrenzung der genutzten Systemresourcen (Laufzeit, 12 public void pruefeGesamtfunktion() { persistenter Speicherplatz, Hauptspeicher), 13 double a=3, b=4, cExpected=5;  Ausführung des studentischen Codes und des 14 Quadrat stub= Mockito.mock(Quadrat.class); 15 Mockito.when(stub.quadrat(a)).thenReturn(a*a); Bewertungscodes in verschiedenen, separat abgesicherten 16 Mockito.when(stub.quadrat(b)).thenReturn(b*b); Schutzbereichen. 17 double c= ReflectionSupport.invokeStatic( 18 getClassForName("Hypo"),double.class,"hypo",stub,a,b); 19 org.junit.Assert.assertEquals("hypo(q,"+a+","+b+")="+c+ 2.2 Beispielaufgabe 20 " (erwartet: "+cExpected+")", cExpected, c, 1E-5); Wir betrachten eine für Zwecke der konzentrierten Darstellung 21 } stark vereinfachte Programmieraufgabe (s. Abbildung 1). Abbildung 3: Bewertung des Aspekts (2) Diese Aufgabe verlangt vom Studierenden nicht nur die Programmierung einer einfachen mathematischen Formel, 22 @Test @ScoringWeight(40.0) 23 public void pruefeAufrufVonQuadrat() { sondern die Implementierung einer vorgegebenen Schnittstelle. 24 double a=3, b=4; Eine korrekte Lösung kann nicht nur Hypotenusen berechnen (2); 25 Quadrat mock= Mockito.mock(Quadrat.class); eine korrekte Lösung kann darüber hinaus Quadrate berechnen (1) 26 ReflectionSupport.invokeStatic( und sie setzt Wiederverwendung durch Delegation ein (3). Für 27 getClassForName("Hypo"),double.class,"hypo",mock,a,b); 28 try { jeden der im vorstehenden Satz markierten Bewertungsaspekte 29 Mockito.verify(mock, Mockito.times(1)).quadrat(a); möchten wir Teilpunkte vergeben. 30 Mockito.verify(mock, Mockito.times(1)).quadrat(b); 31 } catch (WantedButNotInvoked e) { 32 org.junit.Assert.fail("hypo muss die Quadrierung "+ 33 "an den Quadrat-Parameter delegieren"); 34 } 35 } 2 http://junit.org/ Abbildung 4: Bewertung des Aspekts (3) 2.4 Test Doubles: Stubs und Mocks  AutograderCore: Der Kern des Autobewerters, welcher eine Ähnlich ließe sich nun der Bewertungsaspekt (2) untersuchen, Startroutine und eine Bibliothek mit bewertungs- indem eine QuadratImpl-Musterlösung als Parameter an die unterstützenden Funktionen enthält. Ein Beispiel einer studentische hypo-Methode übergeben wird. Die erneute AutograderCore-Komponente ist Graja. Verwendung einer u. U. fehlerhaften studentischen QuadratImpl-  AssignmentGrader: vom Dozenten erstellter, auf eine Klasse würde die Bewertung des Aspekts (2) negativ verzerren. spezielle Programmieraufgabe zugeschnittener Code (kann Der Fehler würde in zwei Bewertungsaspekten „gezählt“. Fremdsoftware, bspw. die mockito-Bibliothek beinhalten). Die Codeschnipsel der Abschnitte 2.3 und 2.4 entstammen Als Alternative zu einer eigenen Musterlösung kann man ein Test dieser Komponente. Double [Me07] einsetzen – ein Platzhalter-Objekt, mit dem ein  Submission: vom Studenten erstellter Lösungsversuch. untersuchter Programmteil (das sog. system under test - kurz SUT) während des Tests interagiert. Stub-Objekte sind Test Doubles, Jede Komponente5 stellt einen eigenen Schutzbereich (protection die vorgefertigte Antworten an das SUT liefern. domain) mit jeweils eigenen Rechten (permissions) dar. Der Code in Abbildung 3 verwendet in Zeile 14 die Bibliothek mockito3 zur Erzeugung eines Stubs, welches das Interface Quadrat vollständig implementiert. Die beiden folgenden Zeilen „bestücken“ das Stub mit vorbereiteten Antworten auf erwartete Anfragen des SUT4. In Zeile 17f kommt das SUT (hier die Abbildung 5: Drei geladene Komponenten studentische Methode hypo) zur Ausführung. Als Übergabe- 3.2 Benötigte Rechte parameter erhält hypo das Stub-Objekt. Der AutograderCore benötigt für seine Funktion weitgehende Der Bewertungsaspekt (3) lässt sich schließlich durch eine weitere Rechte (Zugriffe auf das lokale Dateisystem, Ausführen des Test Double Variante, die sog. Mock-Objekte realisieren (vgl. Compilers, Verwendung eigener Klassenlader, Zugriff auf Abbildung 4). Ein Mock-Objekt wird in Zeile 25 erstellt, welches Reflection-Funktionen, etc.). Die Submission benötigt in der die Quadrat-Schnittstelle implementiert. Da uns bei diesem Regel wenige Rechte, wobei dies sicher von der Art der zu Bewertungsaspekt das Berechnungsergebnis nicht interessiert, lösenden Programmieraufgabe abhängt. Dazwischen im Sinne der programmieren wir keine vorbereiteten Antworten. Stattdessen Rechtemenge steht der AssignmentGrader, der häufig grund- befragen wir das Mock-Objekt nach Ausführung des SUT in Zeile legende Rechte für Dateizugriffe, manchmal auch weitergehende 29f, ob es Aufrufe mit den angegebenen Parametern erhalten hat. Rechte besitzen muss. Eine Teilmengenbeziehung zwischen den benötigten Rechtemengen der drei genannten Schutzbereiche 3. Sicherheit des Bewertungssystems besteht nicht notwendigerweise. Der Ansatz, studentische Lösungen dynamisch zu analysieren, erfordert die Ausführung des studentischen Codes. Im Unter- 3.3 Bedrohungspotential schied zu herkömmlichen Software-Tests, wo Tester und Autor Um das Bedrohungspotential6 der einzelnen Komponenten einander vertrauen (bei Unit-Tests oft sogar dieselbe Person sind), einschätzen zu können, betrachten wir zunächst die in Tabelle 1 wo also die Testumgebung vom zu testenden System kein böswil- aufgeführten Merkmale der Komponenten-Autoren. Die beiden liges Verhalten zu befürchten hat, ist dies beim Test von studen- ersten Merkmale begünstigen bei hoher Ausprägung unabsichtlich tischen Einreichungen anders. Hier muss mit Angriffen des getes- herbeigeführte Bedrohungen, das dritte Merkmal begünstigt teten Codes auf die Testumgebung gerechnet werden. Einige An- absichtlich herbeigeführte Bedrohungen, das vierte Merkmal griffsbeispiele stellt Abschnitt 3.4 vor. Dazu kommen unab- begünstigt jede Art von Bedrohung. sichtliche Programmierfehler in weitaus größerem Umfang als bei Tabelle 1: Betrachtete Merkmale der Komponenten-Autoren Tests professioneller Software. Schutzmaßnahmen gegen solche Ausprägungs- Angriffe sind daher unabdingbar. In diesem Abschnitt wollen wir grad7 für … Assignment- Autograder- Submission konkrete Bedrohungen und Gegenmaßnahmen beleuchten. Grader Core 3.1 Schutzbereiche Als Bewertungssystem betrachten wir einen separaten Betriebs- Nr. Merkmal systemprozess. Aus konzeptioneller Sicht lädt der Prozess drei verschiedene Komponenten und führt sie aus (vgl. Abbildung 5). 1 Geringe Programmiererfahrung - - + Wir gehen davon aus, dass alle Komponenten aus Java Bytecode 2 Geringe Bereitschaft, Zeit für die korrekte Pro- - 0 + bestehen, die von derselben JVM-Instanz geladen werden: grammierung der Komponente aufzuwenden 3 „Kriminelle Energie“, d. h. Bereitschaft, - - + 3 Bedrohungen absichtlich herbei zu führen. http://code.google.com/p/mockito/ 4 Größe der Autorengruppe - 0 + 4 Zur Funktionsweise der auf der ersten Blick verwirrenden Aufrufsyntax folgt eine kurze Erläuterung: Mockito.mock erzeugt Vor diesem Hintergrund erwarten wir von der Submission-Kom- ein Objekt einer zur Laufzeit mit cglib (http://cglib.sourceforge. ponente das größte Bedrohungspotential. Die AssignmentGrader- net/) erzeugten Subklasse von Quadrat. Das wie ein normaler Methodenaufruf aussehende stub.quadrat(a) führt mockito- 5 In der Praxis entspricht jede Komponente einem jar-Archiv oder intern dazu, dass eine ID des aktuell ausgeführten Threads in jeweils einer Menge von jar-Archiven. Jedem jar-Archiv wird einer Datenstruktur zusammen mit dem stub-Objekt und dem ein Satz von Rechten zugeordnet. Wert a abgelegt wird. Der Rückgabewert von stub.quadrat(a) 6 wird zwar an Mockito.when weiter gereicht, dort jedoch nicht Wir meinen hiermit das, was in etablierten Risikoschätzme- ausgewertet. Stattdessen weist die ID des aktuell ausführenden thoden wie [oV13] „likelihood“ genannt wird. 7 Threads den Weg zum soeben abgelegten stub-Objekt. Legende: -=gering, 0=mittel, +=hoch Komponente, die in der Regel von Lehrkräften oder Hilfspersonal 3.4.2.1 „rm –rf /“ erstellt wird, ist weniger kritisch, den AutograderCode erachten Ein bösartiges Beispiel für Submission-Code, welcher versucht, wir als Komponente mit dem geringsten Bedrohungspotential. alle Dateien im Dateisystem zu löschen: 3.4 Bedrohungen im Einflussbereich des Java Runtime.getRuntime().exec("rm –rf /"); Securitymanagers Durch Gewährung selektiver Dateizugriffsrechte mittels der Java Uns interessieren ganz allgemein alle Bedrohungen der Vertrau- Sicherheitsarchitektur oder auch mittels der vom Betriebssystem lichkeit und Integrität der Daten auf dem die JVM beherbergen- verwalteten Dateirechte kann dieser Angriff gut abgewehrt wer- den System (Dateien, Nutzerdaten, Musterlösungen, …), sowie den. alle Bedrohungen der Verfügbarkeit des Bewertungsdienstes. Wir 3.4.2.2 Denial of service wollen mit der Bedrohungsanalyse dieses Kapitels keine konkret Ein anderes Beispiel, das versucht Schaden anzurichten, in dem es auszumerzenden Schwachstellen identifizieren, sondern es soll die Festplatte füllt10: hier darum gehen, einige mögliche Angriffe mit ihren FileOutputStream f=new FileOutputStream("x"); Auswirkungen („impacts“) zu benennen, die genügend Motivation while (true) f.write(42); liefern, um den Einsatz des Java Securitymanagers für sinnvoll zu erachten. In der folgenden Darstellung nehmen wir die zu Wenn wir davon ausgehen, dass Submission-Code in wenigstens motivierende Maßnahme vorweg: den Einsatz des Security- einem Verzeichnis Schreibrechte eingeräumt werden müssen, ist managers. Die Motivation der Maßnahme durch Angriffsbeispiele dieser denial of service Angriff mit Mitteln der Java Sicher- folgt in Abschnitt 3.4.2. heitsarchitektur unseres Wissens nicht abwehrbar. Hier müssen dem die JVM beherbergenden Betriebssystemprozess Ressourcen 3.4.1 Einsatz der Java Sicherheitsarchitektur in begrenztem Maße zugeteilt werden. Beispielsweise in Form Konkret wollen wir dem Submission-Schutzbereich Rechte einer separaten Festplattenpartition oder in Form einer Datei erteilen oder entziehen, die der Menge aller durch die Java begrenzter Größe, die als loopback device verwendet wird. Sicherheitsarchitektur definierten Rechte entnommen werden. Ein Ähnlich müssen die Ressourcen Hauptspeicher und CPU-Zeit paar Beispiele seien hier genannt8: durch die Umgebung der JVM begrenzt werden, etwa über einen  PropertyPermission: Auslesen oder Setzen von Umgebungs- Parameter zum maximalen Speicherverbrauch beim JVM-Start informationen (bspw. mag eine Submission berechtigter- bzw. mit Hilfe des Linuxkommandos timeout. weise das auf dem System gebräuchliche Zeichen für den Zeilenumbruch abfragen wollen - line.separator) 3.4.2.3 „/etc/passwd“  FilePermission: Dateizugriffsrechte (bspw. Einlesen und Es folgt ein Beispiel, das versucht, die Liste der Benutzernamen Schreiben von Dateien im Arbeitsbereich der Submission) des Systems auszuspähen:  SocketPermission: Netzzugriffsrechte (bspw. soll die Sub- System.out.println(Files.readAllLines(new File("/etc/passwd"). toPath(), Charset.forName("UTF-8"))); mission auf eine im Netz vorgehaltene Datenbank zugreifen)  ReflectPermission: potentes Recht zur Überwindung der Da die Datei /etc/passwd i. d. R. für jeden Systemnutzer lesbar ist, private/protected-Kapselung (wird der Submission i. d. R. können vom Betriebssystem verwaltete Dateirechte nicht greifen. entzogen; Begründung am Beispiel in Abschnitt 3.4.2.5) Dies ist eine Bedrohung, die durch selektive Rechte gemäß der  RuntimePermission: diverse potente Rechte vom Nachladen Java Sicherheitsarchitektur abwehrbar ist. weiterer Klassen bis zur Umleitung der Ein-/Ausgabe (für 3.4.2.4 Ausspähen der Musterlösung Submission i. d. R. nicht erforderlich und damit entziehbar) Ist etwa der Klassenname einer Musterlösung, die häufig Teil der AssignmentGrader-Komponente ist, bekannt oder erraten worden, Viele Bedrohungen können durch die Java Sicherheitsarchitektur könnte man wie folgt versuchen, an den Bytecode der kontrolliert werden. Insbesondere gegen unabsichtlich Musterlösung zu kommen: herbeigeführte Bedrohungen ist das Sandbox-Prinzip der Java InputStream is= Class.forName("org.domain.sample.Solution"). Sicherheitsarchitektur ein wirksamer Mechanismus. Absichtlich getResourceAsStream("Solution.class"); herbeigeführte Bedrohungen können nicht völlig9 durch die Java int b; while ((b= is.read()) >= 0) System.out.print(b+" "); Sicherheitsarchitektur unterbunden werden, wie die Beispiele des Die Standardausgabe wird dem Autor der Submission i. d. R. zur folgenden Abschnitts zeigen sollen. Erläuterung der Bewertung angezeigt. 3.4.2 Beispiele absichtlich herbeigeführter Dieser Angriff ist leicht mit Mitteln der Java Bedrohungen Sicherheitsarchitektur abwehrbar, indem das Recht zum Einlesen Zur Ein- und Abgrenzung seien einige ganz konkrete Beispiele für des AssignmentGrader-jar-Archivs nicht gewährt wird. absichtlich herbeigeführte Bedrohungen genannt. Diese Liste ist verständlicherweise nicht erschöpfend. Sie soll über die Liste des 3.4.2.5 Ausführen der Musterlösung Abschnitts 3.4.1 hinaus einen Eindruck davon vermitteln, welche Die Submission könnte versuchen, die Musterlösung einfach Bedrohungen allein mit Mitteln der Java Sicherheitsarchitektur auszuführen und dadurch die generierten Ausgaben als die abwendbar sind und welche zusätzliche Maßnahmen erfordern. eigenen zu „verkaufen“. Dieser Angriff lässt sich abwehren, Die Beispiele geben außerdem einen Eindruck des möglichen indem die Musterlösungsklasse als package private deklariert wird „impact“ [oV13] erfolgreicher Angriffe. und indem Submission-Code das Recht zur Überwindung der Package-Kapselung nicht erhält. 8 Weitere s. z. B. http://docs.oracle.com/javase/7/docs/technotes/ guides/security/permissions.html 9 10 Noch dazu muss immer wieder mit neu entdeckten Sicher- Bei diesem Beispiel kann es sich auch um eine unabsichtlich heitslücken in der Java Sandbox gerechnet werden. herbeigeführte Bedrohung handeln. 4. Test Doubles bei aktivem Securitymanager in Java den doPrivileged-Aufruf. Ein solcher Aufruf wirkt als Ab- Das vorangegangene Kapitel hat motiviert, dass der Einsatz der bruchskriterium bei der Bildung der o. g. Rechte-Schnittmenge. Java Securitymanagers sinnvoll ist, um reale Bedrohungen Oberhalb des doPrivileged-Aufrufs am Aufrufstapel beteiligte abzuwenden. Die durch den Einsatz des Securitymanagers Schutzbereiche werden nicht berücksichtigt. resultierenden Auswirkungen auf den Einsatz von Test Doubles Wäre etwa im Beispiel der Abbildung 6 der Aufruf der Methode d sind Gegenstand des nun folgenden Kapitels. ein privilegierter Aufruf, würde die resultierende Schnittmenge die Rechte {2, 4} umfassen. 4.1 Wirkung der Schutzbereiche zur Laufzeit Die drei in Abschnitt 3.1 eingeführten Schutzbereiche werden 4.2 Sicherheitsimplikationen durch Test üblicherweise der Klasse der Anwendungsbereiche (application Doubles domains) zugeordnet. Ein vierter Schutzbereich mit i. d. R. unein- Beim Einsatz von Test Doubles ruft Submission-Code Test geschränkten Rechten ist der Systembereich (system domain), Doubles des AssignmentGrader-Schutzbereichs auf (vgl. Aufruf dem u. a. die Klassen der Java-Standardbibliothek angehören. der Methode h in Abbildung 7). Ohne besondere Vorkehrungen Bei eingeschaltetem Securitymanager prüft die JVM zur Laufzeit würde der Code im Test Double mit den Rechten der Schnittmen- alle an der aktuell aufzurufenden Operation beteiligten ge (AutograderCore ∩ AssignmentGrader ∩ Submission) aus- Komponenten auf dem Aufrufstapel. Programmcode eines einge- geführt, also der Rechtemenge {4}. Der von mockito erzeugte schränkten Anwendungsbereichs darf durch Aufruf einer Bytecode eines Test Doubles ruft jedoch Methoden der mockito Operation des Systembereichs selbstverständlich keine zu- Bibliothek auf (Methode i), die weitgehende Rechte erfordern, sätzlichen Rechte erlangen. Die JVM ermittelt daher die u. a. das sehr potente Recht java.lang.reflect.ReflectPermission Schnittmenge der Rechte aller am Aufrufstapel beteiligten "suppressAccessChecks", welches den Zugriff auf private und pro- Schutzbereiche, um eine potentiell bedrohliche Operation zu tected member einer Klasse erlaubt (in Abbildung 7 in der Spalte überprüfen [Go13]. Die Aufrufreihenfolge zur Laufzeit ist in der „Recht 5“ vorstellbar). Regel11 AutograderCore → AssignmentGrader → Submission Eine Lösung kann nun nicht sein, dem Submission-Schutzbereich (vgl. Abbildung 6). Mit zunehmender Aufruftiefe stehen geringere alle Rechte zu gewähren, die das Test Double benötigt. Min- Rechte zur Verfügung. destens das Beispiel in Abschnitt 3.4.2.5 spricht dagegen. Wäre der Aufruf der Methode h privilegiert, würden die Methoden h Recht 1 Recht 2 Recht 3 Recht 4 Recht 5 Komponente Aufrufstapel und i mit der Rechtemenge {2, 4, 5} ausgeführt. Leider hat der Autor des AssignmentGraders keine Möglichkeit, den Test Autograder- a Double-Aufruf privilegiert zu gestalten. Die Programmierschnitt- Code b stelle von mockito, wie wir sie in Abschnitt 2.4 kennen gelernt Assignment- c haben, ermöglicht keine privilegierten Test Doubles. Der eigent- d liche Methodenaufruf findet im Submission-Code statt, der nicht Grader e im Einflussbereich des AssignmentGrader-Autors steht. f Submission g Resultierende Schnittmenge: Legende: Aufruf: Methode: Recht: Abbildung 6: Aufrufstapel und resultierende Rechte (Beispiel) Recht 1 Recht 2 Recht 3 Recht 4 Recht 5 Komponente Aufrufstapel Autograder- a Abbildung 8: Proxy-Klasse für ein Test Double von Quadrat Code b Die vorgeschlagene Lösung besteht nun darin, eine Proxy12- c Assignment- i Klasse in der AssignmentGrader-Komponente zu erstellen, die ein d Grader e h Test Double umhüllt. Beispielhaft ist in Abbildung 8 das Quadrat- f Interface und das zugehörige, mit Mockito.mock erzeugte Test Submission g Double13 zu sehen. Die Proxy-Klasse besitzt genau die gleiche Schnittstelle wie das Resultierende Schnittmenge: Original (Quadrat) und eine dauerhafte Referenz zum Test Double Objekt. Die Implementierung der quadrat-Methode der Proxy- Legende Methode d. Test Doubles: Klasse besteht nun aus einem privilegierten Aufruf von Abbildung 7: Privilegierter Callback eines Test Doubles TestDouble.quadrat. Damit Code des Systembereichs Rechte (bspw. Einlesen von Font-Dateien zwecks Erzeugung einer Ausgabe) erhalten kann, 12 die aufrufender Anwendungsbereichs-Code nicht besitzt, gibt es http://docs.oracle.com/javase/7/docs/api/java/lang/reflect/Pro xy.html 11 13 Rückwärts gewandte Aufrufe von Methoden des Autograder- Der von mockito erzeugten Klasse haben wir hier für Darstel- Core aus dem AssignmentGrader heraus sind ebenfalls denkbar, lungszwecke einen Namen gegeben. In Wirklichkeit ist die sind jedoch hier nicht Gegenstand der Betrachtung. erstellte Klasse aus Benutzersicht anonym. Den wenigsten Autoren von AssignmentGradern wird die 5. Fazit Sicherheit des Autobewerters so wichtig sein, dass sie die Mühe Wählt man wie in Graja JUnit-Tests als Werkzeug zur auf sich nehmen und eine Klasse Proxy für jeden zu automatisierten Programmbewertung, ist der Einsatz einer doublenden Typ T programmieren wollen. Es handelt sich zudem Bibliothek zur Erzeugung von Test Doubles naheliegend. um höchst spezialisierten Code, der ein tiefes Verständnis von Studentischer Code und Test Doubles gehören verschiedenen Java Reflection und Generics erfordert. Schutzbereichen an. Test Doubles sind im Aufrufbaum Kinder des Die naheliegende Idee ist nun, die Erzeugung der Proxy-Objekte studentischen Codes, so dass tendenziell restriktive Rechte des in eine Bibliothek auszulagern, die dem AssignmentGrader- studentischen Codes an Test Doubles vererbt werden. Mock- Schutzbereich angehört. Wir stellen im folgenden Abschnitt kurz Bibliotheken benötigen für ihre Test Doubles jedoch Rechte von die Entwurfsideen einer neuen Bibliothek MockitoWrap als Hülle erheblichem Bedrohungspotential. Um den von der Lehrkraft um mockito vor, die sich um die Erzeugung von Proxy-Objekten geschriebenen Bewertungscode nicht mit sicherheitsspezifischen kümmert, welche Aufrufe an Test Doubles delegiert, wobei jeder Details (Proxy-Objekte mit in doPrivileged-Aufrufen gekapselten delegierte Aufruf in ein doPrivileged-Konstrukt „verpackt“ ist. Delegationen) zu „verschmutzen“, bietet sich die Verlagerung dieser Details in die Mock-Bibliothek oder in einen hierfür zu 4.3 Zentrale Entwurfsideen von Mockito- schreibenden Adapter an. Die Erstellung eines solchen Adapters Wrap kann durch Nutzung von Java Generics und der Java-Reflection- Die zentrale Operation (vgl. Abschnitt 2.4) bei der Nutzung von Bibliothek kompakt gelingen. mockito ist die generische Methode Mockito.mock(Class c)14. Sie liefert ein Test Double vom Basistyp T, für das alle Methoden 6. Literaturverzeichnis [Ed03] Edwards, S.: Using Test-Driven Development in the der Klasse T aufrufbar sind. Das Test Double wird im weiteren Classroom: Providing Students with Automatic, Verlauf von Methoden wie Mockito.when oder Mockito.verify Concrete Feedback on Performance. In Proc. Int’l Conf. verwendet. An dieser Art des Aufrufs von mockito soll sich durch Education and Information Systems: Technologies and die beschriebene Sicherheitsanforderung nichts ändern. Einzig der Applications (EISTA ’03), Aug. 2003. Name der Einstiegsklasse Mockito soll nun MockitoWrap heißen. [Go13] Gong, L.: JavaTM SE Platform Security Architecture. Die vollständige Beschreibung von MockitoWrap würde den http://docs.oracle.com/javase/7/docs/technotes/guides/ Rahmen dieses Aufsatzes sprengen. Wir nennen nur einige security/spec/security-spec.doc.html, Abruf 13.09.2013. grundlegende Entwurfsideen, die vermutlich in ähnlicher Form auf andere Mock-Frameworks übertragen werden können. [Ka13] Kaczanowski, T.: Practical Unit Testing with JUnit and MockitoWrap wird im Zuge der Erstellung neuer Programmier- Mockito. Verlag Tomasz Kaczanowski, 2013. aufgaben sukzessive an der Hochschule Hannover weiter [KSZ02] Krinke J, Störzer M, Zeller A, Web-basierte entwickelt. Programmierpraktika mit Praktomat, Softwaretechnik- Entwurfsidee 1: Sei Class c der Typ, für den ein Test Double Trends, Vol. 22, (3), October 2002. erstellt werden soll. Statt direkt Mockito.mock(c) aufzurufen, soll [Me07] Meszaros, G.: xUnit Test Patterns: Refactoring Test der Wrapper genutzt werden: MockitoWrap.mock(c). Der Wrapper Code. Addison-Wesley Longman, Amsterdam, 2007. delegiert den Aufruf an das Original (T td=Mockito.mock(c)) und erstellt dann ein Proxy-Objekt für das Test Double td. Das Proxy- [oV13] o. V.: OWASP Risk Rating Methodology. https://www. Objekt erhält als Konstruktorparameter ein Objekt einer neuen owasp.org/index.php?title=OWASP_Risk_Rating_Meth generischen Klasse MockProxyInvocationHandler, die von odology&oldid=158022, Abruf 13.09.2013. 15 InvocationHandler erbt. MockProxyInvocationHandler besitzt [SBG10] Striewe, M.; Balz, M.; Goedicke, M.: Enabling Graph als Instanzattribute Referenzen auf das Test Double td und dessen Transformations on Program Code, In Proceedings of Klasse c16, so dass stets vom Proxy-Objekt zum Test Double the Fourth International Workshop on Graph-Based navigiert werden kann. Tools (GraBaTs 2010), Enschede, Netherlands, 2010. Entwurfsidee 2: Die Methode MockProxyInvocationHandler. [SL05] Spillner, A.; Linz, T.: Basiswissen Softwaretest (3. invoke delegiert den Methodenaufruf innerhalb einer Privileged Auflage). dpunkt, Heidelberg, Germany, 2005 17 Action an das Test Double td. [St13] Stöcker, A., Becker, S., Garmann, R., Heine, F., Kleiner, Entwurfsidee 3: Für weitere Klassen der mockito-Bibliothek wer- C., Bott, O. J.: Evaluation automatisierter Programm- den nun (einfachere) Wrapper geschrieben werden. Bspw. besitzt bewertung bei der Vermittlung der Sprachen Java und OngoingStubbingWrap ein Instanzattribut vom Originaltyp SQL mit den Gradern „aSQLg“ und „Graja“ aus OngoingStubbing. Methodenaufrufe wie thenReturn werden an studentischer Perspektive. In Proceedings DeLFI, 2013. das Instanzattribut delegiert. Rückgabewerte werden wieder in [TE08] Thornton, M., Edwards, S. H., Tan, R. P., Pérez- Objekte der …Wrap-Klasse eingehüllt. Quiñones, M. A.: Supporting student-written tests of GUI programs. In Proceedings of the 39th SIGCSE 14 http://docs.mockito.googlecode.com/hg/latest/index.html?org/ Technical Symposium on Computer Science Education. mockito/Mockito.html ACM Press, New York, NY, 2008, pp. 537-541. 15 http://docs.oracle.com/javase/7/docs/api/java/lang/reflect/Invo cationHandler.html 16 Type erasure bei Java Generics macht den Einsatz dieses zweitgenannten Instanzattributs notwendig. 17 http://docs.oracle.com/javase/7/docs/api/java/security/Privi legedAction.html