Kusto lekérdezésnyelv a Microsoft Sentinelben

Kusto lekérdezésnyelv az a nyelv, amellyel a Microsoft Sentinelben dolgozhat és kezelhet adatokat. A munkaterületre betáplálási naplók nem sokat érnek, ha nem tudja elemezni őket, és az összes adatban elrejti a fontos információkat. Kusto lekérdezésnyelv nemcsak az információk beszerzésének ereje és rugalmassága, hanem az egyszerűség is segít a gyors kezdésben. Ha rendelkezik szkriptkészítési vagy adatbázis-kezelő háttérrel, a cikk sok tartalma ismerősnek fogja érezni magát. Ha nem, ne aggódjon, mivel a nyelv intuitív természete gyorsan lehetővé teszi, hogy saját lekérdezéseket írjon, és értéket teremtsen a szervezet számára.

Ez a cikk bemutatja a Kusto lekérdezésnyelv alapjait, amelyek a leggyakrabban használt függvényeket és operátorokat ismertetik, amelyek a naponta írandó lekérdezések 75–80 százalékát fogják érinteni. Ha részletesebbre vagy összetettebb lekérdezésekre van szüksége, kihasználhatja a Microsoft Sentinel új speciális KQL-jének előnyeit (lásd ezt a bevezető blogbejegyzést). Lásd még a hivatalos Kusto lekérdezésnyelv dokumentációt, valamint számos online kurzust (például a Pluralsightot).

Háttér – Miért Kusto lekérdezésnyelv?

A Microsoft Sentinel az Azure Monitor szolgáltatásra épül, és az Azure Monitor Log Analytics-munkaterületeit használja az összes adat tárolására. Ezek az adatok a következők bármelyikét tartalmazzák:

  • külső forrásokból előre definiált táblákba a Microsoft Sentinel adatösszekötők használatával betöltött adatok.
  • külső forrásokból felhasználó által definiált egyéni táblákba betöltött adatok, egyénileg létrehozott adatösszekötők, valamint néhány beépített összekötőtípus használatával.
  • a Microsoft Sentinel által létrehozott és végrehajtott elemzésekből származó adatok – például riasztások, incidensek és UEBA-adatok.
  • a Microsoft Sentinelbe feltöltött adatok, hogy segítsenek az észlelésben és az elemzésben – például fenyegetésfelderítési hírcsatornák és figyelőlisták.

Kusto lekérdezésnyelv az Azure Data Explorer szolgáltatás részeként fejlesztették ki, ezért felhőalapú környezetben található big data-tárolókban való keresésre van optimalizálva. Jacques Cousteau híres tenger alatti felfedező által inspirált (és ennek megfelelően "koo-STOH"-nak is kihangsúlyozott) úgy tervezték, hogy segítsen mélyen belemerülni az adatok óceánjaiba és felfedezni rejtett kincseiket.

Kusto lekérdezésnyelv az Azure Monitorban (és így a Microsoft Sentinelben) is használják, beleértve néhány további Azure Monitor-funkciót is, amelyek lehetővé teszik az adatok lekérését, vizualizációját, elemzését és elemzését a Log Analytics-adattárakban. A Microsoft Sentinelben Kusto lekérdezésnyelv alapuló eszközöket használ, amikor adatokat vizualizál és elemez, és fenyegetéseket keres, akár meglévő szabályokban és munkafüzetekben, akár saját buildelésben.

Mivel Kusto lekérdezésnyelv része szinte mindennek, amit a Microsoft Sentinelben tesz, a működés egyértelmű megértése segít abban, hogy még többet kihozza a SIEM-ből.

Mi az a lekérdezés?

A Kusto lekérdezésnyelv lekérdezések csak olvasható kérések az adatok feldolgozására és az eredmények visszaadására – nem ír adatokat. A lekérdezések az SQL-hez hasonló adatbázisok, táblák és oszlopok hierarchiájába rendezett adatokon működnek.

A kérések egyszerű nyelven vannak megadva, és egy adatfolyam-modellt használnak, amely megkönnyíti a szintaxis olvasását, írását és automatizálását. Ezt részletesen is látni fogjuk.

Kusto lekérdezésnyelv lekérdezések pontosvesszővel elválasztott utasításokból állnak. Sokféle utasítás létezik, de csak két széles körben használt típust tárgyalunk itt:

  • A táblázatos kifejezési utasítások azok, amelyeket általában a lekérdezésekről beszélünk – ezek a lekérdezés tényleges törzse. A táblázatos kifejezési utasításokról fontos tudni, hogy táblázatos bemenetet (táblázatot vagy más táblázatos kifejezést) fogadnak el, és táblázatos kimenetet hoznak létre. Ezek közül legalább egy szükséges. A cikk többi része ezt a fajta állítást fogja tárgyalni.

  • Az utasítások lehetővé teszik változók és állandók létrehozását és definiálását a lekérdezés törzsén kívül, a könnyebb olvashatóság és sokoldalúság érdekében. Ezek nem kötelezőek, és az adott igényektől függnek. Ezt a fajta állítást a cikk végén fogjuk kezelni.

Bemutató környezet

Az Azure Portalon egy Log Analytics-bemutató környezetben gyakorolhatja Kusto lekérdezésnyelv utasításokat – beleértve a cikkben szereplőket is. Ennek a gyakorlókörnyezetnek a használata díjmentes, de a hozzáféréshez Azure-fiókra van szüksége.

Ismerkedjen meg a bemutatókörnyezettel. A Log Analyticshez hasonlóan az éles környezetben is számos módon használható:

  • Válasszon ki egy táblát, amelyre lekérdezést szeretne készíteni. Az alapértelmezett Táblák lapon (a bal felső sarokban látható piros téglalapban) válasszon ki egy táblázatot a témakörök szerint csoportosított táblák listájából (a bal alsó sarokban látható). Bontsa ki a témaköröket az egyes táblák megtekintéséhez, és az egyes táblák további kibontásával megtekintheti az összes mezőt (oszlopot). Ha duplán kattint egy táblára vagy egy mezőnévre, az a kurzor helyére kerül a lekérdezési ablakban. Írja be a lekérdezés többi részét a tábla neve után, az alábbiak szerint.

  • Keresse meg a tanulmányozni vagy módosítani kívánt meglévő lekérdezést. Válassza a Lekérdezések lapot (a bal felső sarokban látható piros téglalapban látható) a választható lekérdezések listájának megtekintéséhez. Vagy válassza a Lekérdezések lehetőséget a jobb felső sarokban lévő gombsávon. A Microsoft Sentinel beépített lekérdezéseivel ismerkedhet meg. Ha duplán kattint egy lekérdezésre, a teljes lekérdezés a lekérdezési ablakban lesz elhelyezve a kurzor helyén.

    Shows the Log Analytics demo environment.

A bemutatókörnyezethez hasonlóan a Microsoft Sentinel-naplók lapon is lekérdezheti és szűrheti az adatokat. Kijelölhet egy táblát, és lehatolással megtekintheti az oszlopokat. Az oszlopválasztóval módosíthatja az alapértelmezett oszlopokat, és beállíthatja a lekérdezések alapértelmezett időtartományát. Ha az időtartomány explicit módon van definiálva a lekérdezésben, az időszűrő nem lesz elérhető (szürkítve).

Lekérdezési struktúra

A Kusto lekérdezésnyelv megismerésének jó helye az általános lekérdezési struktúra megismerése. A Kusto-lekérdezések során elsőként a csőszimbólum (|) használata jelenik meg. A Kusto-lekérdezések struktúrája azzal kezdődik, hogy az adatokat egy adatforrásból szerzi be, majd átadja az adatokat egy "folyamaton", és minden lépés bizonyos szintű feldolgozást biztosít, majd átadja az adatokat a következő lépésnek. A folyamat végén megkapja a végső eredményt. Valójában ez a folyamat:

Get Data | Filter | Summarize | Sort | Select

Ez az adatátadási koncepció nagyon intuitív struktúrát tesz lehetővé, mivel minden lépésnél könnyű mentális képet készíteni az adatokról.

Ennek szemléltetéséhez tekintsük át az alábbi lekérdezést, amely a Microsoft Entra bejelentkezési naplóit mutatja be. Ahogy végigolvassa az egyes sorokat, láthatja azokat a kulcsszavakat, amelyek jelzik, hogy mi történik az adatokkal. Az egyes sorokban megjegyzésként szerepeltetjük a folyamat megfelelő szakaszát.

Megjegyzés:

A lekérdezés bármely sorához megjegyzéseket fűzhet, ha kettős perjellel (//perjellel) előzi meg őket.

SigninLogs                              // Get data
| evaluate bag_unpack(LocationDetails)  // Ignore this line for now; we'll come back to it at the end.
| where RiskLevelDuringSignIn == 'none' // Filter
   and TimeGenerated >= ago(7d)         // Filter
| summarize Count = count() by city     // Summarize
| sort by Count desc                    // Sort
| take 5                                // Select

Mivel minden lépés kimenete a következő lépés bemenete, a lépések sorrendje meghatározhatja a lekérdezés eredményeit, és befolyásolhatja annak teljesítményét. Fontos, hogy a lépéseket annak megfelelően rendelje meg, hogy mit szeretne kihozni a lekérdezésből.

Tipp.

  • Jó ökölszabály az adatok korai szűrése, így csak a releváns adatokat adja át a folyamaton. Ez jelentősen növeli a teljesítményt, és gondoskodik arról, hogy ne foglalja bele véletlenül az irreleváns adatokat az összegzési lépésekbe.
  • Ez a cikk néhány egyéb ajánlott eljárásra is rámutat, amit érdemes szem előtt tartani. A teljesebb listát a lekérdezés ajánlott eljárásaiban találja.

Remélhetőleg most már megbecsüli a lekérdezések általános szerkezetét Kusto lekérdezésnyelv. Most tekintsük át a lekérdezés létrehozásához használt tényleges lekérdezési operátorokat.

Adattípusok

Mielőtt belevágnánk a lekérdezési operátorokba, először vessünk egy gyors pillantást az adattípusokra. A legtöbb nyelvhez hasonlóan az adattípus határozza meg, hogy milyen számítások és manipulációk futtathatók egy értéken. Ha például egy sztring típusú érték van, nem fog tudni számtani számításokat végezni rajta.

A Kusto lekérdezésnyelv a legtöbb adattípus a szokásos konvenciók szerint történik, és olyan névvel rendelkezik, amelyet korábban valószínűleg látott. Az alábbi táblázat a teljes listát mutatja:

Adattípustábla

Type További név/nevek Egyenértékű .NET-típus
bool Boolean System.Boolean
datetime Date System.DateTime
dynamic System.Object
guid uuid, uniqueid System.Guid
int System.Int32
long System.Int64
real Double System.Double
string System.String
timespan Time System.TimeSpan
decimal System.Data.SqlTypes.SqlDecimal

Bár a legtöbb adattípus standard, előfordulhat, hogy kevésbé ismeri az olyan típusokat, mint a dinamikus, az időkeret és a guid.

A dinamikus szerkezet nagyon hasonlít a JSON-hoz, de egyetlen lényeges különbséggel rendelkezik: képes tárolni Kusto lekérdezésnyelv olyan adattípusokat, amelyeket a hagyományos JSON nem tud, például beágyazott dinamikus értéket vagy időkeretet. Íme egy példa egy dinamikus típusra:

{
"countryOrRegion":"US",
"geoCoordinates": {
"longitude":-122.12094116210936,
"latitude":47.68050003051758
},
"state":"Washington",
"city":"Redmond"
}

Az időkeret egy olyan adattípus, amely az idő mérésére vonatkozik, például órákra, napokra vagy másodpercekre. Ne keverje össze az időidőta dátummal, amely a tényleges dátumot és időt értékeli ki, nem pedig az idő mértékét. Az alábbi táblázat az időtartomány utótagjainak listáját tartalmazza.

Időbélyeg utótagok

Function Leírás
D nap
H óra
M perc során.
S másodperc
Ms ezredmásodperc
Microsecond Mikroszekundum
Tick nanoszekundumok

A GUID egy 128 bites, globálisan egyedi azonosítót képviselő adattípus, amely a [8]-[4]-[4]-[4]-[4]-[12] szabványos formátumot követi, ahol minden [szám] a karakterek számát jelöli, és minden karakter 0-9 vagy a-f között mozoghat.

Megjegyzés:

Kusto lekérdezésnyelv táblázatos és skaláris operátorokkal is rendelkezik. A cikk további részében, ha egyszerűen csak az "operátor" szót látja, feltételezheti, hogy táblázatos operátort jelent, kivéve, ha másként fel van jegyezve.

Adatok lekérése, korlátozása, rendezése és szűrése

A Kusto lekérdezésnyelv alapvető szókincse - az alap, amely lehetővé teszi a feladatok túlnyomó többségének elvégzését - operátorok gyűjteménye az adatok szűréséhez, rendezéséhez és kiválasztásához. A hátralévő feladatok elvégzéséhez a nyelv ismeretének bővítése szükséges a fejlettebb igények kielégítése érdekében. Bontsunk ki egy kicsit néhány parancsot, amelyeket a fenti példában használtunk, és nézzük meg takea , sortés where.

Mindegyik operátor esetében megvizsgáljuk annak használatát az előző SigninLogs-példában , és hasznos tippet vagy ajánlott eljárást ismerünk meg.

Adatok lekérése

Az alapszintű lekérdezések első sora határozza meg, hogy melyik táblával szeretne dolgozni. A Microsoft Sentinel esetében ez valószínűleg egy naplótípus neve lesz a munkaterületen, például SigninLogs, SecurityAlert vagy CommonSecurityLog. Például:

SigninLogs

Vegye figyelembe, hogy Kusto lekérdezésnyelv a naplónevek megkülönböztetik a kis- és nagybetűket, ezért SigninLogssigninLogs másképpen lesznek értelmezve. Ügyeljen az egyéni naplók neveinek kiválasztására, hogy könnyen azonosíthatók legyenek, és ne legyenek túl hasonlóak egy másik naplóhoz.

Adatok korlátozása: korlátozás /

A take operátor (és az azonos korlát operátor) az eredmények korlátozására szolgál, ha csak egy adott számú sort ad vissza. Ezt követi egy egész szám, amely meghatározza a visszaadni kívánt sorok számát. Általában a lekérdezés végén, a rendezési sorrend meghatározása után használják, és ebben az esetben a rendezési sorrend tetején megadott számú sort adja vissza.

A lekérdezés korábbi verzióinak használata take hasznos lehet egy lekérdezés teszteléséhez, ha nem szeretne nagy adathalmazokat visszaadni. Ha azonban a take műveletet bármely sort művelet elé helyezi, take véletlenszerűen kiválasztott sorokat ad vissza , és a lekérdezés futtatásakor esetleg más sorokat is. Íme egy példa a take használatára:

SigninLogs
      | take 5

Screenshot of results of take operator.

Tipp.

Ha egy teljesen új lekérdezésen dolgozik, ahol lehet, hogy nem tudja, hogyan fog kinézni a lekérdezés, hasznos lehet egy utasítást az elején elhelyezni take , hogy mesterségesen korlátozza az adathalmazt a gyorsabb feldolgozás és kísérletezés érdekében. Ha elégedett a teljes lekérdezéssel, eltávolíthatja a kezdeti take lépést.

Adatok rendezése: rendezési / sorrend

A rendezési operátor (és az azonos rendelési operátor) az adatok egy megadott oszlop szerinti rendezésére szolgál. Az alábbi példában a TimeGenerated szerint rendeztük az eredményeket, és a desc paraméterrel csökkenő sorrendbe állítottuk a sorrend irányát, a legmagasabb értékeket helyezve az első helyen; növekvő sorrendben az asc-t használjuk.

Megjegyzés:

A rendezések alapértelmezett iránya csökkenő, ezért gyakorlatilag csak azt kell megadnia, hogy növekvő sorrendben szeretne-e rendezni. A rendezési irány megadása azonban minden esetben olvashatóbbá teszi a lekérdezést.

SigninLogs
| sort by TimeGenerated desc
| take 5

Ahogy már említettük, az operátor elé helyeztük az sort operátort take . Először rendezni kell, hogy biztosan megkapjuk a megfelelő öt rekordot.

Screenshot of results of sort operator, with take limit.

Top

A felső operátor lehetővé teszi, hogy egyetlen operátorban egyesítsük a sorttake műveleteket:

SigninLogs
| top 5 by TimeGenerated desc

Ha két vagy több rekord értéke megegyezik a rendezés alatt lévő oszlopban, további oszlopokat is hozzáadhat a rendezéshez. Adjon hozzá további rendezési oszlopokat egy vesszővel tagolt listában, amely az első rendezési oszlop után, de a rendezési sorrend kulcsszó előtt található. Például:

SigninLogs
| sort by TimeGenerated, Identity desc
| take 5

Most, ha a TimeGenerated több rekord között azonos, akkor megpróbálja rendezni az Identitás oszlopban lévő érték alapján.

Megjegyzés:

Mikor és mikor érdemes használni sorttaketop

  • Ha csak egy mezőre rendez, használjatop, mert jobb teljesítményt nyújt, mint a kombináció és takea sort .

  • Ha egynél több mezőre (például a fenti példában) top kell rendeznie, ezt nem teheti meg, ezért a következőt kell használniasort:take

Adatok szűrése: ahol

A where operátor vitathatatlanul a legfontosabb operátor, mivel ez a kulcs annak biztosításához, hogy csak a forgatókönyv szempontjából releváns adathalmazsal dolgozik. Érdemes a lehető leghamarabb szűrni az adatokat, mert ez javítja a lekérdezés teljesítményét azáltal, hogy csökkenti a további lépésekben feldolgozandó adatok mennyiségét; emellett biztosítja, hogy csak a kívánt adatokon végezzen számításokat. Lásd ezt a példát:

SigninLogs
| where TimeGenerated >= ago(7d)
| sort by TimeGenerated, Identity desc
| take 5

Az where operátor egy változót, egy összehasonlító (skaláris) operátort és egy értéket határoz meg. A mi esetünkben azt használtuk >= , hogy a TimeGenerated oszlop értékének nagyobbnak kell lennie, mint (vagyis későbbi, mint) vagy egyenlőnek kell lennie hét nappal ezelőtt.

A Kusto lekérdezésnyelv kétféle összehasonlító operátor létezik: sztring és numerikus. Az alábbi táblázat a numerikus operátorok teljes listáját mutatja:

Numerikus operátorok

Operátor Leírás
+ Összeadás
- Kivonás
* Szorzás
/ Osztás
% Moduló
< Kisebb mint
> Nagyobb mint
== Egyenlő
!= Nem egyenlő
<= Kisebb vagy egyenlő
>= Nagyobb vagy egyenlő
in Egyenlő az egyik elemével
!in Nem egyenlő az elemek egyikével sem

A sztringoperátorok listája sokkal hosszabb lista, mert permutációkkal rendelkezik a kis- és nagybetűk érzékenységére, az alsztringhelyekre, az előtagokra, az utótagokra és még sok másra. Az == operátor egyszerre numerikus és sztring operátor, ami azt jelenti, hogy számokhoz és szövegekhez egyaránt használható. Például az alábbi utasítások mindegyike érvényes lenne, ha az utasítások:

  • | where ResultType == 0
  • | where Category == 'SignInLogs'

Tipp.

Ajánlott eljárás: A legtöbb esetben valószínűleg több oszlop alapján szeretné szűrni az adatokat, vagy több módon is szűrni szeretné ugyanazt az oszlopot. Ezekben az esetekben két ajánlott eljárást kell szem előtt tartania.

A kulcsszóval több where utasítást is kombinálhat egyetlen lépésben. Például:

SigninLogs
| where Resource == ResourceGroup
    and TimeGenerated >= ago(7d)

Ha több szűrő is csatlakozik egyetlen where utasításhoz a fentihez hasonlóan, jobb teljesítményt érhet el, ha olyan szűrőket helyez el, amelyek csak egyetlen oszlopra hivatkoznak. Így a fenti lekérdezés írásának jobb módja a következő lenne:

SigninLogs
| where TimeGenerated >= ago(7d)
    and Resource == ResourceGroup

Ebben a példában az első szűrő egyetlen oszlopot (TimeGenerated) említ, míg a második két oszlopra hivatkozik (Erőforrás és ResourceGroup).

Adatok összegzése

Az Összegzés az Kusto lekérdezésnyelv egyik legfontosabb táblázatos operátora, de az összetettebb operátorok egyike, amelyből megtudhatja, hogy általánosan új-e a nyelvek lekérdezése. A feladat summarize az, hogy egy adattáblában egy új táblát adjon ki, amelyet egy vagy több oszlop összesít.

Az összegző utasítás felépítése

Az utasítás alapstruktúrája summarize a következő:

| summarize <aggregation> by <column>

Az alábbiak például a Perf tábla minden CounterName értékének rekordszámát adnák vissza:

Perf
| summarize count() by CounterName

Screenshot of results of summarize operator with count aggregation.

Mivel a kimenet summarize egy új tábla, az utasításban summarize nem explicit módon megadott oszlopok nem lesznek átadva a folyamatnak. A koncepció szemléltetéséhez tekintse meg ezt a példát:

Perf
| project ObjectName, CounterValue, CounterName
| summarize count() by CounterName
| sort by ObjectName asc

A második sorban azt adhatja meg, hogy csak az ObjectName, a CounterValue és a CounterName oszlop érdekel. Ezt követően összegzettük, hogy lekérjük a rekordszámot a CounterName alapján, és végül megpróbáljuk növekvő sorrendbe rendezni az adatokat az ObjectName oszlop alapján. Ez a lekérdezés sajnos hibával fog meghiúsulni (ami azt jelzi, hogy az ObjectName ismeretlen), mert összegzéskor csak a Count és a CounterName oszlopokat vettük fel az új táblába. A hiba elkerülése érdekében egyszerűen hozzáadhatjuk az ObjectName nevet a lépés végére summarize , például a következőhöz:

Perf
| project ObjectName, CounterValue , CounterName
| summarize count() by CounterName, ObjectName
| sort by ObjectName asc

A sor beolvasásának módja a summarize következő: "a rekordok számlálónév szerinti összegzése és az ObjectName szerinti csoportosítás". Folytathatja az oszlopok vesszővel elválasztott hozzáadását az summarize utasítás végéhez.

Screenshot of results of summarize operator with two arguments.

Az előző példára építve, ha egyszerre több oszlopot szeretnénk összesíteni, ezt úgy érhetjük el, hogy aggregációkat adunk hozzá az summarize operátorhoz vesszővel elválasztva. Az alábbi példában nem csak az összes rekord számát, hanem a CounterValue oszlop értékeinek összegét is megkapjuk az összes rekordban (amelyek megfelelnek a lekérdezés összes szűrőjének):

Perf
| project ObjectName, CounterValue , CounterName
| summarize count(), sum(CounterValue) by CounterName, ObjectName
| sort by ObjectName asc

Screenshot of results of summarize operator with multiple aggregations.

Összesített oszlopok átnevezése

Ez jó alkalomnak tűnik ezeknek az összesített oszlopoknak az oszlopneveiről beszélni. A szakasz elején azt mondtuk, hogy az summarize operátor egy adattáblát vesz fel, és létrehoz egy új táblát, és csak az utasításban summarize megadott oszlopok folytatják a folyamatot. Ezért ha a fenti példát futtatná, az összesítés eredményül kapott oszlopai count_ és sum_CounterValue.

A Kusto motor automatikusan létrehoz egy oszlopnevet anélkül, hogy explicitnek kellene lennie, de gyakran azt fogja tapasztalni, hogy az új oszlopnak barátságosabb neve lesz. Egyszerűen átnevezheti az oszlopot az summarize utasításban egy új név megadásával, majd az összesítéssel = , például:

Perf
| project ObjectName, CounterValue , CounterName
| summarize Count = count(), CounterSum = sum(CounterValue) by CounterName, ObjectName
| sort by ObjectName asc

Most az összegzett oszlopok neve Count és CounterSum lesz.

Screenshot of friendly column names for aggregations.

Sokkal több van az summarize operátor számára, mint amennyit itt bemutatunk, de érdemes időt szánni a tanulásra, mivel ez kulcsfontosságú összetevője minden olyan adatelemzésnek, amelyet a Microsoft Sentinel-adatokon el szeretne végezni.

Összesítési referencia

A legtöbb aggregációs függvény, de a leggyakrabban használt függvények közül néhány az sum(), count()és avg(). Íme egy részleges lista (lásd a teljes listát):

Aggregátumfüggvények

Function Leírás
arg_max() Egy vagy több kifejezést ad vissza, ha az argumentum teljes méretű
arg_min() Egy vagy több kifejezést ad vissza, ha az argumentum kis méretű
avg() Átlagos értéket ad vissza a csoporton belül
buildschema() A dinamikus bemenet összes értékét elismerő minimális sémát adja vissza
count() A csoport számát adja eredményül.
countif() A csoport predikátumával rendelkező darabszámot adja vissza
dcount() A csoportelemek hozzávetőleges eltérő számát adja vissza
make_bag() Dinamikus értékek tulajdonságcsomagját adja vissza a csoporton belül
make_list() A csoporton belüli összes érték listáját adja vissza
make_set() A csoporton belüli különböző értékek készletét adja vissza
max() A csoport teljes maximális értékét adja eredményül.
min() A csoporton belüli minimális értéket adja eredményül.
percentiles() A csoport percentilis hozzávetőleges értékét adja vissza
stdev() A csoport szórását adja vissza
sum() A csoport elemeinek összegét adja eredményül.
take_any() Véletlenszerű, nem üres értéket ad vissza a csoport számára
variance() A csoport varianciáját adja vissza

Kiválasztás: oszlopok hozzáadása és eltávolítása

Amikor elkezd többet dolgozni a lekérdezésekkel, előfordulhat, hogy több információval rendelkezik, mint amennyire szüksége van a témákban (vagyis túl sok oszlop van a táblában). Vagy lehet, hogy több információra van szüksége, mint amennyivel rendelkezik (vagyis olyan új oszlopot kell hozzáadnia, amely más oszlopok elemzési eredményeit fogja tartalmazni). Vizsgáljuk meg az oszlopmanipuláció legfontosabb operátorait.

Projekt és projekteltávol

A Project nagyjából egyenértékű számos nyelv kijelölési utasításaival. Így kiválaszthatja, hogy mely oszlopokat tartsa meg. A visszaadott oszlopok sorrendje megegyezik az utasításban szereplő oszlopok sorrendjének megfelelően, ahogyan az ebben a példában project látható:

Perf
| project ObjectName, CounterValue, CounterName

Screenshot of results of project operator.

Ahogy el tudja képzelni, ha nagyon széles adathalmazokkal dolgozik, előfordulhat, hogy sok oszlopot meg szeretne tartani, és az összes név megadása sok gépelést igényelne. Ezekben az esetekben a projekteltávolodás lehetővé teszi, hogy megszüntesse az eltávolítandó oszlopokat ahelyett, hogy azokat megtartja, például:

Perf
| project-away MG, _ResourceId, Type

Tipp.

Hasznos lehet két helyen használni project a lekérdezésekben, az elején és a végén. A lekérdezés korai szakaszának használatával project javíthatja a teljesítményt azáltal, hogy eltávolítja azokat a nagy adattömböket, amelyeket nem kell átadnia a folyamatnak. Ha ismét a végén használja, eltávolíthatja az előző lépésekben esetleg létrehozott és a végső kimenetben nem szükséges oszlopokat.

Kiterjesztése

Az Extend egy új számított oszlop létrehozásához használható. Ez akkor lehet hasznos, ha számítást szeretne végezni a meglévő oszlopokon, és minden sor kimenetét látni szeretné. Tekintsünk meg egy egyszerű példát, amelyben egy Kbytes nevű új oszlopot számítunk ki, amelyet az MB-érték (a meglévő Mennyiség oszlopban) 1024-gyel való megszorzásával tudunk kiszámítani.

Usage
| where QuantityUnit == 'MBytes'
| extend KBytes = Quantity * 1024
| project ResourceUri, MBytes=Quantity, KBytes

Az utasítás utolsó sorában project átneveztük a Quantity oszlopot Mbytes-re, így könnyen megállapíthatjuk, hogy melyik mértékegység releváns az egyes oszlopokhoz.

Screenshot of results of extend operator.

Érdemes megjegyezni, hogy a extend már számított oszlopokkal is működik. Hozzáadhatunk például egy további, Bájtok nevű oszlopot, amely kbytes-ből van kiszámítva:

Usage
| where QuantityUnit == 'MBytes'
| extend KBytes = Quantity * 1024
| extend Bytes = KBytes * 1024
| project ResourceUri, MBytes=Quantity, KBytes, Bytes

Screenshot of results of two extend operators.

Táblák összekapcsolása

A Microsoft Sentinelben végzett munkája nagy része egyetlen naplótípussal végezhető el, de vannak olyan esetek, amikor össze szeretné hasonlítani az adatokat, vagy egy másik adatkészleten szeretne keresni. A legtöbb lekérdezési nyelvhez hasonlóan a Kusto lekérdezésnyelv is kínál néhány operátort, amelyek különböző típusú illesztések végrehajtására szolgálnak. Ebben a szakaszban a leggyakrabban használt operátorokat unionjoinés a .

Unió

Az Egyesítő csak két vagy több táblát vesz fel, és az összes sort visszaadja. Például:

OfficeActivity
| union SecurityEvent

Ez az OfficeActivity és a SecurityEvent tábla összes sorát visszaadja. Union néhány paramétert kínál, amelyek az egyesítő viselkedésének módosítására használhatók. A két legfontosabb a forrás és a fajta:

OfficeActivity
| union withsource = SourceTable kind = inner SecurityEvent

A withsource paraméterrel megadhatja egy új oszlop nevét, amelynek értéke egy adott sorban annak a táblának a neve lesz, amelyből a sor származik. A fenti példában elneveztük a SourceTable oszlopot, és a sortól függően az érték vagy OfficeActivity vagy SecurityEvent lesz.

A másik megadott paraméter típus volt, amelynek két lehetősége van: belső vagy külső. A fenti példában belső értéket adtunk meg, ami azt jelenti, hogy a egyesítés során csak azok az oszlopok maradnak meg, amelyek mindkét táblában léteznek. Másik lehetőségként, ha külső értéket adtunk volna meg (ez az alapértelmezett érték), akkor a rendszer mindkét tábla összes oszlopát visszaadja.

Csatlakozás

Az illesztés hasonlóan unionműködik, kivéve, ha ahelyett, hogy új táblázatot hoznánk létre, sorokat illesztünk össze, hogy új táblát hozzunk létre. A legtöbb adatbázisnyelvhez hasonlóan többféle illesztés is elvégezhető. Az a függvény join általános szintaxisa a következő:

T1
| join kind = <join type>
(
               T2
) on $left.<T1Column> == $right.<T2Column>

Az join operátor után megadhatja, hogy milyen típusú illesztéseket szeretnénk végrehajtani, majd egy nyitott zárójelet. A zárójelek között adja meg az összekapcsolni kívánt táblát, valamint a hozzáadni kívánt táblán lévő többi lekérdezési utasítást. A záró zárójel után a bal oldali kulcsszót ($left) használjuk.<columnName> kulcsszó) és jobb ($right.<columnName>) oszlopokat a == operátorral elválasztva. Íme egy példa egy belső illesztésre:

OfficeActivity
| where TimeGenerated >= ago(1d)
    and LogonUserSid != ''
| join kind = inner (
    SecurityEvent
    | where TimeGenerated >= ago(1d)
        and SubjectUserSid != ''
) on $left.LogonUserSid == $right.SubjectUserSid

Megjegyzés:

Ha mindkét tábla neve megegyezik azoknak az oszlopoknak a nevével, amelyeken illesztést végez, nem kell $left és $right használnia, ehelyett egyszerűen megadhatja az oszlop nevét. A $left és a $right használata azonban explicitebb és általánosan ajánlott eljárásnak számít.

A hivatkozáshoz az alábbi táblázat az elérhető illesztések listáját tartalmazza.

Illesztések típusai

Illesztés típusa Leírás
inner Egyetlen értéket ad vissza mindkét tábla egyező sorainak minden kombinációjához.
innerunique A bal oldali táblából származó sorokat adja vissza a csatolt mező különböző értékeivel, amelyek egyezést tartalmaznak a jobb oldali táblában.
Ez az alapértelmezett meghatározatlan illesztéstípus.
leftsemi A bal oldali táblából származó összes rekordot visszaadja, amelyek egyezéssel rendelkeznek a jobb oldali táblában.
A rendszer csak a bal oldali táblázatból származó oszlopokat adja vissza.
rightsemi A jobb oldali táblából származó összes rekordot visszaadja, amelyek megegyeznek a bal oldali táblában.
A rendszer csak a jobb oldali táblázatból származó oszlopokat adja vissza.
leftanti/
leftantisemi
A bal oldali tábla összes olyan rekordját adja vissza, amelyeknek nincs egyezése a jobb oldali táblában.
A rendszer csak a bal oldali táblázatból származó oszlopokat adja vissza.
rightanti/
rightantisemi
A jobb oldali tábla összes olyan rekordját adja vissza, amely nem egyezik a bal oldali táblával.
A rendszer csak a jobb oldali táblázatból származó oszlopokat adja vissza.
leftouter A bal oldali tábla összes rekordjának visszaadása. A jobb oldali táblázatban nem egyező rekordok esetén a cellaértékek null értékűek lesznek.
rightouter A jobb oldali táblából származó összes rekordot visszaadja. A bal oldali táblázatban nem egyező rekordok esetén a cellaértékek null értékűek lesznek.
fullouter A bal és a jobb oldali táblák összes rekordja egyező vagy sem.
A nem egyező értékek null értékűek lesznek.

Tipp.

Ajánlott, hogy a legkisebb asztala legyen a bal oldalon. Bizonyos esetekben a szabály követése hatalmas teljesítménybeli előnyöket biztosíthat a végrehajtott illesztések típusától és a táblák méretétől függően.

Értékelés

Bizonyára emlékszik, hogy az első példában az egyik sor kiértékelő operátorát láttuk. Az evaluate operátort ritkábban használják, mint azokat, amelyeket korábban érintettünk. Azonban az operátor működésének ismerete evaluate megéri az idejét. Még egyszer, itt van az első lekérdezés, ahol látni evaluate fogja a második sorban.

SigninLogs
| evaluate bag_unpack(LocationDetails)
| where RiskLevelDuringSignIn == 'none'
   and TimeGenerated >= ago(7d)
| summarize Count = count() by city
| sort by Count desc
| take 5

Ez az operátor lehetővé teszi az elérhető beépülő modulok (alapvetően beépített függvények) meghívását. Ezek közül a beépülő modulok közül sok az adatelemzésre összpontosít, például az autoclusterre, a diffpatternsre és a sequence_detect, lehetővé téve a fejlett elemzések elvégzését és a statisztikai anomáliák és kiugró értékek felderítését.

A fenti példában használt beépülő modul neve bag_unpack, és nagyon egyszerűvé teszi a dinamikus adatok egy darabjának felvételét és oszlopokká alakítását. Ne feledje, hogy a dinamikus adatok olyan adattípusok, amelyek nagyon hasonlítanak a JSON-hoz, ahogyan az ebben a példában látható:

{
"countryOrRegion":"US",
"geoCoordinates": {
"longitude":-122.12094116210936,
"latitude":47.68050003051758
},
"state":"Washington",
"city":"Redmond"
}

Ebben az esetben városonként szeretnénk összegezni az adatokat, de a city tulajdonságként szerepel a LocationDetails oszlopban. A városi tulajdonság lekérdezésben való használatához először át kellett alakítanunk egy oszlopba bag_unpack használatával.

Visszatérve az eredeti folyamat lépéseihez, a következőket láttuk:

Get Data | Filter | Summarize | Sort | Select

Most, hogy figyelembe vettük az evaluate operátort, láthatjuk, hogy a folyamat egy új szakaszát jelöli, amely most így néz ki:

Get Data | Parse | Filter | Summarize | Sort | Select

Számos más példa is van az operátorokra és függvényekre, amelyekkel olvashatóbb és módosíthatóbb formátumban elemezhetők az adatforrások. Ezekről – és a többi Kusto lekérdezésnyelv – a teljes dokumentációban és a munkafüzetben is tájékozódhat.

Let utasítás

Most, hogy áttekintettük számos fő operátort és adattípust, foglaljuk össze a Let utasítást, amely nagyszerű módja annak, hogy a lekérdezések könnyebben olvashatók, szerkeszthetők és karbantarthatók legyenek.

Lehetővé teszi egy változó létrehozását és beállítását, vagy egy név hozzárendelését egy kifejezéshez. Ez a kifejezés lehet egyetlen érték, de egy teljes lekérdezés is lehet. Íme egy egyszerű példa:

let aWeekAgo = ago(7d);
SigninLogs
| where TimeGenerated >= aWeekAgo

Itt egy aWeekAgo nevet adtunk meg, és úgy állítottuk be, hogy egyenlő legyen egy időbélyegfüggvény kimenetével, amely egy dátum/idő értéket ad vissza. Ezután pontosvesszővel fejezzük be a let utasítást. Most már rendelkezünk egy új aWeekAgo nevű változóval, amely bárhol használható a lekérdezésben.

Ahogy az imént említettük, let utasítással egy teljes lekérdezést készíthet, és nevet adhat az eredménynek. Mivel a lekérdezési eredmények táblázatos kifejezésekként használhatók a lekérdezések bemeneteként, ezt az elnevezett eredményt táblaként kezelheti egy másik lekérdezés futtatása céljából. Íme egy kis módosítás az előző példában:

let aWeekAgo = ago(7d);
let getSignins = SigninLogs
| where TimeGenerated >= aWeekAgo;
getSignins

Ebben az esetben létrehoztunk egy második let utasítást, amelyben a teljes lekérdezést egy getSignins nevű új változóba csomagoltuk. A korábbiakhoz hasonlóan pontosvesszővel fejezzük be a második let utasítást. Ezután meghívjuk a változót az utolsó sorban, amely lefuttatja a lekérdezést. Figyelje meg, hogy az aWeekAgo-t a második let utasításban tudtuk használni. Ennek az az oka, hogy az előző sorban határoztuk meg; ha felcserélnénk a let utasítást, hogy a getSignins legyen az első, hibaüzenetet kapnánk.

Most már használhatjuk a getSigninst egy másik lekérdezés alapjaként (ugyanabban az ablakban):

let aWeekAgo = ago(7d);
let getSignins = SigninLogs
| where TimeGenerated >= aWeekAgo;
getSignins
| where level >= 3
| project IPAddress, UserDisplayName, Level

Lehetővé teszi , hogy az utasítások nagyobb erőt és rugalmasságot biztosítsanak a lekérdezések rendszerezésében. Definiálhat skaláris és táblázatos értékeket, valamint létrehozhat felhasználó által definiált függvényeket. Ezek igazán jól jöhetnek, ha összetettebb lekérdezéseket szervez, amelyek több csatlakozást is végezhetnek.

Következő lépések

Bár ez a cikk alig karcolta meg a felületet, most már rendelkezik a szükséges alapokkal, és bemutattuk azokat a részeket, amelyeket a leggyakrabban a Microsoft Sentinelben végzett munka elvégzéséhez fog használni.

Speciális KQL a Microsoft Sentinel-munkafüzethez

Használja ki a Kusto lekérdezésnyelv munkafüzetet közvetlenül a Microsoft Sentinelben – a Microsoft Sentinel-munkafüzet speciális KQL-jében. Részletes segítséget és példákat nyújt a mindennapi biztonsági műveletek során valószínűleg előforduló számos helyzethez, és számos, a Kusto-lekérdezéseket használó elemre mutat be kész, beépített példákat. Indítsa el ezt a munkafüzetet a Microsoft Sentinel Munkafüzetek paneljén.

Speciális KQL-keretrendszerbeli munkafüzet – A KQL-hozzáértés használatának elősegítése egy kiváló blogbejegyzés, amely bemutatja, hogyan használhatja ezt a munkafüzetet.

More resources

A Kusto lekérdezésnyelv ismereteinek bővítéséhez és elmélyítéséhez tekintse meg a tanulási, képzési és készségfejlesztő források gyűjteményét.