API Publicatie Handleiding

Direct publiceren via IIS (zonder DMZ)

Versie 1.0 — Januari 2026

Inhoudsopgave

  1. Overzicht
  2. Wat wordt extern toegankelijk?
  3. Beveiligingslagen
  4. Vereisten
  5. Stap 1: URL Rewrite installeren
  6. Stap 2: URL Rewrite configureren
  7. Stap 3: IP Whitelisting (optioneel)
  8. Stap 4: Rate Limiting configureren
  9. Volledige web.config
  10. Testen
  11. Probleemoplossing

1. Overzicht

Deze handleiding beschrijft hoe u de SQLio API's direct kunt publiceren via IIS, zonder gebruik te maken van een DMZ met reverse proxy. Dit is een eenvoudigere configuratie die geschikt is voor MKB-omgevingen.

Architectuur

Internet
↓ (poort 443)
Firewall
↓
IIS Server met SQLio
↓
SQL Server (intern)

In deze configuratie wordt IIS URL Rewrite gebruikt om te bepalen welke paden extern toegankelijk zijn. Alleen de API endpoints, Swagger documentatie en login pagina worden doorgelaten. De beheer UI blijft afgeschermd voor externe toegang.

Let op: Deze configuratie is acceptabel voor MKB, maar biedt minder "defense in depth" dan een DMZ met reverse proxy. Voor enterprise omgevingen of gevoelige data wordt een DMZ aanbevolen.

2. Wat wordt extern toegankelijk?

Na configuratie zijn alleen de volgende paden extern bereikbaar:

URL Toegankelijk Bescherming
/api/* ✅ Ja Basic Auth + API Key
/api-login ✅ Ja Login formulier
/api-docs ✅ Ja Basic Auth login vereist
/swagger/* ✅ Ja Basic Auth login vereist
/ (UI) ❌ Nee Geblokkeerd door URL Rewrite
/webhooks ❌ Nee Geblokkeerd door URL Rewrite
/environment-configuration ❌ Nee Geblokkeerd door URL Rewrite
/datasets ❌ Nee Geblokkeerd door URL Rewrite

3. Beveiligingslagen

Deze configuratie biedt meerdere beveiligingslagen:

Laag Wat het doet
1. URL Rewrite Alleen /api/*, /api-login, /api-docs extern bereikbaar
2. Rate Limiting Maximaal aantal requests per IP per tijdseenheid
3. IP Whitelist Optioneel: alleen bekende IP-adressen toestaan
4. Basic Auth Login vereist voor Swagger documentatie
5. API Key Elke API call vereist een geldige API key
6. HTTPS Alle verkeer versleuteld

4. Vereisten

Component Versie / Details
Windows Server 2016 of hoger
IIS Geïnstalleerd met ASP.NET Core Hosting Bundle
URL Rewrite Module 2.1 of hoger
Dynamic IP Restrictions IIS Feature (voor rate limiting)
SQLio Geïnstalleerd en werkend
SSL Certificaat Geldig certificaat voor HTTPS

5. Stap 1: URL Rewrite installeren

Download en installatie

Download de URL Rewrite Module van de officiële Microsoft website:

https://www.iis.net/downloads/microsoft/url-rewrite

Of installeer via PowerShell:

# Download en installeer URL Rewrite
$url = "https://download.microsoft.com/download/1/2/8/128E2E22-C1B9-44A4-BE2A-5859ED1D4592/rewrite_amd64_en-US.msi"
Invoke-WebRequest -Uri $url -OutFile "rewrite.msi"
Start-Process msiexec.exe -ArgumentList '/i rewrite.msi /quiet' -Wait

Verificatie

Na installatie verschijnt URL Rewrite in IIS Manager onder de site features.

6. Stap 2: URL Rewrite configureren

De URL Rewrite regels bepalen welke paden extern toegankelijk zijn. Voeg de volgende regels toe aan de web.config in de SQLio root folder.

Basis configuratie

Voeg het volgende toe binnen de <system.webServer> sectie:

<rewrite>
  <rules>
    <!-- Regel 1: API paden toestaan (geen actie) -->
    <rule name="Allow API paths" stopProcessing="false">
      <match url="^(api/|api-login|api-docs|swagger)" />
      <action type="None" />
    </rule>
    
    <!-- Regel 2: Blokkeer niet-API paden voor externe IP's -->
    <rule name="Block external non-API" stopProcessing="true">
      <match url=".*" />
      <conditions logicalGrouping="MatchAll">
        <!-- Niet van intern netwerk -->
        <add input="{REMOTE_ADDR}" 
             pattern="^(192\.168\.|10\.|172\.(1[6-9]|2[0-9]|3[01])\.|127\.0\.0\.1)" 
             negate="true" />
        <!-- En niet een toegestaan API pad -->
        <add input="{REQUEST_URI}" 
             pattern="^/(api/|api-login|api-docs|swagger)" 
             negate="true" />
      </conditions>
      <action type="CustomResponse" 
              statusCode="403" 
              statusReason="Forbidden" 
              statusDescription="Access denied from external network" />
    </rule>
  </rules>
</rewrite>

Hoe werkt het?

Stap Wat er gebeurt
1 Regel 1 checkt of de URL begint met api/, api-login, api-docs of swagger
2 Als ja: geen actie (request gaat door naar applicatie)
3 Regel 2 checkt of het IP-adres NIET van het interne netwerk komt
4 Als extern EN niet een API pad: blokkeer met 403 Forbidden
Tip: De regex pattern voor interne IP's dekt 192.168.x.x, 10.x.x.x en 172.16-31.x.x. Pas dit aan als uw netwerk andere ranges gebruikt.

7. Stap 3: IP Whitelisting (optioneel)

Als u alleen specifieke externe IP-adressen wilt toestaan (bijv. van partners of klanten), kunt u een whitelist toevoegen.

IP Whitelist regel

Voeg deze regel toe vóór de "Block external non-API" regel:

<!-- Optionele IP whitelist voor API toegang -->
<rule name="IP Whitelist for API" stopProcessing="true">
  <match url="^api/" />
  <conditions logicalGrouping="MatchAll">
    <!-- Niet van intern netwerk -->
    <add input="{REMOTE_ADDR}" 
         pattern="^(192\.168\.|10\.|127\.0\.0\.1)" 
         negate="true" />
    <!-- Niet op de whitelist -->
    <add input="{REMOTE_ADDR}" 
         pattern="^(203\.0\.113\.50|198\.51\.100\.25|85\.12\.34\.56)$" 
         negate="true" />
  </conditions>
  <action type="CustomResponse" 
          statusCode="403" 
          statusReason="Forbidden" 
          statusDescription="IP address not allowed" />
</rule>

Whitelist beheren

Voeg IP-adressen toe aan de pattern, gescheiden door | (pipe):

pattern="^(203\.0\.113\.50|198\.51\.100\.25|nieuw\.ip\.adres)$"
Let op: Vergeet niet de punten te escapen in de regex (\. in plaats van .). Dit is vereist in XML configuratie.

8. Stap 4: Rate Limiting configureren

Rate limiting beschermt tegen brute force aanvallen en DDoS. IIS heeft ingebouwde Dynamic IP Restrictions.

Feature installeren

# Installeer IIS IP Security feature
Install-WindowsFeature Web-IP-Security

Configuratie via web.config

Voeg toe binnen de <system.webServer> sectie:

<security>
  <dynamicIpSecurity enableLoggingOnlyMode="false" enableProxyMode="false">
    <!-- Blokkeer bij te veel gelijktijdige requests -->
    <denyByConcurrentRequests enabled="true" maxConcurrentRequests="20" />
    
    <!-- Blokkeer bij te veel requests per tijdseenheid -->
    <denyByRequestRate enabled="true" 
                       maxRequests="50" 
                       requestIntervalInMilliseconds="10000" />
  </dynamicIpSecurity>
</security>

Aanbevolen instellingen

Setting Waarde Toelichting
maxConcurrentRequests 20 Max gelijktijdige requests per IP
maxRequests 50 Max requests per interval
requestIntervalInMilliseconds 10000 10 seconden interval
enableLoggingOnlyMode false Daadwerkelijk blokkeren (niet alleen loggen)
Tip: Bij legitiem hoog verkeer (bijv. bulk imports) kunnen deze limieten te laag zijn. Verhoog de waarden indien nodig, of whitelist specifieke IP's.

9. Volledige web.config

Hieronder staat een complete web.config sectie met alle beveiligingslagen gecombineerd. Voeg dit toe aan of merge met de bestaande web.config in de SQLio folder.

Belangrijk: Maak altijd een backup van de originele web.config voordat u wijzigingen aanbrengt!
<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <system.webServer>
    
    <!-- Rate Limiting -->
    <security>
      <dynamicIpSecurity enableLoggingOnlyMode="false">
        <denyByConcurrentRequests enabled="true" 
                                  maxConcurrentRequests="20" />
        <denyByRequestRate enabled="true" 
                           maxRequests="50" 
                           requestIntervalInMilliseconds="10000" />
      </dynamicIpSecurity>
    </security>
    
    <!-- URL Rewrite: alleen API paden extern -->
    <rewrite>
      <rules>
        <!-- Stap 1: API paden toestaan -->
        <rule name="Allow API" stopProcessing="false">
          <match url="^(api/|api-login|api-docs|swagger)" />
          <action type="None" />
        </rule>
        
        <!-- Stap 2: Optionele IP whitelist voor API -->
        <!--
        <rule name="IP Whitelist" stopProcessing="true">
          <match url="^api/" />
          <conditions logicalGrouping="MatchAll">
            <add input="{REMOTE_ADDR}" 
                 pattern="^(192\.168\.|10\.)" negate="true" />
            <add input="{REMOTE_ADDR}" 
                 pattern="^(203\.0\.113\.50)$" negate="true" />
          </conditions>
          <action type="CustomResponse" statusCode="403" />
        </rule>
        -->
        
        <!-- Stap 3: Blokkeer rest voor externe IP's -->
        <rule name="Block non-API external" stopProcessing="true">
          <match url=".*" />
          <conditions logicalGrouping="MatchAll">
            <add input="{REMOTE_ADDR}" 
                 pattern="^(192\.168\.|10\.|172\.(1[6-9]|2[0-9]|3[01])\.|127\.0\.0\.1)" 
                 negate="true" />
            <add input="{REQUEST_URI}" 
                 pattern="^/(api/|api-login|api-docs|swagger)" 
                 negate="true" />
          </conditions>
          <action type="CustomResponse" 
                  statusCode="403" 
                  statusReason="Forbidden" 
                  statusDescription="Access denied" />
        </rule>
      </rules>
    </rewrite>
    
  </system.webServer>
</configuration>

10. Testen

Na configuratie moet u testen of de beveiliging correct werkt.

Interne tests (vanuit intern netwerk)

Test Verwacht resultaat
Browse naar https://sqlio.bedrijf.nl/ ✅ SQLio UI (Windows Auth popup)
Browse naar https://sqlio.bedrijf.nl/webhooks ✅ Webhook pagina
Browse naar https://sqlio.bedrijf.nl/api-docs ✅ Swagger login of Swagger UI
API call naar /api/test ✅ 401 (zonder credentials) of 200 (met credentials)

Externe tests (vanuit internet)

Test vanaf een extern IP-adres (bijv. via mobiel netwerk of externe server):

Test Verwacht resultaat
Browse naar https://api.bedrijf.nl/ ❌ 403 Forbidden
Browse naar https://api.bedrijf.nl/webhooks ❌ 403 Forbidden
Browse naar https://api.bedrijf.nl/api-login ✅ Login pagina
Browse naar https://api.bedrijf.nl/api-docs ✅ Redirect naar login pagina
API call naar /api/test ✅ 401 of 200 (afhankelijk van credentials)

Rate limiting test

# PowerShell: stuur 100 requests snel achter elkaar
1..100 | ForEach-Object { 
    try {
        Invoke-WebRequest -Uri "https://api.bedrijf.nl/api/test" -Method GET -TimeoutSec 5
    } catch {
        Write-Host "Request $_`: $($_.Exception.Response.StatusCode)"
    }
}

# Na ~50 requests zou u 403 moeten krijgen
Gelukt! Als alle tests slagen, is uw SQLio API correct geconfigureerd voor externe toegang.

11. Probleemoplossing

Probleem Mogelijke oorzaak Oplossing
403 op alle requests URL Rewrite fout Check regex patterns, controleer backslash escaping
UI bereikbaar van extern Regel volgorde incorrect Zorg dat Block regel NA Allow regel komt
Rate limit te snel bereikt Waarden te laag Verhoog maxRequests en interval
IP whitelist werkt niet Pattern fout Test regex op regex101.com
500 errors web.config syntax fout Valideer XML syntax
Interne toegang geblokkeerd IP range niet correct Voeg uw interne IP range toe aan de pattern

Failed Request Tracing

Schakel Failed Request Tracing in om te zien welke regels worden toegepast:

# In IIS Manager:
# 1. Selecteer de SQLio site
# 2. Klik op "Failed Request Tracing Rules"
# 3. Klik "Add..." en voeg regel toe voor status code 403
# 4. Schakel Failed Request Tracing in (rechterkolom: "Edit Site Tracing")
# 5. Logs staan in: %SystemDrive%\inetpub\logs\FailedReqLogFiles

URL Rewrite logs

Voeg tijdelijk logging toe om te zien welke regels matchen:

<!-- Voeg toe aan rewrite sectie voor debugging -->
<rewrite>
  <rules>
    <!-- Voeg logCondition toe aan uw regels -->
    <rule name="Debug logging" stopProcessing="false">
      <match url=".*" />
      <serverVariables>
        <set name="HTTP_X_DEBUG_IP" value="{REMOTE_ADDR}" />
        <set name="HTTP_X_DEBUG_URI" value="{REQUEST_URI}" />
      </serverVariables>
      <action type="None" />
    </rule>
    <!-- ... rest van uw regels ... -->
  </rules>
</rewrite>
Tip: Bekijk ook de IIS logs in C:\inetpub\logs\LogFiles voor gedetailleerde request informatie.