Nets brugte 3 døgn på at tilføje 2 linjer kode til NemID

En ny sikkerhedsfunktion i Java slog benene væk under NemID i tre dage. Spørgsmålet er nu, om det er sjusk hos Nets eller dårligt varsel fra Oracle, der er forklaringen.

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.

Læs også: Java-opdatering blokerer NemID

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) <em>/
        if (manifest == null){
            manifest = new URL(basePath + "META-INF/MANIFEST.MF");
        }
        /</em> 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
    // ....
 
}

Tips og korrekturforslag til denne historie sendes til tip@version2.dk
Kommentarer (29)
sortSortér kommentarer
  • Ældste først
  • Nyeste først
  • Bedste først
David Rechnagel Udsen

Folk på Version 2 burde nikke genkendende til scenariet om at finde en fejl kan tage meget lang tid, mens selve rettelsen tager ingen tid.

Men nu var det ret klart at problemet var et manifest-problem (givet hvad Java selv sagde), så fejlen burde være relativ let at finde. Så på det punkt kan man undre sig over det tog lang tid.

  • 35
  • 1
Søren Jensen

De har sikkert også brugt tid på at teste om der skulle være andre ændringer i v45 som kunne skabe problemer.

Er det egentlig tilladt at dekompilere Nemid-applet'en?

  • 9
  • 0
Christian Dahl

Er enig i at Nets nok godt kunne have håndteret det her bedre.
Synes også Version godt kunne stramme lidt op... De her EB inspireret overskrifter hører ikke til et seriøst nyhedssite som det her. Jeg er selv udvikler og jeg kender udmærket til hvordan fejlsøgning kan tage meget lang tid og sagtens kan ende ud i at det er meget få linier koder der skal skrives.

  • 21
  • 0
Casper Bang

Er det egentlig tilladt at dekompilere Nemid-applet'en?

Hvorfor skulle det ikke være dét? Det er efterhånden åbenlyst at DanID helst så at folk betragtede deres kode som en magisk sort boks, men det er klassisk security through obscurity, der i virkeligheden efterlader et lidet flatterende indtryk af dem bl.a. andre professionelle. Jeg vil klassificere NemId's problemer som en konsekvens af accedential complexity og den JavaScript løsning kan kun komme for langsomt.

  • 14
  • 1
Martin Eskildsen

Jeg melder mig hermed ind i koret af stemmer, der igen og igen påpeger at Version2 burde være for gode til den slags overskrifter. Det er jo ikke fordi denne NemID fiasko mangler opmærksomhed i forvejen, så selv med noget mere dæmpet burde I kunne få jeres clicks ind.

  • 19
  • 4
Adam Tulinius

En bruger jeg kender fil netbank tilbage i går, men ikke dimsen fra Statens Arkiver.
Bare et gæt, men det kunne tyde på den nye funktionalitet ikke er særlig godt beskrevet.

Jeg finder det mere sandsynligt at SAs slægtsforsknings thingy bare ikke bliver aktivt udviklet og testet, og at Nets er inkompetente (sidstnævnte er jo nærmest fakta), end at Oracle ikke har beskrevet ændringen ordentligt.

  • 9
  • 0
Morten Klitgaard

Kunne det evt. tænkes at efterårsferien har spillet lidt ind i forsinkelsen? Det tager jo alligevel lidt tid at få folk kaldt hjem fra ferie...og så er det nemmere blot at sige at problemet er "komplekst" frem for at indrømme at alle udviklere er på ferie og det derfor tager lidt tid at få fejlen rettet.

  • 3
  • 1
Christian Christiansen

Nu er det jo også sådan i større virksomheder at det sjældent er én udvikler der sidder med beslutningerne.. Danid har jo nok faste procedure mht. debug, test og release.. Og typisk skal det jo igennem flere bureaukratiske instanser... Når det så samtidig er efterårsferie som Morten påpeger så kan det jo sagtens være dét som har været hovedårsagen til de 3 dages ventetid...

Dermed ikke sagt et Nets burde have et nødberedskab af en slags når nu netop NemID er så vital for Danmarks IT´ infrastruktur

  • 10
  • 0
Henrik Dalsager

Er det ikke ca. den normale fejlsøgnings til løsnings ratio, når man ingen idé har om hvad der er galt?

Jeg har ihvertfald personligt ofte den oplevelse, at selvom man udfra symptomerne finder ud af hvad der sådan ca. må være galt meget hurtigt, kan det tage lang tid at få afklaret hvad der helt nøjagtigt sker, og hvor, og hvor mange steder problemet er.

Dertil kommer så diskussionen af hvad den bedste løsning er.

Når så man er færdig med "problem isolerings fasen" tager det typisk 10 sekunder at skrive koden, og lidt tid at teste den.

Det er typisk også der hvor chefen hænger i luften ved ens skærm, så man har svært ved at koncentrere sig.

  • 14
  • 1
Adam Tulinius

Er det ikke ca. den normale fejlsøgnings til løsnings ratio, når man ingen idé har om hvad der er galt?

Nets burde vide hvad der var galt på forhånd. Det gjorde de ikke. Næstbedst burde de kunne finde fejlen ret hurtigt, der var i hvert fald flere på V2 der inden for 24 timer havde gisnet om det mest sandsynlige problem, og de endte da også med at få ret -- uden kendskab til koden bag NemID.

  • 3
  • 6
Sune Foldager

Nets burde vide hvad der var galt på forhånd. Det gjorde de ikke. Næstbedst burde de kunne finde fejlen ret hurtigt, der var i hvert fald flere på V2 der inden for 24 timer havde gisnet om det mest sandsynlige problem, og de endte da også med at få ret -- uden kendskab til koden bag NemID.

Det er jo nemt at være bagklog. Folk på version2 havde gættet på at det var noget med manifestet og så videre, men det har de nok også hurtigt vidst hos DanID. Derfra og så til at finde ud af at et privat API som kaldes via reflection er ændret eller har ændret opførsel, kan der jo sagtens være lidt vej.

Det er jo generelt en dårlig ide at kalde private APIer selvom man (med reflection) kan, men det forekommer en del. Jeg arbejder hos en mellemstor .NET-shop, og vi har også forekomster af den slags et par steder. Det kan være fordi platformudvikleren (hos os, Microsoft) ikke har forudset alle brugsscenarier, eller det kan være af hensyn til performance eller andet.

  • 9
  • 2
Søren Jensen

Nej, når du har en så forretningkritisk applikation så har man etableret et nødberedskab. Også juleaften og efterårsferien.

Det har de da sikkert også, men det er jo ikke sikkert at de folk som var på vagt havde den fornødne viden netop omkring dette problem.
Set i bakspejlet så er problemet simpelt men når man står med problemet så ser verden helt anderledes ud - specielt fordi chefen og pressen ånder en i nakken ;)

  • 1
  • 4
Daniel Udsen

Rodproblemet her er vel at nemid pr design er inkompatibel med god sikkerheds praksis, og gængse eu standarder for Signaturløsninger.

Problemet kan koges ned til at nemID kræver at fuldt udstillet API der lader tilfældige sider bryde ud af en sandbox på en måde der aldrig vil blive 110% sikker. Oracle forsøger så løbende sikre Java's "trusted mode" ved at indføre begrænsninger på hvor stor kontrol en applet kan få over brugeren's, hvilket så kolidere med nemID designprincip om at nemID appletten skal have fuld adgang til alle system API'er.

Havde staten fulgt best practice og overholdt EU's standarder fra staten havde man aldrig haft det her problem men det blev politisk vedtaget, at det ikke var den danske måde at drive it på at bestille hvad IT branchen betegner som godt håndværk.

  • 6
  • 3
Kristian Sørensen

Kommentarer er ikke med i .class filerne

Så de pågældende kommentarer stammer fra de-compileren, og er et resultat af dennes automatiske kode analyse.

Eksempler:
"// Never reached"
"// Use reflection on classLoader"

Navne såsom "Foofieface" stammer fra en obfuscater som koden er kørt igennem før den er lagt på nettet. Den omdøber procedure og variabel navne til volapyk for at besværliggøre kode analyse efter dekompilering, men siger intet om hvad navnet er i den kildekode version som nets arbejder i.

Bemærk også variabel navnene. De bærer præg af at være dannet ved automatiseret kode analyse, snarere end at være valgt af et menneske for forståelighedens skyld.

  • 5
  • 0
Kristian Sørensen

Bemærk at hvis nemid havde holdt sig indenfor den normale applet sandbox, og afholdt sig fra at udnytte de muligheder for læse/skrive adgang til lokal disk mv. som en signed applet giver, så var dette problem ikke opstået.

Havde nemid ikke følt et behov for at se og snage på folks maskiner, så havde de ikke behøvet at benytte reflection, loade classer explicit pr. navn og lignende tricks og dermed havde befolkningen været dette nedbrud foruden.

Giver denne seen og snagen nogen fordele for borgeren, som retfærdiggør den øgede risiko for fejl og nedbrud?

  • 11
  • 0
Casper Bang

Så de pågældende kommentarer stammer fra de-compileren, og er et resultat af dennes automatiske kode analyse.

Nope, det må være Christians kommentar. De-compileren kan ikke analysere sig frem til at disse kode-blokke, afh. af ekstern input, ikke nås - havde det været tilfældet, havde javac iøvrigt nægtet at compile koden og smidt en "Code unreachable" fejl.

  • 0
  • 2
Kristian Sørensen

Nope, det må være Christians kommentar. De-compileren kan ikke analysere sig frem til at disse kode-blokke, afh. af ekstern input, ikke nås - havde det været tilfældet, havde javac iøvrigt nægtet at compile koden og smidt en "Code unreachable" fejl.

Det kan godt være Christians håndskrevne kommentarer. Det kan jeg ikke vide med sikkerhed.

Men der kan nu godt være "unreachable code" i en .class fil, og jeg har da oplevet dekompilere der spottede det samt andre fejl og mangler "efter bedste evne".

Dels er der mange andre måder at generere .class filer på end via javac og de er ikke nødvendigvis perfekte.

Men i det konkrete tilfælde tænkte jeg mere på obfuscatoren.

Nogle Obfuscatere efter-behandler .class filerne, med henblik på at få de-compilere til at opgive at de-compile. Dette gøres ved at forurene .class filerne på en måde som ikke påvirker den normale afvikling, men som får de-compilere til at fejle og opgive at de-compile. Der kører en lille stille krig imellem de-compiler producenterne og obfuscator producenterne om dette.

Motivet for at anvende den type obfuscatorer er at undgå analyser som den nærværende ;-)

  • 5
  • 0
Log ind eller Opret konto for at kommentere