Secure by Design - Hoofdstuk 10

Ingediend door Dirk Hornstra op 05-feb-2021 22:23

In januari 2020 zijn we gestart met hoofdstuk 1 (link), in februari met hoofdstuk 2 (link), in april met hoofdstuk 3 (link), in mei met hoofdstuk 4 (link), in juni met hoofdstuk 5 (link), in juli met hoofdstuk 6 (link), in augustus hoofdstuk 7 (link), in september hoofdstuk 8 (link), in november hoofdstuk 9 (link) en nu wordt het tijd voor het 10e hoofdstuk. Nu was eigenlijk december 2020, maar omdat die datum in de kerstperiode viel is deze verschoven naar januari. Vervolgens zaten er 53 weken in 2020 en had ik erop gerekend dat er in januari een week later vergaderd zou worden, daardoor schuift deze door naar februari 2021. Zelf ook het hoofdstuk nog maar een keer doorgelezen ;)

De Timo-samenvatting

Thema van dit hoofdstuk is dat je over je software nadenkt alsof het een cloud-oplossing is. Het hoeft nog geen cloud-oplossing te zijn, maar je moet het zo bouwen dat het bij wijze van spreken morgen in de cloud zou kunnen draaien en je dus zonder al teveel problemen extra server kunt bijpluggen om load op te vangen. De punten die benoemt worden kun je hierna wel lezen. Één van de punten die hier benoemd worden is dat in je log-gegevens geen gevoelige data geplaatst moet worden. Daar heeft Jeldert een tijd geleden een "goede actie" in doorgevoerd. Wat hier ook benoemt wordt is het "vasthouden van state". We zien (volgens mij) nog vaak de software als een groot geheel van functies, waarbij het eigenlijk losse onderdelen zouden moeten zijn, waardoor je de schaalbaarheid vergroot. In het orderproces wordt aan het einde een bericht naar het ERP gestuurd en de mail naar de klant afgehandeld. Op dat moment heb je de "ordergegevens" in je sessie o.i.d. Maar als dat weg zou vallen, kun je deze essentiële acties niet (meer) uitvoeren. En ik ben voorstander van de 3-R theorie: rotate, repave, repair. Rotate: je hebt ergens een secret. Maar eigenlijk zou je die 1x in de zoveel tijd moeten vervangen/bijwerken. Want als die maar lang genoeg gelijk blijft, dan komt er een moment dat iemand de juiste waarde raadt. Repave is het overschrijven van de data met je eigen data, zodat je zeker weet dat er geen "corrupte" data blijft staan. En repair, het zo snel mogelijk doorvoeren van patches (of updates op bijvoorbeeld nuget-packages) is natuurlijk hoe het zou moeten werken.

De titel van hoofdstuk 10 is "Benefits of Cloud Thinking".

Door het toepassen van het "cloud concept" maak je volgens het boek je applicatie een stuk veiliger. Uiteindelijk komen we uit bij de 3 R-en van beveiliging, rotate, repave en repair.

Twee concepten: de twelve-factor app en cloud-native concepts

Door deze 2 concepten te combineren kun je op een makkelijke manier gebruik maken van bepaalde cloud-implementaties. De 12 factor app is een concept wat bedacht is door de mensen van de cloud-omgeving "Heroku", het is een methodologie om te bouwen voor "Software as a Service". De 12 factoren worden hier benoemd: link en is ook hier in Github te vinden: link.

I. Codebase
één codebase, bijgehouden in versiebeheer met veel deployments.

II. Dependencies
Declareer afhankelijkheden expliciet en isoleer ze.

III. Config
Sla configuratie op in de omgeving.

IV. Backing services
Behandel ondersteunende services als gekoppelde bronnen.

V. Build, release, run
Maak een strikte scheiding tussen build/bouw en uitvoer fases.

VI. Processes
Laat de applicatie draaien als één of meer processen zonder "state"

VII. Port binding
Exporteer services via gekoppelde poorten

VIII. Concurrency
Gebruik het process model om op te kunnen schalen.

IX. Disposability
Maximaliseer de robuustheid van de applicatie door snel starten en netjes afsluiten.

X. Dev/prod parity
Houdt development, staging/test en productie zoveel mogelijk gelijk.

XI. Logs
Behandel logs als event streams.

XII. Admin processes
Admin- of beheertaken moeten als een proces draaien op de build.

Met deze onderdelen zou je een applicatie moeten kunnen bouwen die het in de cloud goed doet. Maar daarmee waren we er nog niet, dus kwam er nog een concept bij "cloud-native". Kevin Hoffman heeft het als volgt uitgelegd: A cloud-native application is an application that has been designed and implemented to run on a Platform-as-a-Service installation and to embrace horizontal elastic scaling. We gaan vervolgens enkele items behandelen;

Storing configuration in the environment

Veel applicaties hebben bepaalde instellingen nodig. Maar soms zit in die configuratie "gevoelige data", een public key, token. In de cloud wordt daarom vaak aangeraden om configuratie extern op te slaan omdat het vaak naar verschillende omgevingen overgezet moet worden (dev/test/prod).

We zien het voorbeeld van database-connectie-gegevens opslaan in code. Dat doen we (gelukkig) allang niet meer. Het volgende voorbeeld toont het opslaan van de database-gegevens in resource-bestanden (voorbeeld is een .YAML bestand). Bijkomend nadeel is dat als iemand toegang tot de server heeft het bestand kan lezen... En daardoor heb je geen "audit-trail", want wie heeft de gegevens geraadpleegd? We weten het niet... Je kunt wel data encrypten, maar je moet dan ook ergens een decrypt-key hebben, het kip-en-het-ei-probleem.

Het boek komt dan met het opslaan van de configuratie in de omgeving waar de applicatie draait (environment). Een veel gebruikte methode is dat gegevens in omgevings-variabelen opgeslagen worden (bijvoorbeeld env-variabele in UNIX).

Audit Trail

Niet iedereen mag bij de omgevingsvariabelen komen, dus daar zit een deel van het audit-trail. De developer is er niet meer verantwoordelijk voor.

Sharing Secrets

De omgeving-variabelen kunnen soms "gedumpt" worden. Dus als jouw token als plain-text daarin staat, kun je een data-lek hebben en heb je dus een probleem.

Decryption

Maar je houdt dus nog het probleem waar je de decryptie-sleutel gaat opslaan. Conclusie, hiermee zou duidelijk moeten zijn waarom je per omgeving je de configuratie bijhoudt en waarom "secrets" niet in omgevingsvariabelen opgeslagen kunnen worden. Onze methode, de web.config met verschillende transformaties is hier prima geschikt voor.

Losstaande processen

Elke applicatie zou als een los proces zonder "state" moeten draaien. Hierdoor kun je bij load een extra webserver erbij gooien en doordraaien.

Deployen en uitvoeren zijn verschillende dingen

Iemand die code deployed, moet mappen en bestanden kunnen aanmaken en wijzigen, rechten instellen. De code die uitgevoerd wordt hoeft in veel gevallen alleen op input te wachten, wat met de database te doen en respons teruggeven. Deze hoeft dus veel minder rechten te hebben dan de deployer. Het geldt het principe van het kleinste privilege, je krijgt de rechten die je nodig hebt, niet meer.

Verwerkende instanties hebben geen state

We zien een plaatje van een aantal mensen die op een website zitten en elk hun eigen winkelkarretje. Deze zit in een "backing database of orders". De bezoeker voegt een boek toe in de winkelwagen en een tijdje later nog een boek. Dat proces, het toevoegen, kan door verschillende instanties uitgevoerd worden (andere front-end webserver). Die instantie moet dus geen state hebben, je stuurt of data terug naar de cliënt of slaat het op in bijvoorbeeld een database.

Als een langdurig proces opgestart moet worden, is het advies van het boek om dit in kleinere delen op te splitsen en een "status-vlag" bij te houden. Als er wat moet worden weggeschreven naar een bestand, dan moet het file-system als een onbetrouwbaar opslagmedium worden beschouwd. Pas als alle acties afgerond zijn kan en mag het proces als afgerond beschouwd worden. Het boek benadrukt dat file-opslag niet betrouwbaar is en veel cloud-diensten het opslaan als bestand(en) zelfs onmogelijk maakt.

Voordelen qua security

Hierin benadrukt het boek nogmaals dat je de processen de laagst mogelijke rechten geeft, zodat een proces wat alleen iets met een database doet niet bij het file-system kan komen. Ook wordt nog een keer de stateless instanties genoemd, voordeel om nieuwe servers op te starten, maar ook een server die niet responsive meer is te killen en te rebooten. Omdat er geen data in bijvoorbeeld het geheugen wordt opgeslagen, verlies je geen data.

Voorkom het opslaan van log-gegevens naar bestanden

Gegevens die in het log komen kunnen soms (onbedoeld) gegevens bevatten die externe partijen niet mogen zien. Je moet logging altijd beschikbaar hebben als developer, maar het moet wel veilig zijn. Er is een design pattern met de naam "logging as a service".

Confidentiality (vertrouwelijkheid): zodra meerdere mensen bij het bestand kunnen komen (hetzij via RDP, hetzij dat er via-via een mogelijkheid is om het bestand via de browser te downloaden), dan weet je niet meer wie wat geraadpleegd heeft. Het vertrouwelijkheidsprincipe wordt dus geschaad door je gegevens in een bestand weg te schrijven.

Integrity (integriteit): als het log-bestand voor een rechtszaak nodig is (die persoon is naar die website gesurft en heeft daar vertrouwelijke informatie gelekt), dan moet de rechter er wel op kunnen vertrouwen dat het bestand niet aangepast is. Heeft iemand op meerdere regels het ip-adres veranderd om een collega erbij te lappen?

Availability (beschikbaarheid): data-migratie (nieuwe server), je moet dan zorgen dat de log-bestanden ook overgezet worden. Het bestand groeit en groeit, wat doe je met diskruimte? Een oplossing hiervoor is rotatie, het bestand syslog wordt hernoemd naar syslog.1 en een nieuw bestand met de naam syslog kan gevuld worden. Die syslog.1 kan overgezet worden naar archief o.i.d.

Logging as a service

Via het netwerk stuur je de data naar een database. Ook hier wordt met de CIA-bril naar gekeken; Confidentiality, je kunt nu met categorieën werken, bijvoorbeeld DEBUG, AUDIT, ERROR en op die manier AUDIT (gevoelige gegevens) afschermen voor de ontwikkelaar die alleen geïnteresseerd is in het type ERROR meldingen. Het loggen wat over het netwerk gaat moet wel via een beveiligde lijn en/of geëncrypt verzonden worden. Integrity, het log-systeem kan gescheiden worden in een READ en WRITE component waardoor dit afgevangen is. Availability, hoe zit het als de log-service eruit ligt? Dat moet je op dezelfde manier oppakken als dat het file-system tijdens wegschrijven niet beschikbaar is. Als loggen essentieel is, moet je dus een rollback doen. Als het geen zaak van leven of dood is en er logdata "weg mag raken" zou je het in het geheugen kunnen opslaan en later nogmaals kunnen proberen te versturen. Doordat je geen losse instanties met eigen (beperkte) diskruimte hebt, maar een centrale locatie voor de logs, kun je daar de zaken configureren qua grootte. En omdat het centraal is, weet je waar je moet zijn als je alle data van iets/iemand moet zoeken of waar je alle data moet verwijderen als dat verzoek er ligt.

Admin processes

Er zitten in een systeem altijd bepaalde taken, zoals imports, het versturen van berichten. Vaak hangt dat er een beetje bij, code is niet in een versiebeheer-systeem bijgehouden, hangt aan elkaar op basis van SQL snippets en bash-scripts. Dat is de verkeerde manier, deze processen moeten meegebouwd worden met de applicatie zelf. Dit leidt tot:

  • je bent zekerder over het systeem, het kan afgesloten worden
  • de integriteit is verbeterd, omdat de tools in sync blijven met het systeem
  • ook als het systeem zwaar belast wordt zijn de admin tools beschikbaar
     

In het boek wordt gezegd dat deze processen (het bijhouden van de voorraad, het opnieuw uitvoeren van een import van prijzen) vaak over het hoofd worden gezien, omdat de focus ligt op de site zelf en de werking daarvan. Maar ook deze processen zijn essentieel voor het product.

Veiligheidsproblemen bij het over het hoofd zien van administratieve taken

In het boek nemen ze het voorbeeld dat via SSH taken uitgevoerd worden. Dat is een extra deur naar de buitenwereld. Het andere risico is dat de scripts die hier opgeslagen worden niet meer overeen komen met de structuur zoals de ontwikkelaars die bijwerken. Bleven eerst bepaalde koppeltabellen bestaan, nu worden ze met een CASCADE DELETE meegenomen. Maar de systeembeheerder wil die tabellen nog wel bewaren. Oeps. Het derde risico dat genoemd wordt betreft de verhoudingen tussen de teams die niet altijd optimaal zijn door deze oplossing.

Het boek geeft aan dat dit meegebouwd moet worden, waarbij er een eigen GUI voor de admin komt en via een API taken uitgevoerd kunnen worden.

Service discovery en load balancing

Dit zijn 2 begrippen die vaak gebruikt worden bij Cloud computing en Platform as a Service-oplossingen. Werd er in het verleden met hardware een load-balancer voor de servers geplaatst (met mogelijke downtime), het is nu de PaaS oplossing die dat allemaal afhandelt. Dat is de centralized load balancing oplossing.

Ook heb je de client-side load balancing. Met service discovery krijgt de client door welke instanties er zijn. De client bepaalt dan welke van die instanties aangeroepen worden.

Embracing Change

Door het dynamische geheel van servers die verschijnen en verdwijnen wordt het voor een partij die misbruik wil maken van de diensten een stuk moeilijker dan dat hij/zij zich op een statische inrichting hoeft te focussen.

De 3 R-en van enterprise security

Als je met de 12-factor app en cloud native zaken jouw applicatie klaar voor de cloud hebt, kun je naar het volgende level. Hier komen de 3 R-en om de hoek. Justin Smith heeft dit lijstje gemaakt:

  • Rotate secrets every few minutes or hours
  • Repave servers and applications every few hours
  • Repair vulnerable software zo snel mogelijk (binnen een paar uur) als er een patch beschikbaar is
     

Verhoog wijzigingen om het risico te beperken

Bij de huidige systemen wordt er zo weinig mogelijk veranderd: een update pas na 3 maanden doorvoeren, een "secret" niet aanpassen, omdat het anders op 5 plekken kapot gaat. Maar als je jouw applicatie "in de cloud" hebt, mag die omgeving niet meer zo statisch zijn. Je moet juist regelmatig de zaken bijwerken om een advanced persistent threat (APT) af te slaan.

Rotate

Als je systeem wachtwoorden gebruikt om verbinding te maken met andere systemen, zorg dan dat deze elke zoveel minuten aangepast worden. En ook dat iedere applicatie zijn eigen gebruikersaccount heeft om verbinding te maken. De PaaS kan ervoor zorgen dat het aangepast wordt en "geïnject" wordt in het systeem wat de data nodig heeft. In het voorbeeld van het boek is dat in RAM, dus niet opgeslagen in een fysiek bestand. Tevens hoef je daardoor de wachtwoorden niet te encrypten om ze dan op te slaan (en later weer decrypten). Dit principe kan ook gebruikt worden voor certifcaten en tokens. In sommige gevallen kan dat niet via de omgeving, maar moet de applicatie zelf een "secret service" aanroepen om bijvoorbeeld het bijgewerkte wachtwoord van de database op te vragen. Dit principe zorgt ervoor dat gelekte wachtwoorden maar kort te gebruiken zijn.

Repave

In dit geval gaat het over servers/containers/VM en applicaties die je elk uur opnieuw hergenereert. Hiermee zorg je dat als iemand "een gaatje" gevonden heeft en bijvoorbeeld een bestand binnen de container heeft kunnen toevoegen, deze na het deployment weer weg is. Als de applicaties 'cloud-native' zijn moet dit geen downtime met zich meebrengen.

Repair

Zowel voor applicaties als het systeem: als er een beveiligingslek is en er is een patch: zo snel mogelijk doorvoeren. Hetzelfde geldt voor eigen applicaties, een nieuwe versie, zo gauw mogelijk deployen.