Jeg er både interesseret i at udforske API’er og i at læse bøger. Jeg har fx tidligere vist, hvordan jeg ved hjælp af en Android-emulator og programmet Charles fandt en løsning til at få videresendt E-boksbeskeder til min e-mail.
Og så skete der det, at jeg fik et prøveabonnement til Saxo Premium.
Derfor gav jeg mig i kast med at udforske boghandelen Saxos app til streaming af bøger og opdagede nogle sikkerhedsproblemer.
Jeg fandt ud af, at enhver med lidt teknisk snilde kunne skaffe sig adgang til Saxos ebøger, uden først at købe et streaming-abonnement.
Efter først at have kontaktet Saxo anonymt for at blive forsikret om, at de ikke ville melde mig til politiet, så længe jeg ikke havde udnyttet sikkerhedshullerne, fik jeg indrapporteret problemerne.
Saxo var både flinke og professionelle i dialogen, og nu har de lanceret en mere sikker app. Derfor vil og kan jeg nu fortælle om, hvordan jeg undersøgte Saxos app, og hvad jeg opdagede.
Om streaming og at sikre sig mod kopiering af data
Men først en sidebemærkning: Det er meget svært at give midlertidigt adgang til data (bøger, film, musik), som Saxo, Netflix, Spotify osv., gør, og være helt sikker på, at adgangen altid og i alle tilfælde kun er midlertidig.
Hvis noget kan ses på en skærm eller lyttes til på højttalere, skal der meget til at forhindre ihærdige brugere, (der måske endda er villige til at bryde ophavsretsloven – gisp!), i at få gemt en kopi af materialet.
Spørgsmålet er mere, hvor svært og tidskrævende man gør det.
Problemet hos Saxo var altså ikke, efter min mening, at en abonnement kunne vælge at misbruge deres streamingabonnement til at tage kopier af ebøger. Problemet var, at selv en ikke-abonnement kunne gøre det.
Om at undersøge hvordan apps virker og opdage sikkerhedshuller
Hvis du tænker på selv at give dig i kast med at undersøge apps, API’er og eventuelle sikkerhedshuller, er det vigtigt, du har hjertet på det rette sted.
Som privatperson er det vigtigt, at:
- Du ikke udnytter en utilsigtet adgang til data. Straffeloven siger, du ikke uberettiget må skaffe dig adgang til andres data. Ophavsretsloven siger, du ikke må dele ophavsretsbeskyttede værker med andre. Du kan også (måske uden selv at have opdaget det) have accepteret nogle vilkår for brug af en app, som ejeren af appen måske kan bruge til at anlægge en sag mod dig, som de måske/måske ikke kan vinde.
- Du hurtigst muligt giver virksomheden besked om sikkerhedshullerne, så den kan rette dem.
- Du ikke deler din viden om sikkerhedshuller med andre, fx dine venner eller medierne. Det ville medføre, at nogle kunne udnytte hullerne og begå ulovligheder.
Læs IT-Branchens glimrende vejledning til anmeldere af sikkerhedsbrister.
Til gengæld for din ædelhed bør virksomheden:
- Behandle henvendelsen fra dig fortroligt
- Handle på henvendelsen og løse sikkerhedsproblemerne inden for rimelig tid
- Undlade at melde dig til politiet, hvis du (anmelderen) har handlet i overensstemmelse med kodekset
Du kan ikke være sikker på, at virksomheden handler ædelt. Derfor valgte jeg selv at kontakte Saxo anonymt, for at høre om deres ædelhed, inden jeg fortalte om det sikkerhedshul, jeg havde opdaget.
Forberedelsesfasen
Android-emulator
Det første man skal bruge for at kunne undersøge mobilapps til Android er en emulator, så apps kan køre på ens PC og man har mulighed for at overvåge trafikken.
Jeg bruger en emulator, der hedder Nox. Den er mest lavet til at kunne spille spil og er fyldt med reklamer og sikkert også overvågning. Men: Nox gør det let at hente, installere og eksportere apps, og at begynde at overvåge trafikken til og fra dem.
For at overvåge trafikken på moderne Android-versioner er det nødvendigt først at pille lidt ved den app, hvis trafik man vil overvåge.
(Nogle apps med højere sikkerhedsniveau, bruger noget der hedder “SSL pinning” til at forhindre trafikovervågning. Det gør det væsentligt sværere at overvåge trafikken, end hvad jeg beskriver her.)
Rette i appen for at tillade traffikovervågning
I Nox installerede jeg Saxos app og eksporterede appen som apk-fil.

Derefter brugte jeg værktøjet Apktool til at dekompilere appen. Værktøjet er gratis, kræver Java og er ret nemt at bruge.

For at kunne overvåge trafikken skal appen tillade, at jeg bruger andre SSL-certifikater end dem, der kommer med Android.
I mappen res/xml oprettede jeg filen network_security_config.xml (nogle apps har den allerede) og satte det her indhold ind. Det fortæller, at jeg både stoler på systemcertifikater og brugerinstallerede certifikater:
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<base-config>
<trust-anchors>
<certificates src="system" />
<certificates src="user" />
</trust-anchors>
</base-config>
</network-security-config>
Derefter åbnede jeg AndroidManifest.xml og indsatte stien på den nye fil i tagget “application”.
Før:
<application android:allowBackup="false" android:appComponentFactory="androidx.core.app.CoreComponentFactory" android:hardwareAccelerated="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:largeHeap="true" android:name="com.saxo.read.saxoread.application.SaxoReadApplication" android:resizeableActivity="false" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/SaxoTheme">
Efter:
<application android:networkSecurityConfig="@xml/network_security_config" android:allowBackup="false" android:appComponentFactory="androidx.core.app.CoreComponentFactory" android:hardwareAccelerated="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:largeHeap="true" android:name="com.saxo.read.saxoread.application.SaxoReadApplication" android:resizeableActivity="false" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/SaxoTheme">
Med disse små rettelser på plads, brugte jeg Apktool til at pakke en ny apk-fil og signerede filen med et værktøj, der hedder Uber Apk Signer.
Min modificerede app var klar, og jeg trak-og-slap den over i Nox for at installere den.
Overvågning af app-trafik
Jeg brugte programmet Charles til at overvåge trafikken fra Saxos app. Kort fortalt installerer man Charles’ SSL-certifikat og sætter Nox op til at bruge Charles som proxy for internettrafik.
Hul igennem
Hvis alt er gået godt, kan det se sådan her ud, når Charles trafikovervåger. Her er fx oprettelsen af en bruger og de første par handlinger i Saxos app:

Undersøgelsesfasen
Når først trafikken til og fra en app kan overvåges, er det bare at begynde at bruge app’en for at finde ud af, hvordan dens API virker.
Det jeg fandt ud af, var et problem ved Saxos app, var:
- Når man søger med Saxos app, returneres en række id-numre på bøger
- Søgning i appen kræver ikke en Premium-konto, alle kan oprette en konto og søge for at se udvalget af bøger
- Download-adressen på en bog til offline-læsning kunne regnes ud alene ud fra en bogs id-nummer
- Downloadede bøger var krypterede, men:
- Appens nøgle til at dekryptere downloadede bøger, så de kunne læses offline, var meget nem at finde
Problemet betød, at brugere uden abonnement kunne få adgang til bøger uden abonnement.
Brugere med abonnement kunne få adgang til bøger uden at deres download blev registreret gennem Saxos API og dermed, formoder jeg, uden at Saxo kunne honorere bogens forlag og i sidste ende bogens forfatter.
Muligvis – det har jeg ikke testet – gjorde hullet også, at eventuelle check, som Saxo har af, hvor mange bøger en bruger kan hente, blev sat ud af spillet.
I de næste afsnit prøver jeg at tage dig med gennem undersøgelsesfasen.
Download af bøger til offline-læsning
Når jeg downloade en bog hos Saxo, kunne jeg se, at der blev spurgt efter en fil herfra:

Når jeg forsøgte at tilgå adressen i en browser, kunne jeg downloade filen. Men, som adressen afslører, er filerne krypteret (“encrypted-base-files”).
Nøglesammenfald mellem søgeresultater og download-adresse
Så opdagede jeg, at en bogs id gik igen i download-adressen. Her har jeg klikket mig ind på den novellesamling af Jens Blendstrup, som jeg downloadede til offlinebrug. Læg mærke til id:

Id:
a3519df0-182a-4f77-90f7-52a82c5bacf9/user/ee3b4be0-fcab-48b8-944f-e2bffe372f45
Bliver til download-url:
https://readcontentprdcryptbase.blob.core.windows.net/encrypted-base-files/a3/51/9d/f0/a3519df0-182a-4f77-90f7-52a82c5bacf9/a3519df0-182a-4f77-90f7-52a82c5bacf9
Mapperne “a3“, “51“, “9d” og “F0” i stien kommer fra de første otte tegn i id’et: a3519df0.
Altså: Kender du id på en bog, kender du også downloadadressen på den krypterede bog!
Søgeresultater tilgængelige for alle
Jeg fandt også ud af, at søgning i appen, som er åben for både premium-medlemmer og ikke-betalende brugere på appen, udstiller bøgers id. Her er et eksempel, hvor jeg leder efter Puk Damsgårds Arabica:

Næsten alle kan downloade alt!
Når søgningen udstiller bøgers id, og download-adressen til bøger kan findes alene ud fra en bogs id, kunne en ondsindet bruger med god tid, eller med evnen til at programmere en robot, have:
- Hentet alle ISBN-numre på alle bøger i Saxos streaming-katalog
- Søgt på alle ISBN-numrene ved hjælp af Saxos app-api og fundet bøgernes id
- Downloadet alle bøgerne i kataloget
Det kan være, at Saxo havde implementeret noget, der fx blokerede en bruger, der foretog rigtig mange søgninger, eller downloadede rigtigt meget fra downloadserveren. Hvis de havde det, havde det gjort øvelsen med at kopiere hele kataloget lidt sværere. Men kun en lille smule.
Sidste brik: Dekryptering af downloadede bøger
Efter at have fundet muligheden for at downloade krypterede bøger hos Saxo uden at være abonnent, ledte jeg efter en krypteringsnøgle.
Når Saxos app kan læse de downloadede, krypterede bøger, må krypteringsnøglen jo befinde sig i – eller blive leveret til – Saxos app på en eller anden måde.
Jeg fandt nøglen i mine dekompilerede filer fra appen på min harddisk efter at have lavet forskellige søgninger i filerne, som jeg dårligt nok kan huske og heller ikke vil afsløre. Nøglen viste sig at ligge meget dårligt skjult, og med en lille bid Python-kode og modulet Cryptography skrev jeg et lille program, der kunne dekryptere bøgerne:
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.backends import default_backend
filename = "" # Filnavn på krypteret bog
key = "" # Fra Saxos app
iv = "" # Fra Saxos app
encoded_key = key.encode('utf-8')
encoded_iv = iv.encode('utf-8')
backend = default_backend()
cipher = Cipher(algorithms.AES(encoded_key), modes.CBC(encoded_iv), backend=backend)
with open(filename, "rb") as encrypted_book:
encrypted = encrypted_book.read()
decryptor = cipher.decryptor()
decrypted = decryptor.update(encrypted) + decryptor.finalize()
with open(filename + '.epub', "wb") as fout:
fout.write(decrypted)
Saxos rettelser
Efter at Saxo har opdateret deres app, har jeg genbesøgt appen. Jeg kan se, at:
- Krypteringsnøglen til Saxos ebøger er blevet skjult en hel del bedre end tidligere.
- Det er ikke længere nok at have internetadressen på en bog for at downloade den. For at brugeren kan downloade en bog, genererer appen nu en unik nøgle per bog, som downloadserveren vil have for at sende en bog tilbage.
Den gamle version af appen tillod en bruger at springe det trin over, hvor Saxo registererer, at en bog er blevet hentet. I den nye er det kun muligt at downloade en bog, hvis man inden da har spurgt API’et om downloadadressen:

Downloadadresserne på bøger har fået nogle ekstra parametre på, bl.a. en unik “signatur” (“sig”), som API’et returnerer for hver bog, brugeren downloader. Jeg har censureret nogle få bytes her:

Derudover har Saxo, har de fortalt mig, lavet andre sikkerhedsopstramninger bag kulisserne.
Skønt!
Hvad betyder ændringerne i Saxos app?
Ændringerne betyder, at ikke-betalende brugere af Saxos app, så vidt jeg kan se, nu er effektivt afskåret fra at kunne tilgå bøger.
Betalende brugere har ikke længere mulighed for at downloade bøger, uden at Saxo kan registrere det og sørge for passende honorering af forfatter og forlag.
Tidsforløb og Saxos kommentarer
Jeg gjorde opmærksom på sikkerhedsproblemet den 22. marts 2021. Jeg kontaktede først Saxos kundeservice den 12. marts og opdagede, så vidt jeg husker, problemet den 11. marts. Saxos opdaterede app blev rullet ud den 17. maj 2021.
Jeg har slettet de bøger, jeg selv har downloadet og dekrypteret i forbindelse med undersøgelsen af Saxos app.
Saxo har haft mulighed for at foreslå rettelser og kommentere dette blogindlæg.
Saxo foreslog at gøre ekstra opmærksom på lovgivningen omkring at få uberettiget adgang til og dele data. Det synes jeg var en god idé, så det har jeg gjort i afsnittet om at undersøge hvordan apps virker og at opdage sikkerhedshuller.
De foreslog også at gøre opmærksom på, at det at dekompilere apps, ændre dem og bygge dem igen, efter deres mening er en juridisk gråzone. Her har din hensigt med at undersøge en app betydning: Hvis du blot er ude på at undersøge, hvordan ting virker, kender jeg ikke noget lovgivning, der siger, at du gør noget forkert (hvis du gør, vil jeg gerne høre om det). Hvis du er ude på at få uberettiget adgang til data eller ophavsretsbeskyttet materiale er det en anden sag – så er du ude på at bryde loven.