Nets brugte 3 døgn på at tilføje 2 linjer kode til NemID
Da Oracle tirsdag aften den 15. oktober rullede den nye version af Java Runtime Environment ud, Java 7 update 45, som en af de helt faste, kvartalsvise opdateringer, førte det til store problemer i det digitale Danmark. NemID-appletten kunne som bekendt ikke køre under den nye Java-udgave, og først fredag aften kunne NemID igen bruges hos dem, der havde fulgt almindelig sikkerhedspraksis og opdateret Java.
Java-kyndige spekulationer om problemet kredsede hurtigt om en ny sikkerhedsfunktion i Java, der kom med update 45, og Version2 har nu fået bekræftet, at det var denne funktion, der gav hovedbrud hos Nets. Det er dog ikke sket via de officielle kanaler, da Nets stadig ikke ønsker at udtale sig om baggrunden for Java-problemerne.
Den nye funktion hedder Caller-Allowable-Codebase Attribute. Som en ekstra sikkerhedsforanstaltning skal en applet, som den Nets bruger til NemID, definere hvilke domæner, appletten må hente kode ned fra. Det skal defineres i et manifest, som blot skal opdateres med en liste over tilladte hosts.
Datalogen Christian Panton har i et blogindlæg. set nærmere på den løsning, der blev rullet ud, Efter en udpakning af den obfuskerede applet har han fundet ganske få ændringer, som ganske rigtigt har med det manifest at gøre. Hvis Java ikke kan finde det krævede manifest, bliver der nu i NemID henvist til nye metaoplysninger i manifestet, viser Christian Pantons analyse:
if (manifest == null){ manifest = new URL(basePath + "META-INF/MANIFEST.MF"); }
Men han understreger, at man ikke ud fra koden præcist kan sige, hvilke problemer Nets måtte slås med.
»Måske har ændringer i manifestet fået noget andet til at gå galt. Vi kender ikke kausaliteten i det,« siger Christian Panton til Version2.
Ifølge hans dissekering af Nets’ kode har NemID-appletten brugt reflections og brugt et internt API i Java, hvilket førte til problemerne.
»At bruge reflections, hvor man kigger på det udefra og hopper lidt tilfældigt rundt i koden, er som regel ret dårlig stil. Måske har der været en grund til det, det ved vi ikke, men i min verden er det ikke så godt. Og så lader det til, at de har tilgået et internt Java-API, og det synes jeg er problematisk,« siger Christian Panton, der understreger, at han ikke er ekspert i Java, men mest af alt har deobfuskeret koden og lagt den op for at få åbnet en diskussion.
»Spørgsmålet er, om det virkeligt skal tage tre dage. Jeg ved det ikke - men nu kan andre så se på det. Løsningen var i øvrigt klar 24 timer før, den blev rullet ud generelt. Jeg ved ikke, hvorfor det tog dem så lang tid. Så vidt jeg ved, kan Facebook rulle en ny opdatering ud på et par timer,« siger Christian Panton.
Han foreløbige konklusion - indtil Nets kommer med en officiel forklaring - er, at det var en lille fejl, som væltede en afgørende samfundsfunktion.
»Det er kritisk, at en ændring i Java kan få så stor effekt. Det er ikke godt for en vigtig infrastruktur for hele Danmark, når en lille ændring betyder, at det hele falder ned,« siger han.
Det store spørgsmål er også, om den nye funktion i Java, som gav problemer, var med i den pre-release, som Oracle sender ud. Var den det, burde Nets have opdaget problemet med det samme, lyder en vurdering fra en anden Java-kyndig, der kender til arbejdsprocessen med NemID.
Omvendt kan det også have været Oracle, der ikke har været gode nok til at fortælle om den nye sikkerhedsfunktion i god nok tid, lyder vurderingen.
Nets ønsker foreløbigt ikke at udtale sig om den tekniske baggrund for problemerne og om firmaets tests af den nye Java 7 update 45, før hele forløbet er analyseret. Og når det er sket, er det også uvist, om Nets overhovedet vil fortælle noget, oplyser pressechef Søren Winge til Version2.
Sådan ser de to linjer kode, der er blevet tilføjet, ud i sammenhæng. Kilde: Christian Pantons analyse af den tidligere og den nye version af NemID-appletten.
public void Foofieface() { // I love that name (from codeobfuscator) // lets find the basePath int lenPackage = 0; if (getClass().getPackage() != null) lenPackage = getClass().getPackage().getName().length(); String className = getClass().getName().substring(lenPackage > 0 ? lenPackage + 1 : 0) + ".class"; // Someclass.class URL classAbsolutePath = getClass().getResource(className); // file://some/path/package/Someclass.class String classFilePath = getClass().getName().replace('.', File.separatorChar) + ".class"; // package/Someclass.class String basePath = classAbsolutePath.toString().substring(0, (classAbsolutePath.toString().length() - classFilePath.length())); Object cl = Bootapplet.class.getClassLoader(); try { // Use reflection on classLoader Method findResource = cl.getClass().getMethod("findResource", new Class[] { Bootapplet.class }); findResource.setAccessible(true); // Returns null under 7u45 URL manifest = (URL)findResource.invoke(cl, new Object[] { "META-INF/MANIFEST.MF" }); /* BEGIN FIX (diff in decompiled source) */ if (manifest == null){ manifest = new URL(basePath + "META-INF/MANIFEST.MF"); } /* END FIX */ // Never reached if (manifest == null){ throw new SecurityException("Missing manifest in signed applet"); } String manifestBasePath = manifest.toString().substring(0, manifest.toString().length() - 20) // "META-INF/MANIFEST.MF".length = 20 // Never reached if (!(manifestBasePath).equals(basePath)){ throw new SecurityException("Manifest file loaded from insecure resource : " + manifestBasePath); } InputStream manifestStream = manifest.openConnection().getInputStream(); Manifest mf = new Manifest(manifestStream); } catch (Exception ex) { throw new SecurityException("Failed to load manifest : " + ex.getMessage()); } // continue to load manifest and check for secure sources // .... }

...men det er dyrt at lave god journalistik. Derfor beder vi dig overveje at tegne abonnement på Version2.
Digitaliseringen buldrer derudaf, og it-folkene tegner fremtidens Danmark. Derfor er det vigtigere end nogensinde med et kvalificeret bud på, hvordan it bedst kan være med til at udvikle det danske samfund og erhvervsliv.
Og der har aldrig været mere akut brug for en kritisk vagthund, der råber op, når der tages forkerte it-beslutninger.
Den rolle har Version2 indtaget siden 2006 - og det bliver vi ved med.