api.ksef.mf.gov.pl — środowisko produkcyjne | Raport techniczny, marzec 2026
| Przedmiot audytu | api.ksef.mf.gov.pl (KSeF 2.0, produkcja) |
| Metoda | Pasywny rekonesans sieciowy + aktywne testy filtracji WAF |
| Data | Marzec 2026 |
| Środowisko testowe | PowerShell 5.1+ / Windows, Play Polska (PL) |
1. Pytanie audytowe
Czy bramkę bezpieczeństwa WAF systemu KSeF obsługuje zagraniczna firma Imperva w chmurze, czy on-premises — i czy chodzi tu o obecne, produkcyjne API KSeF 2.0?
Pytanie dotyczy dwóch kwestii: (a) modelu deploymentu ochrony WAF — cloud vs. on-premises, oraz (b) weryfikacji, czy diagnozowane środowisko jest faktycznym środowiskiem produkcyjnym KSeF 2.0. Audyt odpowiada na oba pytania na podstawie twardych śladów infrastrukturalnych zebranych metodami pasywnymi, uzupełnionymi o aktywne testy zachowania warstwy filtrującej.
2. Metodologia i zakres
Audyt składa się z sześciu kroków pomiarowych wykonanych sekwencyjnie. Kroki 1–4 opierają się na pasywnym rekonesansie (DNS, TLS, HTTP fingerprinting, traceroute, WHOIS/RIPE). Kroki 5–6 to aktywne testy weryfikujące, czy warstwa Impervy aktywnie pośredniczy i filtruje ruch oraz jakie warstwy infrastruktury kryją się za nią.
| Krok | Technika | Cel |
|---|---|---|
| 1 | DNS CNAME — multi-resolver (Google, Cloudflare, system) | Weryfikacja delegacji DNS i trwałości rekordu |
| 2 | Inspekcja certyfikatu TLS (X.509) | Identyfikacja certyfikatu prezentowanego przez edge |
| 3 | Traceroute + ASN / WHOIS / RIPE RDAP | Fizyczna trasa ruchu, przynależność IP, podmioty prawne |
| 4 | HTTP headers fingerprinting (GET, HEAD) | Identyfikacja warstwy WAF i stosu backendowego |
| 5 | POST control vs. POST probe (SQLi, XSS, path traversal) | Dowód aktywnej filtracji ruchu przez WAF |
| 6 | TRACE / HEAD / OPTIONS — wykrywanie warstw | Identyfikacja warstw infrastruktury za Impervą |
3. Krok 1 — Wielopunktowa weryfikacja DNS
3.1 Komenda PowerShell
$hostName = "api.ksef.mf.gov.pl"
$resolvers = @{
"Google (8.8.8.8)" = "8.8.8.8"
"Cloudflare (1.1.1.1)" = "1.1.1.1"
"System (domyślny)" = $null
}
foreach ($label in $resolvers.Keys) {
$params = @{ Name = $hostName; Type = "CNAME" }
if ($resolvers[$label]) { $params["Server"] = $resolvers[$label] }
Resolve-DnsName @params | Select-Object Name, Type, TTL, NameHost | Format-Table
}
3.2 Wynik
=== DNS CNAME via Google (8.8.8.8) ===
api.ksef.mf.gov.pl CNAME 55 hju8yoo.ng.impervadns.net
=== DNS CNAME via System (domyślny) ===
api.ksef.mf.gov.pl CNAME 55 hju8yoo.ng.impervadns.net
=== DNS CNAME via Cloudflare (1.1.1.1) ===
api.ksef.mf.gov.pl CNAME 60 hju8yoo.ng.impervadns.net
3.3 Interpretacja
Wszystkie trzy niezależne resolvery zwracają identyczny cel CNAME: hju8yoo.ng.impervadns.net. CNAME wskazuje na domenę impervadns.net, związaną z infrastrukturą Impervy. Spójność wyniku na trzech niezależnych resolverach wyklucza scenariusz tymczasowego lub lokalnego przekierowania.
Wynik wskazuje na chmurową warstwę edge Impervy jako publiczny front usługi, a nie lokalny front on-premises. Delegacja CNAME do domeny Impervy wskazuje na chmurową warstwę edge jako publiczny front usługi, a nie na lokalny front on-premises.
| Obserwacja | Wartość | Wniosek |
|---|---|---|
| Cel CNAME | hju8yoo.ng.impervadns.net | DNS wskazuje na chmurową warstwę edge Impervy, a nie lokalny front on-premises |
| Spójność resolverów | 3/3 identyczne | Wyklucza tymczasowe lub lokalne przekierowanie |
4. Krok 2 — Inspekcja certyfikatu TLS
4.1 Komenda PowerShell
Add-Type @"
using System.Net; using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
public class CertGrabber {
public static X509Certificate2 GetCert(string host) {
X509Certificate2 captured = null;
var req = (HttpWebRequest)WebRequest.Create("https://" + host + "/");
req.ServerCertificateValidationCallback = (s, cert, chain, err) => {
captured = new X509Certificate2(cert); return true; };
try { req.GetResponse().Close(); } catch {}
return captured; } }
"@
$cert = [CertGrabber]::GetCert("api.ksef.mf.gov.pl")
"Subject: {0}" -f $cert.Subject
"Issuer: {0}" -f $cert.Issuer
"Valid: {0} — {1}" -f $cert.NotBefore, $cert.NotAfter
4.2 Wynik
Subject: CN=*.ksef.mf.gov.pl, O=MINISTERSTWO FINANSÓW, L=Warszawa, C=PL
Issuer: CN=GeoTrust TLS RSA CA G1, OU=www.digicert.com, O=DigiCert Inc, C=US
Valid From: 08.12.2025 01:00:00
Valid To: 08.12.2026 00:59:59
Thumbprint: 6AF8575E9149E4B62C04027912951BFF43A75DEE
4.3 Interpretacja
Certyfikat wildcard *.ksef.mf.gov.pl jest wystawiony na Ministerstwo Finansów przez DigiCert/GeoTrust. Usługa prezentuje ten certyfikat klientom łączącym się z api.ksef.mf.gov.pl — co jest spójne z modelem, w którym warstwa edge posługuje się certyfikatem domeny chronionej. Sam certyfikat nie rozstrzyga modelu zarządzania kluczem prywatnym ani miejsca terminacji TLS.
5. Krok 3 — Trasa ruchu i jurysdykcja węzłów
5.1 Komenda PowerShell
$hostName = "api.ksef.mf.gov.pl"
$targetIP = (Resolve-DnsName $hostName -Type A -Server 8.8.8.8 |
Where-Object { $_.Type -eq "A" } | Select-Object -First 1).IPAddress
tracert -h 20 -w 1000 $hostName
foreach ($ip in @("213.248.77.211","131.125.134.75","45.60.74.103")) {
Invoke-RestMethod "https://rdap.db.ripe.net/ip/$ip" | Select-Object handle, name, country
}
5.2 Wynik
Docelowy IP: 45.60.74.103
1 <1ms 192.168.1.1
2 8ms 10.161.192.1
3 7ms 89-75-3-8.infra.play.pl [89.75.3.8]
4 25ms pl-waw10a-rc1_ae48.0.as9141.pl [185.182.246.0]
5 9ms pl-waw26c-ri1_ae2.0.as9141.pl [185.182.244.29]
6 13ms war-b8-link.ip.twelve99.net [62.115.182.116]
7 24ms hbg-bb2-link.ip.twelve99.net [62.115.141.150]
8 29ms ddf-b3-link.ip.twelve99.net [62.115.135.155]
9 27ms imperva-ic-379643.ip.twelve99-cust.net [213.248.77.211]
10 29ms 131.125.134.75 [Imperva Ltd., IL — blok 131.125.128.0/17]
11 28ms 45.60.74.103 [Incapsula Inc, USA — blok 45.60.0.0/16, AS19551]
5.3 Interpretacja
Ścieżka prowadzi przez infrastrukturę operatorską Arelion/Twelve99 do punktu styku z Impervą. W widocznej trasie pojawia się węzeł imperva-ic-379643.ip.twelve99-cust.net, a następnie dwa adresy z bloków przypisanych w RIPE do podmiotów Impervy: blok 131.125.128.0/17 zarejestrowany na Imperva Ltd. w Izraelu oraz blok 45.60.0.0/16 zarejestrowany na Incapsula Inc w USA.
| IP | Blok CIDR | Podmiot RIPE | Kraj rejestracji |
|---|---|---|---|
| 213.248.77.211 | 213.248.64.0/19 | Twelve99 / Arelion (Telia Carrier) | UE / Szwecja |
| 131.125.134.75 | 131.125.128.0/17 | Imperva Ltd. | Izrael (IL) |
| 45.60.74.103 | 45.60.0.0/16 | Incapsula Inc | USA |
W przeprowadzonym teście latencja do węzła końcowego wyniosła 27–31 ms z Polski. Niska latencja sugeruje, że punkt obsługi ruchu znajduje się geograficznie bliżej Polski niż typowa lokalizacja w kontynentalnych USA, choć bloki IP są zarejestrowane na podmioty z USA i Izraela.
6. Krok 4 — Fingerprinting warstwy HTTP
6.1 Komenda PowerShell
$req = [System.Net.HttpWebRequest]::Create("https://api.ksef.mf.gov.pl/")
$req.Method = "GET"
$req.AllowAutoRedirect = $false
try { $resp = $req.GetResponse() }
catch [System.Net.WebException] { $resp = $_.Exception.Response }
foreach ($key in $resp.Headers.AllKeys) {
"{0,-35} {1}" -f $key, $resp.Headers[$key]
}
6.2 Wynik
GET / → HTTP 302 (Redirect → /docs/v2)
Server: Kestrel
X-CDN: Imperva
X-Iinfo: 62-59611270-59597222 pNNN RT(1773355916122 62) q(0 0 0 5) r(0 0) U11
Set-Cookie: visid_incap_3296082=...; HttpOnly; Secure; SameSite=None
incap_ses_1855_3296082=...; Secure; SameSite=None
6.3 Interpretacja
Odpowiedź HTTP dostarcza trzech niezależnych śladów identyfikujących warstwę Impervy:
- X-CDN: Imperva — jawny fingerprint warstwy edge Impervy.
- Ciasteczka visid_incap_* i incap_ses_* — charakterystyczne dla platformy Incapsula / Imperva.
- X-Iinfo — dodatkowy nagłówek warstwy pośredniej, pojawiający się razem z fingerprintami Impervy.
Nagłówek Server: Kestrel wskazuje, że za warstwą pośrednią znajduje się backend oparty na ASP.NET Core.
7. Krok 5 — Aktywna filtracja: POST control vs. POST probe
7.1 Komenda PowerShell
$auth = "https://api.ksef.mf.gov.pl/api/online/Session/AuthorisationChallenge"
function Invoke-Probe($label, $body, $ct) {
$req = [System.Net.HttpWebRequest]::Create($auth)
$req.Method = "POST"; $req.ContentType = $ct
$req.AllowAutoRedirect = $false; $req.Timeout = 10000
$bytes = [System.Text.Encoding]::UTF8.GetBytes($body)
$req.ContentLength = $bytes.Length
$s = $req.GetRequestStream(); $s.Write($bytes,0,$bytes.Length); $s.Close()
try { $resp = $req.GetResponse() }
catch [System.Net.WebException] { $resp = $_.Exception.Response }
if ($resp) {
$code = [int]$resp.StatusCode
$server = if ($resp.Headers["Server"]) { $resp.Headers["Server"] } else { "(brak)" }
$xcdn = if ($resp.Headers["X-CDN"]) { $resp.Headers["X-CDN"] } else { "(brak)" }
"[{0}] HTTP {1} | Server: {2} | X-CDN: {3}" -f $label,$code,$server,$xcdn
$resp.Close()
} else { "[{0}] Brak odpowiedzi HTTP" -f $label }
}
Invoke-Probe "CONTROL JSON" '{"contextIdentifier":{"type":"onip","identifier":"1234563218"},"documentType":{"version":"FA(2)"},"encryptionKey":null}' "application/json"
Invoke-Probe "CONTROL XML" '<?xml version="1.0"?><AuthorisationChallengeRequest xmlns="http://ksef.mf.gov.pl/schema/gtw/svc/online/auth/request/2021/10/01/0001"><ContextIdentifier><Type>onip</Type><Identifier>1234563218</Identifier></ContextIdentifier></AuthorisationChallengeRequest>' "application/octet-stream"
Invoke-Probe "PROBE SQLi" "id=' OR '1'='1" "application/x-www-form-urlencoded"
Invoke-Probe "PROBE XSS" "<script>alert(1)</script>" "text/plain"
Invoke-Probe "PROBE PATH" "file=../../../../etc/passwd" "application/x-www-form-urlencoded"
7.2 Wynik
[CONTROL JSON] HTTP 404 | Server: Kestrel | X-CDN: Imperva
[CONTROL XML ] HTTP 404 | Server: Kestrel | X-CDN: Imperva
[PROBE SQLi ] Brak odpowiedzi HTTP
[PROBE XSS ] Brak odpowiedzi HTTP
[PROBE PATH ] HTTP 302 | Server: (brak) | X-CDN: (brak)
7.3 Interpretacja
Wynik testów stanowi bezpośredni dowód, że warstwa Impervy nie jest biernym elementem DNS ani ozdobnym CDN-em — aktywnie pośredniczy w ruchu HTTP i filtruje część żądań.
| Żądanie | Kod HTTP | Server | Interpretacja |
|---|---|---|---|
| CONTROL JSON | 404 | Kestrel | Żądanie dotarło do backendu MF — warstwa Impervy przepuściła |
| CONTROL XML | 404 | Kestrel | Żądanie dotarło do backendu MF — warstwa Impervy przepuściła |
| PROBE SQLi | Brak odpowiedzi | (brak) | Połączenie zerwane przed odpowiedzią HTTP — backend MF nie był osiągany |
| PROBE XSS | Brak odpowiedzi | (brak) | Połączenie zerwane przed odpowiedzią HTTP — backend MF nie był osiągany |
| PROBE PATH | 302 | (brak) | Warstwa pośrednia odpowiedziała samodzielnie — backend niewidoczny w odpowiedzi |
Przy żądaniach CONTROL obecność Server: Kestrel potwierdza dotarcie do backendu MF (HTTP 404 oznacza nieznany endpoint, nie błąd WAF). Przy PROBE SQLi i XSS PowerShell zgłosił wyjątek zamkniętego połączenia — jest to zachowanie charakterystyczne dla twardego zerwania połączenia TCP przez WAF (pakiet TCP RST). Taka polityka Drop, w odróżnieniu od odpowiedzi HTTP 403, jest celowym wyborem konfiguracyjnym: WAF nie odpowiada atakującemu żadnym kodem HTTP, oszczędzając zasoby i nie ujawniając faktu blokady. Backend MF nie był w tych przypadkach osiągany. Przy PROBE PATH warstwa pośrednia zwróciła samodzielnie kod 302, a nagłówki Server i X-CDN zniknęły z odpowiedzi.
8. Krok 6 — TRACE i wykrywanie warstw za Impervą
8.1 Komenda PowerShell
$urls = @(
"https://api.ksef.mf.gov.pl/",
"https://api.ksef.mf.gov.pl/docs/v2"
)
foreach ($url in $urls) {
foreach ($method in @("TRACE","HEAD","OPTIONS")) {
$req = [System.Net.HttpWebRequest]::Create($url)
$req.Method = $method
$req.AllowAutoRedirect = $false; $req.Timeout = 8000
try { $resp = $req.GetResponse() }
catch [System.Net.WebException] { $resp = $_.Exception.Response }
if ($resp) {
$server = if ($resp.Headers["Server"]) { $resp.Headers["Server"] } else { "(brak)" }
$xcdn = if ($resp.Headers["X-CDN"]) { $resp.Headers["X-CDN"] } else { "(brak)" }
"{0,-10} {1,-45} → {2} | Server: {3} | X-CDN: {4}" -f $method,$url,[int]$resp.StatusCode,$server,$xcdn
$resp.Close()
}
}
}
8.2 Wynik
TRACE https://api.ksef.mf.gov.pl/ → 405 | Server: Microsoft-Azure-Application-Gateway/v2 | X-CDN: Imperva
HEAD https://api.ksef.mf.gov.pl/ → 405 | Server: Kestrel | X-CDN: Imperva
OPTIONS https://api.ksef.mf.gov.pl/ → 405 | Server: Kestrel | X-CDN: Imperva
TRACE https://api.ksef.mf.gov.pl/docs/v2 → 405 | Server: Microsoft-Azure-Application-Gateway/v2 | X-CDN: Imperva
HEAD https://api.ksef.mf.gov.pl/docs/v2 → 404 | Server: Kestrel | X-CDN: Imperva
OPTIONS https://api.ksef.mf.gov.pl/docs/v2 → 404 | Server: Kestrel | X-CDN: Imperva
8.3 Interpretacja
Wynik jest powtarzalny i spójny na obu ścieżkach. Ujawnia trójwarstwową architekturę edge KSeF.
Metody HEAD i OPTIONS zwracają Server: Kestrel — potwierdzając backend ASP.NET Core widoczny przez warstwę Impervy. Metoda TRACE na obu ścieżkach zwraca natomiast Server: Microsoft-Azure-Application-Gateway/v2 przy jednoczesnej obecności X-CDN: Imperva. Oznacza to, że żądanie TRACE przeszło przez Impervę (X-CDN widoczny), lecz odpowiedź 405 zwróciła wewnętrzna warstwa identyfikująca się jako Azure Application Gateway v2 — ujawniając swoją obecność między Impervą a backendem Kestrel.
| Metoda | Ścieżka | Kod | Server | Interpretacja |
|---|---|---|---|---|
| HEAD | / i /docs/v2 | 405 / 404 | Kestrel | Backend ASP.NET Core widoczny przez warstwę Impervy |
| OPTIONS | / i /docs/v2 | 405 / 404 | Kestrel | Backend ASP.NET Core widoczny przez warstwę Impervy |
| TRACE | / i /docs/v2 | 405 | Microsoft-Azure-Application-Gateway/v2 | Wewnętrzna warstwa Azure ujawnia się — obecna między Impervą a Kestrel |
Różnica w zachowaniu między TRACE a HEAD/OPTIONS wynika z tego, jak poszczególne warstwy obsługują różne metody HTTP. HEAD i OPTIONS są przepuszczane do backendu Kestrel, który odpowiada bezpośrednio. TRACE jest obsługiwany przez Azure Application Gateway przed dotarciem do Kestrel — co powoduje, że to właśnie ta warstwa ujawnia się w odpowiedzi.
9. Zestawienie dowodów
| # | Dowód | Wartość | Znaczenie |
|---|---|---|---|
| 1 | CNAME | hju8yoo.ng.impervadns.net | DNS wskazuje na chmurową warstwę edge Impervy, a nie lokalny front on-premises |
| 2 | Spójność DNS | 3/3 resolverów — identyczny wynik | Wyklucza tymczasowe lub lokalne przekierowanie |
| 3 | X-CDN: Imperva | Nagłówek HTTP odpowiedzi | Jawny fingerprint warstwy edge Impervy |
| 4 | Ciasteczka incap_* | visid_incap_3296082, incap_ses_* | Charakterystyczne dla platformy Incapsula/Imperva |
| 5 | X-Iinfo | Nagłówek warstwy pośredniej | Dodatkowy fingerprint pojawiający się razem ze śladami Impervy |
| 6 | Certyfikat TLS | CN=*.ksef.mf.gov.pl, O=MINISTERSTWO FINANSÓW | Warstwa edge prezentuje certyfikat domeny MF — spójne z modelem cloud WAF |
| 7 | Blok IP tranzytowy | 131.125.128.0/17 — Imperva Ltd. (IL) | Węzeł tranzytowy należy do spółki Impervy zarejestrowanej w Izraelu |
| 8 | Blok IP edge | 45.60.0.0/16 — Incapsula Inc (USA), AS19551 | Węzeł końcowy należy do spółki Impervy zarejestrowanej w USA |
| 9 | Server: Kestrel przy HEAD/OPTIONS | Nagłówki przy HEAD i OPTIONS | Backend MF oparty na ASP.NET Core — widoczny przez warstwę Impervy |
| 10 | POST CONTROL → 404 / Kestrel | CONTROL JSON i XML | Poprawne żądania docierają do backendu MF |
| 11 | POST PROBE → brak odpowiedzi | PROBE SQLi, PROBE XSS | Połączenie zerwane — backend MF nie był osiągany |
| 12 | POST PROBE PATH → 302 / brak Server | PROBE path traversal | Warstwa pośrednia odpowiada samodzielnie — backend niewidoczny |
| 13 | TRACE → Azure App Gateway | Server: Microsoft-Azure-Application-Gateway/v2 + X-CDN: Imperva (powtarzalny na / i /docs/v2) | Potwierdzona dodatkowa warstwa między Impervą a backendem Kestrel |
10. Podsumowanie i wnioski
10.1 Odpowiedź na pytanie audytowe
Audyt wykazał, że api.ksef.mf.gov.pl, czyli produkcyjne API KSeF 2.0, jest wystawione przez chmurową warstwę Impervy. Warstwa ta nie jest biernym wpisem DNS ani ozdobnym CDN-em — aktywnie pośredniczy w ruchu HTTP do backendu KSeF i filtruje część żądań. W widocznej z zewnątrz ścieżce sieciowej pojawiają się adresy IP z bloków przypisanych w rejestrze RIPE do podmiotów Impervy zarejestrowanych w Izraelu i w USA. Powtarzalne testy metodą TRACE ujawniły ponadto dodatkową warstwę infrastruktury identyfikującą się jako Microsoft Azure Application Gateway v2, obecną między Impervą a backendem Kestrel.
10.2 Architektura edge KSeF
[Podatnik / System ERP]
│ HTTPS
▼
[Play Polska → Arelion/Telia — sieć tranzytowa]
│
▼
[Imperva Cloud WAF] rejestracja: USA (Incapsula Inc) + Izrael (Imperva Ltd.)
fingerprint: X-CDN: Imperva, visid_incap_*, incap_ses_*, X-Iinfo
aktywna filtracja:
SQLi / XSS → połączenie zerwane, backend nieosiągany
path traversal → w tym teście: 302 challenge, Server i X-CDN nieobecne w odpowiedzi
│
▼ ← ujawniony przez TRACE (powtarzalny na / i /docs/v2)
[Azure Application Gateway v2]
Server: Microsoft-Azure-Application-Gateway/v2
│
▼
[Kestrel / ASP.NET Core — backend KSeF]
widoczny przy HEAD/OPTIONS i poprawnych POST: Server: Kestrel
10.3 Granice audytu
Audyt obejmuje wyłącznie publicznie dostępną warstwę edge infrastruktury KSeF, zbadaną metodami pasywnego rekonesansu sieciowego uzupełnionymi o aktywne testy filtracji HTTP. Audyt nie weryfikuje architektury wewnętrznej backendu MF, treści umów kontraktowych, faktycznej zawartości przetwarzanych danych ani wewnętrznych polityk bezpieczeństwa MF. Wszystkie wnioski opierają się wyłącznie na dowodach zebranych z publicznie dostępnych źródeł sieciowych.
Ograniczenie metodologiczne: użyta klasa HttpWebRequest negocjuje połączenia przez HTTP/1.1. Infrastruktura Impervy obsługuje HTTP/2 i HTTP/3 (QUIC) — testy z użyciem nowoczesnego klienta (np. curl --http2) mogłyby ujawnić dodatkowe nagłówki specyficzne dla tych protokołów, stanowiąc naturalne rozszerzenie niniejszego audytu.
Wykonanie audytu: Grzegorz GPS Świderski. Sformatowanie tekstu: Sonnet 4.6 Extended.