Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 10 additions & 5 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# Dependabot version updates.
# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file

version: 2
updates:
- package-ecosystem: "nuget" # See documentation for possible values
directory: "/src/" # Location of package manifests
# NuGet: "/" lets dotnet discover every manifest (src, tests, samples).
- package-ecosystem: "nuget"
directory: "/"
schedule:
interval: "weekly"

# Keep GitHub Actions (checkout, setup-dotnet, upload-artifact) up to date.
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
27 changes: 21 additions & 6 deletions .github/workflows/dotnet.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,39 @@ name: .NET CI

on:
push:
branches: [ main, master ]
branches: [ main, master, 'claude/**' ]
pull_request:
branches: [ main, master ]
workflow_dispatch:

jobs:
build:
build-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: '8.0.x'
- name: Restore NuGet Packages

- name: Restore
run: dotnet restore
- name: Clean solution
run: dotnet clean

- name: Build
run: dotnet build --configuration Release --no-restore

- name: Test
run: dotnet test --configuration Release --no-build --verbosity normal
run: >-
dotnet test --configuration Release --no-build --verbosity normal
--logger "trx;LogFileName=test-results.trx"
--results-directory ${{ github.workspace }}/TestResults
--collect:"XPlat Code Coverage"

- name: Upload test results
if: always()
uses: actions/upload-artifact@v4
with:
name: test-results
path: ${{ github.workspace }}/TestResults
if-no-files-found: warn
40 changes: 40 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Changelog

Bu projedeki önemli değişiklikler bu dosyada belgelenir.

## [1.1.0] - Yayınlanmadı

### Düzeltildi — koruma doğruluğu (davranış değişikliği)
- **IBAN tip anahtarı uyumsuzluğu.** Tanıyıcı `IBAN` üretirken `Weights`/`RedactTypes` `IBAN_TR` bekliyordu; IBAN'lar ağırlık 1 alıyor ve hiç redakte edilmiyordu. Tüm tip anahtarları tek kaynakta (`PiiTypes`) birleştirildi ve `IBAN` olarak hizalandı. **`appsettings` içinde `Weights`/`RedactTypes` için `IBAN_TR` kullananlar `IBAN` olarak güncellemelidir.**
- **TCKN dil kapısı.** TCKN artık dilden bağımsız tespit edilir; Türkçe diakritik içermeyen (ör. ASCII JSON) gövdelerde de bulunur.
- **Telefon ulusal formatı.** `PhoneRecognizer` artık `+` öneksiz numaraları `DefaultPhoneRegion`/dil bölgesiyle ayrıştırır (`05xx…` gibi numaralar tespit edilir).
- **IBAN boşluklu gösterim.** 4'lü gruplu (boşluklu) IBAN'lar tespit edilir.
- **Adres yanlış pozitifleri.** Anahtar sözcükler kelime sınırıyla eşleştirilir (`have→ave`, `katalog→kat` artık eşleşmez).
- **DOB doğrulaması.** Geçersiz (ör. `31.02.2024`) ve gelecekteki tarihler DOB sayılmaz.
- **Kredi kartı.** Regex erken kesmesi giderildi; Troy, Discover, JCB, Maestro, Diners ve 13/19 haneli Visa eklendi.

### Düzeltildi — middleware / HTTP
- Yanıt gövdesi swap'ı `try/finally` ile korunur; downstream exception'da orijinal stream geri yüklenir.
- Block modunda 403 gövdesi istemciye ulaşır; `-Detected` header'ları bloklanan yanıtta temizlenir.
- Redaksiyon sonrası `Content-Length` güncellenir (Kestrel uyuşmazlık hatası giderildi).
- Yanıtlar yalnızca analiz edilebilir içerik türleri için ve `MaxBodySizeBytes`'a kadar tamponlanır; büyük/streaming yanıtlar doğrudan akıtılır (OOM ve SSE bozulması giderildi).
- İstek gövdesi de boyut sınırıyla okunur.
- UTF-8/ASCII olmayan charset'li yanıtlar bozulmasın diye redakte edilmez.
- Risk header'ları `InvariantCulture` ile üretilir; metod filtreleri büyük/küçük harf duyarsızdır.

### Düzeltildi — edge
- Snippet, geçersiz/eksik eşik ve risk header'larını güvenli şekilde ele alır; virgüllü ondalıkları tolere eder; `DATAGUARDIAN_FAIL_MODE=closed` ile fail-closed seçeneği sunar.

### Eklendi
- `PiiTypes` kanonik tip sabitleri.
- `DataGuardianOptions.Validate()` ve başlangıçta konfigürasyon doğrulaması.
- `AddDataGuardian(IConfiguration)` / `AddDataGuardian(Action<>)` ve `UseDataGuardian()` / `UseDataGuardian(Action<>)` overload'ları (DI + IOptions benzeri bağlama).
- Yeni seçenekler: `DefaultPhoneRegion`, `BlockOversizeBodies`, `RedactionHashKey`, `BlockMessage`; `AnalyzableContentTypes`'a `text/html`, `text/csv`.
- Skorlamada çakışma (overlap) çözümü ve risk clamp; açık `0` ağırlığı tipi devre dışı bırakır.
- Entity tip filtreleri artık NER hit'lerine de uygulanır.
- Hash redaksiyonu anahtarlı HMAC-SHA256'ya geçti; Partial maske kısa değerleri tamamen maskeler.
- Kapsamlı test paketi (recognizer + engine + middleware TestHost) ve `docs/` belgeleri.

### Güvenlik
- NER'in v1.x'te redaksiyon için olgun olmadığı belgelendi; skor/etiketleme için kullanılmalı ([docs/recognizers.md](docs/recognizers.md#ner-onnx)).
- Header oracle riski ve öneriler belgelendi ([docs/security.md](docs/security.md)).
177 changes: 58 additions & 119 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,16 @@

[![NuGet Version](https://img.shields.io/nuget/v/Devoplus.DataGuardian)](https://www.nuget.org/packages/Devoplus.DataGuardian) ![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/devoplus/DataGuardian/dotnet.yml) ![GitHub License](https://img.shields.io/github/license/devoplus/DataGuardian) ![Devoplus Open Source](https://img.shields.io/badge/Open_Source-DP?label=Devoplus&labelColor=%23B60017&color=%2319191a)

DataGuardian, ASP.NET Core için **request ve response** gövdelerinde PII/Sensitive Data tespiti yapar, **0–10 risk skoru** üretir, isteğe bağlı olarak **response header yazar, redaksiyon yapar veya bloklar**. Türkçe ve İngilizce dillerini destekler.
DataGuardian, ASP.NET Core için **request ve response** gövdelerinde PII/hassas veri tespiti yapar, **0–10 risk skoru** üretir, isteğe bağlı olarak **response header yazar, redaksiyon yapar veya bloklar**. Türkçe ve İngilizce dillerini destekler.

- ✅ Kural tabanlı dedektörler: TCKN (checksum), IBAN, Kredi Kartı (Luhn), E-posta, Telefon, Tarih, Adres anahtar sözcükleri
- ✅ Kural tabanlı dedektörler: TCKN (checksum), IBAN (mod-97), Kredi Kartı (Luhn + şema), E-posta, Telefon, Tarih, Adres anahtar sözcükleri
- ✅ TR/EN dil tahmini veya `LanguageOverride`
- ✅ Konfigürasyon: ağırlıklar, eşikler, path/metot filtreleri, entity include/exclude, header öneki
- ✅ Aksiyon modları: **Tag**, **Redact** (MaskAll/Partial/Hash), **Block**
- ✅ Opsiyonel **BERT NER (ONNX)**: serbest metinde `PERSON/ADDRESS/...`

> Ayrıntılı belgeler [`docs/`](docs/) klasöründedir. Değişiklik geçmişi için [`CHANGELOG.md`](CHANGELOG.md).

---

## Hızlı Başlangıç
Expand All @@ -20,36 +22,23 @@ dotnet test

cd samples/Devoplus.DataGuardian.SampleApi
dotnet run
# POST JSON to /echo and check headers:
# POST JSON to /echo and check the response headers:
# X-DataGuardian-Request-Risk, X-DataGuardian-Response-Risk
```

### Program.cs kullanım örneği
### Kullanım (DI + konfigürasyon)

Önerilen yol, seçenekleri `appsettings.json`'daki `DataGuardian` bölümünden bağlamaktır:

```csharp
using Devoplus.DataGuardian;

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

var opt = new DataGuardianOptions
{
AnalyzeRequests = true,
AnalyzeResponses = true,
HeaderPrefix = "X-DataGuardian",
Action = ActionMode.Tag, // None | Tag | Redact | Block
BlockAt = -1, // Block modunda eşik
RedactAt = 4.0, // Redact modunda eşik
Redaction = RedactionStyle.MaskAll,
IncludePaths = new() { "/api/" },
ExcludePaths = new() { "/health", "/metrics" },
IncludeMethods = new() { "POST", "PUT" },
ExcludeMethods = new() { "GET" },
EnableNer = false, // ONNX model ekleyince true
// LanguageOverride = "tr"
};

app.UseDataGuardian(opt);
builder.Services.AddDataGuardian(builder.Configuration.GetSection("DataGuardian"));

var app = builder.Build();
app.UseDataGuardian(); // AddDataGuardian ile kaydedilen seçenekleri çözer

app.MapPost("/echo", async (HttpContext ctx) =>
{
Expand All @@ -61,12 +50,31 @@ app.MapPost("/echo", async (HttpContext ctx) =>
app.Run();
```

### Kullanım (kod içinde inline)

```csharp
app.UseDataGuardian(o =>
{
o.Action = ActionMode.Tag; // None | Tag | Redact | Block
o.BlockAt = 8.0; // Block modunda eşik
o.RedactAt = 4.0; // Redact modunda eşik
o.Redaction = RedactionStyle.MaskAll;
o.ExcludePaths = new() { "/health", "/metrics" };
o.EnableNer = false; // ONNX model ekleyince true
// o.LanguageOverride = "tr";
});
```

> Geçersiz bir konfigürasyon (`K <= 0`, `MaxCountPerType < 1`, eşiklerin aralık dışı olması vb.) başlangıçta `ArgumentException` ile **erken** hata verir; sessizce yok sayılmaz.

### Header’lar
- `X-DataGuardian-Request-Risk: 0..10`
- `X-DataGuardian-Request-Risk: 0..10` (nokta ondalık, kültürden bağımsız)
- `X-DataGuardian-Request-Detected: EMAIL=2;PHONE=1;...`
- `X-DataGuardian-Response-Risk: 0..10`
- `X-DataGuardian-Response-Detected: ...`
- `X-DataGuardian-Response-Skip-Reason: ...`
- `X-DataGuardian-Response-Skip-Reason: ...` (ör. `ContentTypeNotAnalyzable`, `BodyTooLarge`, `UnsupportedCharset`, `NoRedactableTypes`)

> **Güvenlik notu:** `-Detected` header’ları hangi PII tiplerinin bulunduğunu açığa vurur. Bunları yalnızca güvenilir iç tüketicilere (ör. edge) verin; dış istemcilere dönen yanıtlarda `EmitHeaders = false` yapın veya güven sınırında temizleyin. Ayrıntı: [`docs/security.md`](docs/security.md).

### Postman ile test örneği
Projede yer alan **Devoplus.DataGuardian.SampleApi** projesini başlatarak Postman üzerinden veri göndererek header'ları test edebilirsiniz.
Expand All @@ -88,15 +96,17 @@ Projede yer alan **Devoplus.DataGuardian.SampleApi** projesini başlatarak Postm
"RedactAt": 4.0,
"Redaction": "MaskAll", // MaskAll | Partial | Hash
"IncludePaths": ["/api/"],
"ExcludePaths": ["/health","/metrics"],
"IncludeMethods": ["POST","PUT"],
"ExcludePaths": ["/health", "/metrics"],
"IncludeMethods": ["POST", "PUT"],
"ExcludeMethods": ["GET"],
"IncludeEntityTypes": [],
"ExcludeEntityTypes": ["ADDRESS"],
"Weights": { "TCKN":10, "CREDIT_CARD":9, "IBAN_TR":8, "DOB":7, "ADDRESS":6, "PHONE":5, "EMAIL":4, "PERSON":3 },
"Weights": { "TCKN": 10, "CREDIT_CARD": 9, "IBAN": 8, "DOB": 7, "ADDRESS": 6, "PHONE": 5, "EMAIL": 4, "PERSON": 3 },
"MaxCountPerType": 5,
"K": 0.15,
"MaxBodySizeBytes": 524288,
"BlockOversizeBodies": false,
"DefaultPhoneRegion": "TR",
"EnableNer": false,
"NerModelPath": "models/kvkk-ner.onnx",
"NerTokenizerPath": "models/tokenizer.json",
Expand All @@ -107,121 +117,50 @@ Projede yer alan **Devoplus.DataGuardian.SampleApi** projesini başlatarak Postm
}
}
```
> `IOptions<DataGuardianOptions>` ile bağlayabilirsiniz.

---

## Cloudflare Snippet / Worker ile Edge’de Uygulama

Cloudflare üzerinde aşağıdaki snippet, **origin’den dönen** DataGuardian header’larını kontrol eder. **Hariç tutulan path’ler** (exclude) dışındaysa ve risk **eşiği aşmışsa**, **403** döndürür.

**Environment Değişkenleri:**

- `DATAGUARDIAN_THRESHOLD` - örn. `8.0`
- `DATAGUARDIAN_HEADER_PREFIX` - varsayılan `X-DataGuardian`
- `DATAGUARDIAN_EXCLUDED_PATHS` - `/health,/metrics,/public`

> Not: Header’lar origin’de üretildiğinden istek bir kez origin’e ulaşır. Request'i uygulama katmanında daha erken durdurmak isterseniz `Action = Block` + `BlockAt` ayarını kullanmanız gerekir.

```js
// edge/dataguardian-snippet.js
export default {
async fetch(request, env, ctx) {
const THRESHOLD = parseFloat(env.DATAGUARDIAN_THRESHOLD ?? "8.0");
const HEADER_PREFIX = env.DATAGUARDIAN_HEADER_PREFIX || "X-DataGuardian";
const EXCLUDED = (env.DATAGUARDIAN_EXCLUDED_PATHS || "/health,/metrics")
.split(",").map(s => s.trim()).filter(Boolean);

const url = new URL(request.url);
if (EXCLUDED.some(p => url.pathname.startsWith(p))) {
return fetch(request);
}

const originResp = await fetch(request);
const reqRisk = originResp.headers.get(`${HEADER_PREFIX}-Request-Risk`);
const resRisk = originResp.headers.get(`${HEADER_PREFIX}-Response-Risk`);
const risk = Math.max(parseFloat(reqRisk ?? "-1"), parseFloat(resRisk ?? "-1"));

if (!Number.isNaN(risk) && risk >= THRESHOLD) {
return new Response("Blocked by DataGuardian policy (edge).", { status: 403 });
}
return originResp;
}
};
```

Tüm seçeneklerin ayrıntısı: [`docs/configuration.md`](docs/configuration.md).

### Hangi yaklaşımı kullanmalıyım?

**Kısa cevap:**
- **Sadece gözlem/uyarı** istiyorsanız → **Origin’de _Tag_ (sadece response header yazar)**
- **Maliyet ve risk kritik** (erken kes) → **Origin’de _Block_**
- **Merkezi politika + çok-çekirdek/origin** → **Edge’de (Cloudflare) blok**
- **En sıkı** senaryo → **Origin’de _Block_ + Edge’de ikinci bariyer**
> **Not:** Entity tip anahtarları tek bir kaynakta (`PiiTypes`) tanımlıdır. `Weights`, `RedactTypes` ve tanıyıcı çıktıları aynı anahtarları kullanır (ör. IBAN için `IBAN`). Bir birim testi bu tutarlılığı sabitler.

---

**Karşılaştırma**

| Kriter | Origin (Middleware) | Edge (Cloudflare Snippet/Worker) |
|---|---|---|
| Bloklama noktası | Uygulama katmanı (erken) | Kullanıcıya en yakın nokta |
| Uygulama maliyeti | Düşer (erken durur) | Origin’e yine gider (header okumak için) |
| Çoklu origin / ortak politika | Zor (her service ayrı ayar) | Kolay (tek yerde politika) |
| Gözlemlenebilirlik | Uygulama logları | Edge logları ile merkezi + Cloudflare Logpush desteği |
| Hata modları | Uygulama hatası etkiler | Origin hatası olsa da Edge karar verebilir |
| Streaming / SSE | İçerik değişmeden önce durdurma/redaksiyon | Çoğu zaman içerik geldikten sonra karar |
| Cache entegrasyonu | App tarafında | Cloudflare Cache ile kolay |
| Rollout / kademeli geçiş | Feature flag ile | Route/hostname bazlı çok kolay |

---

**Ne zaman hangisini seçelim?**

- **Regülasyon-kritik uçlar** (KYC, ödeme, veri ihracı):
→ *Öncelik Origin Block.* `Action=Block`, `BlockAt=…` ile **erken kes**.
Gerekirse **Edge**’de de aynı eşiği uygulayıp ikinci bariyer kur.

- **Tek merkezden yönetim** (çok mikroservis, çok dil/yığın):
→ *Öncelik Edge.*
Snippet/Worker ile **tek yerde politika**. Origin’de **Tag** kullanılır (response header üretir), edge üzerinde bloklama yapılabilir.
---

**Pratik ipuçları**

- **Gözlemleme:** “blok nedenleri” için Cloudflare Worker’a D1 kullanarak *log* eklenebilir.
- **Hata toleransı:** Bir yapılandırma hatası nedeniyle origin header üretmezse Edge "risk yok" varsayabilir **veya** default-deny modunda kullanılabilir.
## Belgeler

| Belge | İçerik |
|---|---|
| [docs/configuration.md](docs/configuration.md) | Tüm seçeneklerin referansı |
| [docs/recognizers.md](docs/recognizers.md) | Tanıyıcılar, ne tespit eder, doğrulama |
| [docs/scoring.md](docs/scoring.md) | Risk skoru formülü |
| [docs/actions.md](docs/actions.md) | Tag / Redact / Block ve redaksiyon stilleri |
| [docs/security.md](docs/security.md) | Güvenlik modeli, sınırlar ve öneriler |
| [docs/edge.md](docs/edge.md) | Cloudflare Snippet/Worker ile edge dağıtımı |
| [docs/contributing.md](docs/contributing.md) | Geliştirme, test, yeni tanıyıcı ekleme |

---

## ONNX NER (Opsiyonel)
`models/` altına:
- `kvkk-ner.onnx`
- `tokenizer.json`
- `labels.txt` (etiket listesi)

`EnableNer = true` yaparak etkinleştirin. Çıktı etiketleriniz `PERSON`, `ADDRESS`, `EMAIL`, `PHONE`, `DATE` vb. olabilir; DataGuardian bunları ağırlıklandırıp risk skoruna dahil eder.
`models/` altına `kvkk-ner.onnx`, `tokenizer.json` ve `labels.txt` ekleyip `EnableNer = true` yaparak etkinleştirin. Çıktı etiketleriniz `PERSON`, `ADDRESS`, `EMAIL`, `PHONE`, `DATE` vb. olabilir; DataGuardian bunları ağırlıklandırıp risk skoruna dahil eder. NER entegrasyonunun bilinen sınırları ve olgunluk durumu için [`docs/recognizers.md`](docs/recognizers.md#ner-onnx) bölümüne bakın.

---

## Roadmap

DataGuardian için planlanan geliştirmeler ve hedefler:

### v1.0 (Mevcut)
- [x] Kural tabanlı PII tespitleri (T.C. kimlik numarası, IBAN, kredi kartı, e-posta, telefon, tarih, adres)
### v1.x (Mevcut)
- [x] Kural tabanlı PII tespitleri (TCKN, IBAN, kredi kartı, e-posta, telefon, tarih, adres)
- [x] Risk skorlaması (0–10) ve header üretimi (`X-DataGuardian-*`)
- [x] Aksiyon modları: **Tag**, **Redact**, **Block**
- [x] Konfigürasyon: path/method filtreleri, entity include/exclude, redaksiyon stili
- [x] Opsiyonel NER entegrasyonu (ONNX)
- [x] DI / `AddDataGuardian` + konfigürasyon bağlama ve başlangıçta doğrulama
- [x] Opsiyonel NER entegrasyonu (ONNX, deneysel)

### v2.0 (Kısa vadeli hedeflenen)
- [ ] .NET Standard 2.0 desteği
- [ ] Edge (Cloudflare) snippet için logging ve metric forwarding
- [ ] JSON-safe redaksiyon (sadece değerleri maskeleme, key’lere dokunmama)
- [ ] JSON-aware redaksiyon (sadece değerleri maskeleme, key’lere dokunmama)
- [ ] Farklı risk içeren veriler için kurallar (VKN, SGK sicil numarası, plaka, pasaport numarası, IP adresi, MAC adresi, konum verileri vb.)
- [ ] Daha gelişmiş dil tespiti (Türkçe–İngilizce dışı diller için destek)
- [ ] NER için token→karakter ofset eşlemesi ve pencereleme (uzun gövdeler)
- [ ] CLI aracı ile dosya/batch analizi (`dataguardian analyze file.json`)

### v3.0 (Uzun vadeli hedeflenen)
Expand All @@ -232,4 +171,4 @@ DataGuardian için planlanan geliştirmeler ve hedefler:
---

## Lisans
MIT © Devoplus
MIT © Devoplus
Loading
Loading