Under 2025 tog svenska Integritetsskyddsmyndigheten (IMY) emot 12 276 anmälningar om personuppgiftsincidenter, den högsta siffran sedan GDPR trädde i kraft 2018. En del av dessa incidenter går tillbaka till samma grundorsak: webbservrar som fortfarande accepterar föråldrade TLS-protokoll, svaga chiffer eller trasiga certifikatkedjor. OWASP klassar felkonfigurerad SSL/TLS som en kryptografisk brist (Cryptographic Failures), en av de vanligaste svagheterna säkerhetsgranskare hittar i produktionsmiljöer.
Den här guiden visar hur du skannar, tolkar och härdar din TLS-konfiguration med öppen källkodsverktyg, sedan bygger in kontrollen i CI/CD så att en regression stoppas innan den når produktion. Du använder testssl.sh som huvudverktyg, kompletterar med sslyze för snabbare strukturerad analys, och validerar resultatet externt med Qualys SSL Labs. Sist automatiserar du hela flödet i GitHub Actions med gränsvärden som får bygget att misslyckas om någon lägger till ett svagt chiffer av misstag.
Bakgrunden är inte bara teoretisk. Ransomware-gruppen Qilin stod för 1 062 registrerade incidenter globalt 2025 och fortsatte i samma takt med 389 attacker under första kvartalet 2026, en ökning på ungefär 50 procent jämfört med föregående period. Svag TLS-härdning förenklar inte ransomware-angrepp direkt, men den öppnar dörrar: avlyssningsbar trafik, nedgraderingsattacker och exponerade tjänster som blir startpunkten för intrång. Att stänga de dörrarna är precis vad den här artikeln går igenom, steg för steg, med kommandon du kan köra direkt.
Läget förvärras av hur snabbt sårbarhetslistan växer. CISA:s katalog över kända, aktivt utnyttjade sårbarheter fick 23 nya poster bara i juni 2026, varav sex klassades som zero-days och två redan hade publik exploit-kod i omlopp. Flera av dem träffade nätverks- och webbtjänster där bristande transportlagerhärdning gjorde det enklare för angripare att röra sig vidare efter första intrånget. Insikt Group på Recorded Future räknade dessutom 23 kritiska eller högriskklassade sårbarheter redan i januari 2026, en ökning på cirka 5 procent jämfört med föregående mätperiod. TLS-härdning stoppar inte en sårbarhet i sig, men den tar bort en hel kategori av sekundära vägar in, avlyssning och nedgradering, som annars förvärrar effekten av nästa CVE som drabbar er infrastruktur.
Förutsättningar: verktyg och versioner du behöver
Innan du börjar, se till att du har tillstånd att skanna målservern. En TLS-skanning räknas som en aktiv säkerhetstest, och att köra den mot infrastruktur du inte äger eller saknar skriftligt godkännande för kan bryta mot både avtal och lag. Skanna din egen domän, en testmiljö, eller ett system där du har uttryckligt mandat.
Nedan listas verktygen som används genom hela guiden, med rekommenderade versioner och vad de används till.
| Verktyg | Version | Syfte |
|---|---|---|
| testssl.sh | Senaste huvudgren (klonas från GitHub) | Bash-baserad TLS/SSL-skanner, huvudverktyg i guiden |
| OpenSSL | 3.0 eller senare | Kryptografiskt bibliotek som testssl.sh och sslyze bygger på |
| sslyze | Senaste version via pip | Snabb, Python-baserad skanner med strukturerad JSON-utdata |
| Python | 3.10 eller senare | Krävs för att installera och köra sslyze |
| Bash | 4.x eller senare | Kör testssl.sh på Linux, macOS eller WSL2 på Windows |
| Docker | Valfritt, senaste stabila | Containerbaserad körning utan lokal installation |
| Nginx | 1.24 eller senare | Webbserver som härdas i exemplen (samma principer gäller Apache) |
| GitHub Actions | – | CI/CD-plattform för automatiserad skanning |
Du behöver också root- eller sudo-åtkomst till servern du ska härda, samt en domän med giltigt certifikat. Har du inget certifikat ännu finns steg-för-steg-instruktioner i vår guide till Let’s Encrypt och Certbot, och om du hellre hanterar egna nycklar och certifikat manuellt går det igenom i artikeln om OpenSSL, nycklar och certifikat.
Fundera också på om du vill köra testssl.sh nativt eller via Docker. Den native varianten är snabbast och enklast att felsöka, men kräver att systemets OpenSSL-installation är tillräckligt modern. Docker-varianten är långsammare att starta men ger en identisk, isolerad miljö oavsett vilken distribution CI-servern kör, vilket gör den till ett tryggare val i pipelines där flera team delar samma byggagenter. Båda vägarna fungerar med kommandona i den här guiden, byt bara ./testssl.sh mot docker run --rm -ti drwetter/testssl.sh om du väljer containervarianten.
Steg 1-2: Installera testssl.sh och kör din första skanning
testssl.sh är skrivet i ren bash och kräver ingen kompilering. Klona projektet från GitHub och gör skriptet körbart.
git clone --depth 1 https://github.com/testssl/testssl.sh.git
cd testssl.sh
chmod +x testssl.sh
./testssl.sh --version
Kör därefter en första, grundläggande skanning mot din domän. Utan flaggor testar testssl.sh protokoll, chiffer, certifikat och kända sårbarheter i en enda körning.
./testssl.sh din-domän.se
En typisk körning tar mellan 30 sekunder och två minuter beroende på hur många cipher-kombinationer servern erbjuder. Utdata är strukturerad i sektioner: serverinformation, protokollstöd, cipher-kategorier, kända sårbarheter (Heartbleed, POODLE, ROBOT, med flera) och certifikatdetaljer. Ett förkortat exempel på utdata ser ut ungefär så här:
Testing protocols via sockets
SSLv2 not offered (OK)
SSLv3 not offered (OK)
TLS 1 not offered (OK)
TLS 1.1 not offered (OK)
TLS 1.2 offered (OK)
TLS 1.3 offered (OK): final
Testing cipher categories
NULL ciphers not offered (OK)
Anonymous NULL Ciphers not offered (OK)
Export ciphers (w/o ADH+NULL) not offered (OK)
LOW: 64 Bit + DES, RC[2,4] not offered (OK)
Triple DES Ciphers / IDEA not offered (OK)
Obsoleted CBC ciphers offered
Strong encryption (AEAD ciphers) offered (OK)
Radera not offered (OK) från blicken och leta i stället efter allt som säger offered utan (OK) bredvid, exempelvis raden om obsoleta CBC-chiffer ovan. Det är precis den typen av fynd du åtgärdar i härdningsstegen längre ner i guiden.
Steg 3-4: Tolka protokoll- och cipher-resultat
TLS 1.3, definierat i RFC 8446, är rekommenderad standard för nya driftsättningar 2026. Protokollet tar bort stöd för föråldrade cipher-konstruktioner helt och förhandlar nyckelutbyte snabbare (ett round-trip mindre än TLS 1.2 i de flesta fall). TLS 1.0 och 1.1 är formellt avvecklade genom RFC 8996 och bör vara avstängda överallt, medan TLS 1.2 fortfarande är acceptabelt så länge det begränsas till starka cipher-sviter.
| Protokoll | Status 2026 | Rekommendation |
|---|---|---|
| SSL 2.0 / 3.0 | Kritiskt osäkert | Stäng av helt, aldrig acceptabelt |
| TLS 1.0 | Formellt avvecklat (RFC 8996) | Stäng av |
| TLS 1.1 | Formellt avvecklat (RFC 8996) | Stäng av |
| TLS 1.2 | Fortfarande i bruk brett | Behåll, men begränsa till AEAD-chiffer med forward secrecy |
| TLS 1.3 | Rekommenderad standard | Sätt som förstahandsval, tvinga där det går |
På cipher-sidan är RC4 och 3DES de två klassikerna som fortfarande dyker upp i produktionsmiljöer trots att de räknas som brutna eller kraftigt försvagade. Prioritera cipher-sviter med AEAD-kryptering (AES-GCM, ChaCha20-Poly1305) och forward secrecy via ECDHE-nyckelutbyte. Forward secrecy betyder att en läckt privat nyckel inte automatiskt exponerar tidigare inspelad trafik, en egenskap statiska RSA-nyckelutbyten helt saknar.
Läs cipher-listan från testssl.sh rad för rad och notera särskilt sektionen “Testing robust forward secrecy” samt “Testing server preferences”. Om servern själv väljer cipher (server-preferred order) och den listan börjar med ett svagt alternativ, är det ett härdningsobjekt även om starkare chiffer också erbjuds.
Ett vanligt nybörjarmisstag är att tolka en lång lista av “OK”-rader som ett grönt ljus rakt igenom, utan att titta på vad som faktiskt erbjuds parallellt. En server kan erbjuda både ett starkt AEAD-chiffer och ett gammalt CBC-baserat chiffer samtidigt, och rapporten markerar det som “offered” utan varningsflagga eftersom det tekniskt sett fungerar. Det är fortfarande ett problem, för en nedgraderingsattack kan tvinga fram det svagare alternativet om klienten manipuleras eller om en gammal klient ansluter. Målet är inte bara att ha ett bra chiffer tillgängligt, utan att ta bort de dåliga alternativen helt.
Steg 5-6: Granska certifikatkedjan och kontrollera HSTS-headers
En giltig TLS-konfiguration räcker inte om certifikatkedjan är trasig. Kör testssl.sh med flaggan -S för att fokusera enbart på certifikatdetaljer.
./testssl.sh -S din-domän.se
Kontrollera fyra saker specifikt: att kedjan är komplett fram till en betrodd rot, att inget mellanliggande certifikat saknas, att giltighetstiden inte går ut inom de närmaste 30 dagarna, och att nyckellängden (minst 2048 bitar för RSA, eller en modern elliptisk kurva som P-256) håller måttet. Ett vanligt fel är att servern presenterar bladcertifikatet men glömmer skicka med mellancertifikatet, vilket fungerar i vissa webbläsare men fallerar i andra klienter och API-integrationer.
Automatisk förnyelse löser en del av problemet men inte allt. Certbot och liknande verktyg förnyar certifikatet, men om förnyelsen tyst misslyckas i flera veckor (till exempel för att en brandväggsregel ändrats) märks det ofta först när certifikatet redan gått ut och användarna möts av en varningssida. Bygg därför in en separat kontroll av utgångsdatum i samma pipeline som resten av TLS-skanningen, snarare än att bara lita på att förnyelsejobbet rapporterar fel om det skulle strula.
Kontrollera därefter säkerhetsheaders. HTTP Strict Transport Security (HSTS) tvingar webbläsaren att alltid använda HTTPS mot din domän, även om en användare skriver in adressen utan https://. testssl.sh rapporterar HSTS-status under sektionen “HTTP Header response”, men du kan även verifiera direkt med curl.
curl -sI https://din-domän.se | grep -i strict-transport-security
En stark HSTS-header ser ut ungefär så här: Strict-Transport-Security: max-age=31536000; includeSubDomains; preload. Värdet 31 536 000 sekunder motsvarar ett år. Lägg bara till preload när du är säker på att alla subdomäner faktiskt stödjer HTTPS, för preload-listan är svår att backa ur när den väl är inskickad till webbläsartillverkarna.
Steg 7: Komplettera med sslyze för snabbare, strukturerad analys
testssl.sh är grundligt men relativt långsamt eftersom det testar sekventiellt över socket-anslutningar. sslyze, skrivet i Python, kör tester parallellt och levererar resultat som strukturerad JSON, vilket gör verktyget bättre lämpat för automatisering och CI/CD-pipelines. Installera det via pip.
pip install --upgrade sslyze
sslyze --regular din-domän.se
Flaggan --regular kör en standarduppsättning kontroller: protokollstöd, cipher-sviter, certifikatvalidering och kända sårbarheter som Heartbleed och ROBOT. Vill du ha maskinläsbar utdata för att koppla ihop med ett CI-jobb, exportera i stället till JSON.
sslyze --regular --json_out=resultat.json din-domän.se
Fördelen med att köra både testssl.sh och sslyze är redundans. De två projekten underhålls av olika team med olika testmetodik, och det förekommer att den ena fångar en detalj den andra missar, särskilt vid nya TLS-tillägg eller ovanliga cipher-kombinationer. I en mogen pipeline kör du testssl.sh för den djupa manuella granskningen och sslyze för den snabba, automatiserade grinden.
Steg 8: Validera externt med Qualys SSL Labs
Lokala skanningar berättar vad servern erbjuder, men de säger inget om hur externa klienter faktiskt upplever anslutningen genom brandväggar, CDN:er eller lastbalanserare. Qualys SSL Labs är ett gratis, webbaserat testverktyg som betygsätter din TLS-konfiguration från A+ till F baserat på protokollstöd, cipher-styrka, certifikatkvalitet och kända sårbarheter.
Ett viktigt observandum: SSL Labs publicerar resultatet på en offentlig resultattavla som standard. Bocka i “Do not show the results on the boards” innan du skannar en produktionsdomän du inte vill exponera i en offentlig lista över nyligen testade sajter. Testet tar vanligtvis 1-2 minuter och ger dig, utöver betyget, en detaljerad förhandlingssimulering som visar exakt vilket protokoll och vilken cipher-svit olika webbläsare och operativsystem skulle välja mot din server.
Använd SSL Labs som ett andra öga snarare än ditt enda verktyg. Betyget uppdateras när Qualys ändrar sin poängsättningsmodell, vilket innebär att en konfiguration som fick A+ förra året kan tappa till A om nya krav införs, utan att du faktiskt har försämrat något på servern.
Tänk också på anropsfrekvensen om du planerar att köra SSL Labs-testet automatiserat. Tjänsten är byggd för enstaka, manuella kontroller snarare än frekventa CI-anrop, och upprepade automatiserade förfrågningar mot samma domän riskerar att triggas som avvikande trafik. Använd i stället testssl.sh och sslyze för den täta, automatiserade kontrollen i CI/CD, och spara SSL Labs för en manuell stickprovskontroll månadsvis eller inför en större lansering.
Steg 9-10: Härda Nginx: protokoll, chiffer, HSTS och OCSP stapling
Med skanningsresultaten i hand är det dags att faktiskt ändra konfigurationen. Nedan är en härdad TLS-sektion för Nginx som stänger av allt äldre än TLS 1.2, prioriterar TLS 1.3, och begränsar TLS 1.2 till AEAD-chiffer med forward secrecy. Vill du hellre köra samma härdning bakom en mutual-TLS-uppsättning för interna API:er finns detaljerna i vår guide till mTLS med Nginx.
server {
listen 443 ssl;
http2 on;
server_name din-domän.se;
ssl_certificate /etc/letsencrypt/live/din-domän.se/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/din-domän.se/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305;
ssl_prefer_server_ciphers on;
ssl_ecdh_curve X25519:prime256v1:secp384r1;
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off;
ssl_stapling on;
ssl_stapling_verify on;
resolver 1.1.1.1 8.8.8.8 valid=300s;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Content-Type-Options "nosniff" always;
}
OCSP stapling (raderna med ssl_stapling) gör att servern själv bifogar ett färskt återkallelsebesked från certifikatutfärdaren i TLS-handskakningen, i stället för att klienten separat behöver fråga utfärdaren varje gång. Det snabbar upp anslutningen och minskar hur mycket information om besökarens surfvanor som läcker till en tredje part. Testa om stapling faktiskt fungerar med openssl s_client -connect din-domän.se:443 -status och leta efter OCSP Response Status: successful i utdata.
Kör om testssl.sh eller sslyze efter varje ändring. Att verifiera en härdning direkt efter deploy, i stället för att lita på att konfigurationen “borde” fungera, är den enskilt viktigaste vanan i hela den här guiden.
Motsvarande härdning i Apache
Kör ni Apache i stället för Nginx gäller samma principer, bara direktiven som ser annorlunda ut. Lägg följande i din virtuella värd eller i en global SSL-konfigurationsfil.
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/din-domän.se/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/din-domän.se/privkey.pem
SSLProtocol -all +TLSv1.2 +TLSv1.3
SSLCipherSuite ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384
SSLHonorCipherOrder on
SSLSessionTickets off
SSLUseStapling on
SSLStaplingCache shmcb:/var/run/ocsp(128000)
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
Testa konfigurationen med apachectl configtest innan omstart, precis som du gör med nginx -t. Kör sedan om testssl.sh mot domänen igen för att bekräfta att ändringen faktiskt slog igenom, oavsett vilken webbserver du använder.
Steg 11: Automatisera skanningen i CI/CD med GitHub Actions
En manuell skanning fångar problem den dag du kör den. En pipeline som kör vid varje deploy fångar regressioner innan de når användarna. Nedan är ett GitHub Actions-workflow som klonar testssl.sh, kör en skanning mot din domän efter varje deploy till main, och sparar resultatet som en artefakt.
name: tls-scan
on:
push:
branches: [main]
schedule:
- cron: '0 6 * * 1' # varje måndag 06:00 UTC
jobs:
scan:
runs-on: ubuntu-latest
steps:
- name: Klona testssl.sh
run: git clone --depth 1 https://github.com/testssl/testssl.sh.git
- name: Kör TLS-skanning
run: |
cd testssl.sh
./testssl.sh --jsonfile ../resultat.json din-domän.se
- name: Spara resultat som artefakt
uses: actions/upload-artifact@v4
with:
name: tls-scan-resultat
path: resultat.json
Schemaläggningen med cron: '0 6 * * 1' säkerställer att skanningen körs varje vecka oavsett om det skett en deploy, vilket fångar upp fall där certifikat närmar sig utgångsdatum eller där en extern CDN-leverantör ändrat sin TLS-konfiguration utan att du gjort någon egen ändring. Kombinera gärna detta jobb med skanningsloggen i din befintliga rutin för patchhantering, så hamnar TLS-fynd i samma triage-flöde som andra sårbarheter.
Steg 12: Sätt gränsvärden som stoppar bygget vid regression
Att bara samla in skanningsdata räcker inte, pipelinen måste faktiskt agera på resultatet. Nedan är ett litet Python-skript som läser JSON-utdata från testssl.sh, letar efter allvarliga fynd (severity HIGH eller CRITICAL), och avslutar med felkod om något hittas, vilket får CI-jobbet att markeras som misslyckat.
import json
import sys
with open("resultat.json") as f:
data = json.load(f)
allvarliga = [
fynd for fynd in data
if fynd.get("severity") in ("HIGH", "CRITICAL")
]
if allvarliga:
print(f"Hittade {len(allvarliga)} allvarliga TLS-fynd:")
for fynd in allvarliga:
print(f" - {fynd.get('id')}: {fynd.get('finding')}")
sys.exit(1)
print("Inga allvarliga TLS-fynd. Godkänd.")
sys.exit(0)
Lägg till skriptet som ett eget steg i workflowet efter skanningen. Håll tröskelvärdet strikt i början, justera sedan ner brusnivån när teamet fått en känsla för vilka varningar som faktiskt kräver åtgärd kontra vilka som är avsiktliga undantag (till exempel ett internt API som medvetet stödjer TLS 1.2 för en äldre klient som ännu inte kan uppgraderas).
Undvik frestelsen att sätta tröskelvärdet på “noll varningar av något slag” från dag ett. Ett nystartat projekt som plötsligt kräver en helt ren rapport för att kunna deploya riskerar att blockera hela teamet första gången skriptet körs mot en befintlig, delvis ohärdad miljö. Kör i stället skriptet i en varningsläge (logga fynden men returnera 0) under en eller två veckor, samla en baslinje, åtgärda de värsta fynden manuellt, och byt sedan till att faktiskt stoppa bygget. Den ordningen bygger förtroende för kontrollen i stället för att den upplevs som ett hinder redan från start.
Steg 13-14: Schemalägg kontinuerlig övervakning och dokumentera resultatet
Certifikat går ut, molnleverantörer ändrar standardkonfigurationer, och nya sårbarheter upptäcks i befintliga protokoll. En engångsskanning ger en ögonblicksbild, inte ett skydd över tid. Utöver det veckovisa cron-jobbet i steg 11, sätt upp en avisering som går till Slack eller e-post så fort pipelinen misslyckas, i stället för att förlita dig på att någon manuellt kollar CI-loggen.
- name: Skicka Slack-avisering vid fel
if: failure()
uses: slackapi/slack-github-action@v1
with:
payload: '{"text":"TLS-skanning misslyckades för din-domän.se, se artefakten för detaljer."}'
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
Spara historiska skanningsresultat, antingen som CI-artefakter med lång retention eller i en enkel databas, så att du kan visa trendlinjer över tid: hur länge tog det att åtgärda en viss brist, hur ofta upptäcks nya fynd, och vilka domäner i er portfölj som konsekvent presterar sämst. Den typen av dokumentation är också vad en revisor eller NIS2-tillsyn frågar efter först, ett spårbart bevis på att kontrollen faktiskt körs regelbundet, inte bara att den finns beskriven i ett dokument.
TLS i molnet: särskilda fallgropar hos Cloudflare, AWS och Azure
Nästan ingen nordisk organisation terminerar TLS direkt mot en enda server längre. De flesta lägger en CDN, en lastbalanserare eller en molnleverantörs edge-tjänst framför origin-servern, vilket förändrar var i kedjan härdningen faktiskt behöver ske. En genomgång av molnrelaterade dataincidenter under 2026 pekar ut felkonfigurerade nätverks- och krypteringsinställningar hos både AWS och Azure som en återkommande grundorsak till läckor, vid sidan om öppna lagringshinkar och för generösa IAM-roller.
Skillnaden mot en enda server är att du nu måste skanna flera punkter separat: den publika kanten (det besökaren faktiskt ansluter till), och sträckan mellan kanten och origin-servern om den går över öppet internet. Många team härdar bara den publika kanten eftersom det är den enda adressen som är lätt att komma åt utifrån, och missar därmed att den interna sträckan fortfarande kör en föråldrad konfiguration. Lägg helt enkelt till en extra rad i skanningsskriptet från steg 11 som pekar mot origin-serverns IP-adress eller interna hostnamn, så täcker samma pipeline båda punkterna i kedjan.
Cloudflare och TLS-terminering
Cloudflares standardläge “Flexible” krypterar bara trafiken mellan besökaren och Cloudflares kant, inte mellan kanten och din origin-server, vilket ger en falsk känsla av säkerhet eftersom hänglåset ändå visas i webbläsaren. Byt till “Full (strict)” så snart origin-servern har ett giltigt certifikat, och använd gärna Cloudflares egna TLS-rekommendationsverktyg för att automatiskt flagga när inställningen inte matchar vad origin-servern faktiskt stödjer. Testa alltid origin-servern separat med testssl.sh riktat mot dess direkta IP-adress, annars mäter du bara Cloudflares kant och missar svagheter längre bak i kedjan.
AWS Certificate Manager och Application Load Balancer
På AWS hanteras certifikat vanligen via AWS Certificate Manager kopplat till en Application Load Balancer. Den vanligaste härdningsmissen här är att lämna kvar en äldre säkerhetspolicy, till exempel en policy som fortfarande tillåter TLS 1.0, eftersom ALB inte uppdaterar policyn automatiskt när du byter certifikat. Gå igenom lastbalanserarens listener-inställningar manuellt och välj en av de nyare säkerhetspolicyerna som exkluderar TLS 1.0 och 1.1, sedan kör testssl.sh mot lastbalanserarens publika DNS-namn för att bekräfta att ändringen faktiskt syns utåt.
Azure Front Door och App Service
Azure Front Door stödjer end-to-end-TLS där trafiken krypteras hela vägen till backend-tjänsten, men funktionen måste aktiveras explicit per rutt. Standardkonfigurationen terminerar TLS vid kanten och skickar sedan vidare okrypterat internt i vissa äldre uppsättningar, vilket blir ett problem om backend-nätverket delas med andra tjänster. Kombinera detta med den admission-time-kontroll som beskrivs i avsnittet om avancerade tips nedan, så fångas en svag TLS-policy redan innan en ny deployment går live.
TLS-härdning som efterlevnadsfråga: GDPR, NIS2 och IMY
För många svenska organisationer är TLS-härdning inte längre en frivillig teknisk detalj, utan en del av vad tillsynsmyndigheter och revisorer förväntar sig som grundhygien. IMY har vid upprepade tillfällen pekat ut svag teknisk säkerhet, inklusive föråldrad kryptering, som en bidragande faktor i anmälda personuppgiftsincidenter, och NIS2-regelverket ställer uttryckliga krav på att väsentliga och viktiga entiteter ska kunna visa att de har lämpliga tekniska åtgärder för nätverks- och informationssäkerhet, inklusive kryptering.
OWASP beskriver felkonfigurerad kryptografi som en av de vanligaste kategorierna av säkerhetsbrister i webbapplikationer, vilket gör TLS-härdning till ett naturligt kontrollpunkt i både interna säkerhetsgranskningar och externa penetrationstester. Det praktiska rådet är att inte bara härda konfigurationen en gång, utan att spara skanningsresultaten som bevis, exakt det som CI/CD-pipelinen från steg 11 till 14 i den här guiden gör automatiskt. När en revisor frågar hur ni säkerställer att TLS-konfigurationen inte försämras över tid, är svaret en logg med veckovisa skanningar snarare än en muntlig försäkran.
Vanliga fallgropar vid TLS-härdning
Samma misstag återkommer om och om igen i TLS-härdningsprojekt. Här är de vanligaste, i den ordning de brukar dyka upp.
- Att stänga av TLS 1.2 helt för tidigt. Vissa äldre klienter, betalningsterminaler och interna system saknar fortfarande TLS 1.3-stöd. Kontrollera faktisk klienttrafik i loggarna innan du tar bort TLS 1.2, annars stänger du ute riktiga användare.
- Att glömma mellanliggande certifikat i kedjan. Servern fungerar i webbläsaren men fallerar i mobilappar, API-klienter eller äldre bibliotek som inte bygger kedjan på samma sätt.
- Att sätta HSTS preload utan att testa alla subdomäner. Preload-listan cachas i webbläsarens källkod och kan ta månader att få bort om en subdomän saknar giltigt HTTPS-stöd.
- Att lita på en enda skanning. En konfiguration som var korrekt vid driftsättning kan tysta försämras när ett CDN, en lastbalanserare eller ett bibliotek uppdateras utan att någon TLS-relaterad ändring gjorts avsiktligt.
- Att blanda ihop cipher-ordning för TLS 1.2 och TLS 1.3. TLS 1.3 har en fast, mindre lista med säkra cipher-sviter och ignorerar
ssl_ciphers-direktivet för den delen, vilket förvirrar många som försöker “härda” en rad som redan är säker som standard. - Att skanna produktionsservern utan att informera driftteamet. Aggressiva skanningsflaggor kan generera ovanligt hög trafik och trigga larm i ett intrångsdetekteringssystem, vilket skapar onödig oro om ingen vet att skanningen är planerad.
- Att härda origin-servern men glömma CDN-lagret. Om trafiken passerar Cloudflare, en annan CDN eller en molnleverantörs edge-tjänst räcker det inte att härda bara den bakomliggande servern. Kontrollera TLS-inställningarna i varje lager trafiken passerar, annars mäter din externa skanning bara den svagaste länken.
- Att behandla ett A+-betyg som ett engångsmål. Ett högt betyg hos SSL Labs eller en ren rapport från testssl.sh är en ögonblicksbild. Utan schemalagd uppföljning enligt steg 13 vet ingen om konfigurationen fortfarande håller måttet om sex månader.
Felsökning: vanliga problem och lösningar
Nedan är de problem som oftast dyker upp när team börjar köra testssl.sh, sslyze och Nginx-härdning i skarpt läge, tillsammans med vad som faktiskt löser dem.
| Problem | Trolig orsak | Lösning |
|---|---|---|
| testssl.sh avslutas med “OpenSSL too old” | Systemets inbyggda OpenSSL saknar moderna cipher-sviter | Använd den medföljande statiskt länkade OpenSSL-binären i testssl.sh-mappen, eller kör via Docker |
| sslyze kraschar med ImportError | Fel Python-version eller trasig virtuell miljö | Kör i en ren venv med Python 3.10+ och installera om med pip install --upgrade sslyze |
| SSL Labs ger lägre betyg än den lokala skanningen antyder | CDN eller lastbalanserare framför servern terminerar TLS med annan konfiguration | Skanna den publika IP-adressen som faktiskt tar emot trafik, inte origin-servern direkt |
| Nginx startar inte efter ändring av ssl_ciphers | Syntaxfel eller cipher-namn som inte stöds av den installerade OpenSSL-versionen | Kör nginx -t innan reload, och verifiera cipher-namn med openssl ciphers -v 'ECDHE+AESGCM' |
| OCSP stapling visar “no response sent” | Resolver kan inte nå certifikatutfärdarens OCSP-server | Kontrollera att resolver-direktivet pekar på en fungerande DNS-server och att utgående trafik på port 80 tillåts |
| CI-jobbet timeoutar under testssl.sh-körning | Full skanning testar hundratals cipher-kombinationer sekventiellt | Använd flaggan --fast eller begränsa till specifika tester (-p -h -S) i CI, kör den fulla skanningen manuellt vid behov |
| Klienter med äldre TLS-bibliotek kan inte längre ansluta | TLS 1.0/1.1 stängdes av utan att kartlägga faktisk klientbas | Analysera åtkomstloggar för ssl_protocol innan avstängning, kommunicera brytpunkten i förväg |
| HSTS-headern syns inte i testssl.sh-resultatet | Headern sätts först efter en redirect, testssl.sh läser inte alltid följande request | Verifiera manuellt med curl -sI mot den slutgiltiga HTTPS-URL:en |
| sslyze och testssl.sh ger motstridiga resultat för samma cipher | Olika versioner av underliggande OpenSSL-bibliotek i respektive verktyg | Uppdatera båda verktygen till senaste version och jämför igen, avvikelser minskar oftast |
Avancerade tips och ett komplett projektexempel
När grundhärdningen sitter finns det ett par steg till som separerar en godkänd konfiguration från en riktigt stark. Session resumption via ssl_session_tickets off tvingar en ny full handskakning oftare, vilket kostar lite prestanda men minskar risken kopplad till återanvända sessionsnycklar. TLS 1.3:s 0-RTT-läge (early data) snabbar upp återanslutningar men öppnar för replay-attacker mot idempotenta requests, så stäng av det om din applikation inte explicit är byggd för att hantera dubbletter säkert.
Håll också ett öga på hybrid post-kvant-nyckelutbyte. Flera stora molnleverantörer och webbläsare har under 2025 och 2026 börjat experimentera med hybrider som X25519Kyber768, där en klassisk elliptisk kurva kombineras med en kvantresistent algoritm för att skydda mot framtida “harvest now, decrypt later”-scenarier. Det är ännu inte ett krav för de flesta nordiska organisationer, men värt att bevaka om ni hanterar data med lång sekretesslivslängd.
Cipher-ordningen spelar större roll än många inser. Direktivet ssl_prefer_server_ciphers on tvingar servern att bestämma vilken cipher-svit som används i stället för att låta klienten välja, vilket skyddar mot att en gammal eller komprometterad klientmjukvara pressar fram ett svagare val. Kombinera det med att lista de starkaste AEAD-sviterna först i ssl_ciphers-raden, så att den faktiska förhandlingen alltid landar i det bästa alternativet båda sidor stödjer. Glöm inte heller att TLS 1.2 och TLS 1.3 hanterar den här förhandlingen olika: TLS 1.3 väljer alltid en av sina fem inbyggda cipher-sviter oavsett vad ssl_ciphers anger, vilket är anledningen till att listan i exemplen ovan enbart påverkar TLS 1.2-anslutningar.
Slutligen, glöm inte bort klientsidan av ekvationen. En härdad server hjälper föga om applikationskoden själv gör utgående anrop med en HTTP-klient som tillåter nedgradering till äldre protokoll eller struntar i certifikatvalidering i testmiljö och sedan råkar följa med till produktion. Granska utgående TLS-konfiguration i era egna API-integrationer med samma noggrannhet som ni granskar den inkommande, särskilt i tjänster som pratar med externa betaltjänster eller myndighets-API:er.
Om infrastrukturen körs i Kubernetes eller bakom en molnleverantörs egna kontroller, koppla TLS-policyerna till plattformens inbyggda styrning. Microsofts Azure Defender for Containers fick i juli 2026 en allmänt tillgänglig funktion som granskar eller blockerar deployningar redan vid admission time om de bryter mot definierade säkerhetsregler, vilket gör det möjligt att stoppa en svag TLS-policy för en ingress-controller innan den ens når klustret. Driver ni API:er genom en gateway, lägg TLS-policyn där också, så slipper varje enskild tjänst duplicera samma konfiguration.
Nedan är strukturen för ett komplett, körbart projekt som samlar alla delar från guiden: installation, skanning, gränsvärden och CI-integration i en och samma mapp.
tls-hardening-projekt/
├── .github/
│ └── workflows/
│ └── tls-scan.yml # Workflow från steg 11 och 13
├── scripts/
│ ├── run_scan.sh # Klonar/uppdaterar testssl.sh och kör skanning
│ └── check_thresholds.py # Skript från steg 12
├── nginx/
│ └── tls-hardened.conf # Konfigurationen från steg 9-10
├── resultat/
│ └── .gitkeep # JSON-resultat sparas här (git-ignorerat)
└── README.md
# scripts/run_scan.sh
#!/usr/bin/env bash
set -euo pipefail
DOMAIN="${1:?Ange en domän, t.ex. ./run_scan.sh din-domän.se}"
if [ ! -d testssl.sh ]; then
git clone --depth 1 https://github.com/testssl/testssl.sh.git
fi
cd testssl.sh
./testssl.sh --jsonfile "../resultat/resultat.json" "$DOMAIN"
cd ..
python3 scripts/check_thresholds.py
Med den strukturen på plats kör en enda kommandorad, ./scripts/run_scan.sh din-domän.se, hela kedjan lokalt precis som CI-jobbet gör i molnet. Det gör det enkelt att felsöka ett CI-fel genom att reproducera exakt samma körning på din egen maskin, i stället för att gissa utifrån loggar. Vill du bredda skanningen till fler lager av stacken, till exempel containerimages som byggs i samma pipeline, kompletterar det bra med vår grundläggande genomgång av HTTPS och TLS.
Vanliga frågor
Är det lagligt att köra testssl.sh mot vilken domän som helst?
Nej. Skanna bara domäner du äger, driftar, eller har skriftligt tillstånd att testa. En TLS-skanning genererar onormal trafik som kan tolkas som ett intrångsförsök av mottagarens säkerhetsövervakning.
Räcker det med Qualys SSL Labs, eller behöver jag testssl.sh också?
SSL Labs ger en bra extern helhetsbild men uppdaterar inte i realtid och saknar en del av de djupare cipher- och sårbarhetstesterna som testssl.sh och sslyze erbjuder. Använd SSL Labs som komplement, inte ersättning.
Varför skiljer sig resultatet mellan testssl.sh och sslyze för samma domän?
De två verktygen bygger på olika versioner av underliggande kryptografiska bibliotek och testar i något olika ordning. Mindre avvikelser är normalt, håll båda uppdaterade och jämför resultatet manuellt om skillnaden är stor.
Måste jag stänga av TLS 1.2 för att få högsta betyg hos SSL Labs?
Nej. TLS 1.2 med rätt cipher-urval och forward secrecy ger fortfarande höga betyg. Det som sänker betyget är svaga chiffer inom TLS 1.2, inte protokollet i sig.
Hur ofta bör jag köra en TLS-skanning i produktion?
Vid varje deploy som rör TLS-relaterad konfiguration, plus en schemalagd körning minst en gång i veckan för att fånga certifikat som närmar sig utgångsdatum eller externa ändringar från CDN- och molnleverantörer.
Kan jag använda samma pipeline för flera domäner?
Ja. Parametrisera GitHub Actions-workflowet med en lista av domäner och kör skanningen i en matrix-strategi, så täcker samma pipeline hela er domänportfölj utan att duplicera koden.
Påverkar TLS-härdning sidans prestanda?
Marginellt, och oftast till det bättre. TLS 1.3 kräver ett round-trip mindre vid handskakning än TLS 1.2, och OCSP stapling minskar extra nätverksanrop. Den enda mätbara kostnaden är CPU för kryptering, vilket moderna processorer med AES-NI hanterar utan problem.
Vad gör jag om testssl.sh och Nginx ger olika svar på vilka chiffer som stöds?
Verifiera vilken OpenSSL-version Nginx faktiskt är länkad mot med nginx -V, eftersom den avgör vilka chiffer som verkligen är tillgängliga oavsett vad som står i konfigurationsfilen. En äldre systeminstallation kan sakna cipher-sviter du försöker aktivera.
Behöver jag härda TLS separat bakom en CDN som Cloudflare?
Ja. En CDN skyddar bara sträckan mellan besökaren och CDN:ns kant. Om anslutningen mellan kanten och din origin-server (så kallad “Full (strict)”-läge hos Cloudflare) inte är korrekt konfigurerad kvarstår hela den bakomliggande sträckan okontrollerad, även om betyget mot den publika domänen ser bra ut.
Vilka gratisverktyg täcker den här guiden, och kostar något av dem pengar?
testssl.sh, sslyze och Qualys SSL Labs är samtliga kostnadsfria och öppna eller fria att använda. GitHub Actions har ett gratis månadskvot för publika och mindre privata repon, vilket räcker för de flesta enskilda domäners skanningsschema i den här guiden.




