I blogg #9 går jeg gjennom et eksisterende Python-skript med OWASP secure coding-prinsipper som rammeverk. Ved å se på input-validering, autentisering, TLS, feilhåndtering og logging viser jeg hvordan lab-kode kan forbedres når sikkerhet tas med i designet.
![<span id="hs_cos_wrapper_name" class="hs_cos_wrapper hs_cos_wrapper_meta_field hs_cos_wrapper_type_text" style="" data-hs-cos-general-type="meta_field" data-hs-cos-type="text" >[Min reise mot CCIE Automation #9] Anvendelse av OWASP Secure Coding Practices</span>](https://sicra.no/hs-fs/hubfs/two_guys_working_on_a_computer.jpg?width=1024&height=576&name=two_guys_working_on_a_computer.jpg)
(Denne artikkelen var tidligere en del av Bluetree.no. Siden Sicra og Bluetree har slått seg sammen, er nå innhold fra Bluetree overført til Sicra.)
[Min reise mot CCIE Automation #9] Anvendelse av OWASP Secure Coding Practices er del av en pågående CCIE Automation-serie. I forrige innlegg jobbet jeg med overvåking og synlighet ved hjelp av ThousandEyes. Denne gangen går jeg tilbake til et eksisterende Python-skript og forbedrer det ved å bruke OWASP secure coding-prinsipper.
Denne gangen gikk jeg tilbake til ett av mine egne skript og gjorde det alle ingeniører før eller siden må gjøre: se på lab-kode med produksjonsøyne. Skriptet var skrevet for å løse et problem raskt i et labmiljø – autentisere mot Catalyst Center, hente topologidata og visualisere dem – og det gjorde akkurat det. Det fungerte. Ferdig snakka. Trodde jeg.
Det viser seg at «fungerer i laben» og «designet med sikkerhet i tankene» er to helt forskjellige ting.
I dette innlegget tar jeg dette veldig ekte, veldig uperfekte skriptet og går gjennom det ved hjelp av OWASP secure coding-prinsipper. Målet er ikke å skamme lab-koden min (vi har alle slik kode), men å vise hvordan vanlige snarveier – rundt input-håndtering, legitimasjon, TLS, feilhåndtering og logging – kan identifiseres og forbedres når du begynner å tenke som en plattformingeniør i stedet for en lab-overlever.
Dette handler om å gjøre rask-og-skitten-kode om til bevisst designet kode, én sikkerhetsforbedring av gangen.
Før vi dykker ned i selve skriptet, er det verdt å kort forklare hvorfor OWASP stadig dukker opp når vi snakker om sikker koding.
OWASP (Open Web Application Security Project) er en fellesskapsdrevet organisasjon som fokuserer på å forbedre programvaresikkerhet.
CCIE Automation blueprint lister:
5.1 Utnytte OWASP secure coding practices i alle løsninger for å møte gitte krav
5.1.a Input-validering
5.1.b Autentisering og passordhåndtering
5.1.c Tilgangskontroll
5.1.d Kryptografiske praksiser
5.1.e Feilhåndtering og logging
5.1.f Kommunikasjonssikkerhet
Skriptet henter fysisk topologi fra Catalyst Center og skriver den enten ut som en PyVis-tegning eller som pent formattert JSON. Det er et godt virkelighetsnært eksempel fordi det berører mange vanlige fallgruver innen sikker koding: brukerinput, legitimasjon, TLS, feilhåndtering og logging.
Tar --ip, --username, --password
Kobler til Catalyst Center via ApiCatcenter
Henter topologi som JSON
Konverterer den til et PyVis-vennlig format
Skriver enten HTML-visualisering (topology.html) eller JSON til stdout
La oss nå bruke OWASP secure coding-prinsipper på dette.
Selv om dette er et CLI-skript, er alt som sendes inn å anse som ikke-tiltrodd input.
Hvor input kommer inn
--ip
--username
--password
--type
Jeg validerer allerede --type med click.Choice. Det som mangler er validering av Catalyst Center-adressen.
❌ Nåværende (ingen validering)
@click.option('--ip', '-ip', required=True, help='IP address of Catalyst Center')
...
api_catcenter = ApiCatcenter(ip, username, password)
Hvis brukeren skriver feil, får du runtime-feil (eller verre, i andre kontekster: SSRF-lignende problemer når input blir brukt som URL).
✅ Bedre (syntaktisk validering)
Valider at --ip er en gyldig IP-adresse eller et hostname (avhengig av hva du ønsker å støtte). For kun IP:
import ipaddress
def validate_ip(ctx, param, value):
try:
ipaddress.ip_address(value)
return value
except ValueError:
raise click.BadParameter("Must be a valid IPv4/IPv6 address")
@click.option('--ip', '-i', required=True, callback=validate_ip, help='Catalyst Center IP')
✅ Legg til semantisk validering (kontekstregler)
Hvis du vet at Catalyst Center må ligge innenfor bestemte nett (for eksempel lab-subnett), kan du håndheve dette.
allowed = ipaddress.ip_network("10.0.0.0/8")
if ipaddress.ip_address(value) not in allowed:
raise click.BadParameter("IP must be within the lab range")
Dette er OWASP sin «syntaks + semantikk» i praksis.
Skriptet autentiserer mot Catalyst Center med brukernavn og passord. OWASP-forbedringen handler mindre om å endre autentiseringsmetode og mer om å redusere eksponering.
Å sende secrets via --password er risikabelt fordi det kan dukke opp i:
shell-historikk
prosesslister (ps)
CI-logger
❌ Nåværende
@click.option('--password', '-p', required=True, help='API password')
✅ Bedre: prompt + skjult input (og/eller miljøvariabel)
@click.option('--password', '-p',
prompt=True, hide_input=True, confirmation_prompt=False,
envvar="CATC_PASSWORD",
help='API password (or set CATC_PASSWORD)')
Dette gjør skriptet brukbart både interaktivt og tryggere i automatisering.
Autentisering svarer på «hvem er du?» – passordhåndtering svarer på «hvordan håndterer du secrets trygt?».
Forbedringer her:
Ikke hardkode secrets (det gjør jeg ikke – bra)
Unngå å sende secrets som argumenter (fikset over)
Bruk en read-only / least-privileged konto for topologiuthenting
❌ Feil mønster (ikke i min kode, men vanlig)
password = "P@ssw0rd!"
✅ Riktig mønster (miljøvariabler + prompting)
CATC_PASSWORD som miljøvariabel i CI
click.prompt(... hide_input=True) lokalt
Vurder å integrere en secret manager som Vault, noe jeg allerede gjør i andre deler av applikasjonen.
Dette skriptet implementerer ikke RBAC selv – men autorisering er likevel viktig, fordi identiteten du autentiserer med avgjør hva skriptet har tilgang til.
OWASP-forbedring: least privilege
For API-lesing er beste praksis:
Bruk en konto med kun lese-rettigheter
Unngå kontoer som kan gjøre provisjonering eller endringer
Dette er det mest åpenbare OWASP-punktet i skriptet mitt.
Å deaktivere SSL-advarsler er et rødt flagg.
Jeg gjør for øyeblikket:
urllib3.disable_warnings()
Det indikerer sterkt at jeg kobler til med ugyldige/selvsignerte sertifikater uten verifisering et sted i stakken.
❌ Feil (vanlig labsnarvei)
Deaktivere advarsler og hoppe over sertifikatverifisering
Trener deg i usikre standardvalg
✅ Bedre: gjør TLS-verifisering konfigurerbar
Et godt kompromiss for sikker koding er:
Verifiser TLS som standard
Tillat eksplisitt --insecure-flag for labbruk
Eksempel på CLI-alternativer:
--verify/--no-verify (standard er verify)
Deretter bør ApiCatcenter sende dette videre til HTTP-klienten.
Hovedpoeng:
Den sikre standarden er at TLS-verifisering er aktivert. Hvis du velger å deaktivere verifisering i et labmiljø, bør det være et eksplisitt og synlig valg.
Skriptet bruker i dag sys.exit(1) og skriver meldinger til bruker. Det fungerer, men er ikke ideelt fordi:
sys.exit() stopper hele kjeden brått
feiloutput er ikke standardisert
du kan utilsiktet lekke sensitiv info hvis exceptions bobler opp
❌ Nåværende
click.echo(click.style("Could not connect to catcenter", fg="red"), err=True)
sys.exit(1)
✅ Bedre: bruk Click-exceptions
Click gir ryddig CLI-oppførsel automatisk:
raise click.ClickException("Could not connect to Catalyst Center")
Foretrekk også å feile med trygge, høynivå meldinger, og logg detaljer separat.
Jeg bruker i dag click.echo() til alt. Det er greit for UX, men ikke skikkelig logging:
ingen loggnivåer
ingen tidsstempler
ikke maskinlesbart
ingen separasjon mellom brukeroutput og audit/debug-logger
Behold click.echo() for brukerstatus
Legg til Python logging for strukturerte logger
Logg aldri passord/tokens
Legg til korrelasjons-ID-er om ønskelig
❌ Feil
click.echo(f"Connecting to Catalyst Center at {ip} with {username}/{password}")
✅ Riktig
logger.info("Connecting to Catalyst Center", extra={"host": ip, "user": username})
Og hvis du må logge request/response-detaljer, maskér (redact) secrets.
Dette skriptet startet livet akkurat der mye automasjonskode starter: i en lab, skrevet for å løse et problem raskt og gå videre. Det fungerte, og på det tidspunktet var det nok. Å se på det igjen gjennom OWASP secure coding-briller var en nyttig påminnelse om at fungerende kode og godt designet kode ikke er det samme.
Det som slo meg mest i denne øvelsen, er at ingen av forbedringene krevde en full omskriving. Ved å validere input tidlig, håndtere legitimasjon mer forsiktig, håndheve least privilege, fikse TLS-standarder, forbedre feilhåndtering og skille logging fra brukeroutput, ble skriptet betydelig sikrere uten å bli mer komplekst.
Dette er et viktig poeng for meg i arbeidet mot CCIE Automation-labben: sikker koding handler ikke om perfeksjon eller paranoia. Det handler om bevisste designvalg, selv i små verktøy, og å forstå hvor snarveier er akseptable – og hvor de ikke er det.
[Min reise mot CCIE Automation #1] Introduksjon + bygging av en Python CLI-applikasjon
[Min reise mot CCIE Automation #2] Inventory REST API og mikrotjenestearkitektur
[Min reise mot CCIE Automation #3] Orchestration API og NETCONF
[Min reise mot CCIE Automation #10] Fra Docker Compose til Kubernetes



