Vastus: Väide: Kui rakenduse tasemel andmeid valideeritakse, siis andmebaasi tasemel pole seda enam vaja teha, sest see on liiga keeruline.
Vastus: Kõik sõltub sellest, kui oluliseks
andmete korrektsust peetakse. Muidugi ei taga kontrollid, et andmed on alati sisuliselt õiged, kuid aitavad vähendada andmebaasi sattuvate ebaõigete andmete hulka. Kui kontroll realiseerida n rakenduses (mida on pidevalt vaja edasiarendada), mis on tehtud m firma poolt (igaühel oma CASE vahendid, dokumenteerimise standardid ja tavad - probleem: kuidas neile kitsenduste olemasolu kõige paremini kommunikeerida) kasutades y erinevat keelt ja kus on z vormi mille kaudu saab andmeid muuta ning kõigele lisaks on veel g skripti, mis laadivad andmebaasi regulaarselt uusi andmeid, siis kontrolli veelkordne teostamine andmebaasi tasemel ei tundugi enam nii suur täiendav pingutus - pealegi kui sellest tõuseb olulist täiendavat kasu.
Teemast hetkeks kõrvale kaldudes - deklaratiivsete reeglite jõustamine pole suurem pingutus kui Java koodi kirjutamine. See võib olla pingutus indiviididele, kes kahe tabeli ühendamise päringu kirjutamiseks peavad pool tundi googeldama. Siinkohal on abiks oma tööjõu parem valimine ja koolitamine. Elav klassik hr Leo Võhandu on öelnud, et umbes 1/3-le inimestest on võimatu deklaratiivset, hulkade töötlemisel põhinevat keelt korralikult selgeks õpetada - nad ei saa sellest aru ja ei hakkagi kunagi korralikult aru saama. Õpetamise praktikuna võin seda väidet kinnitada.
Andmebaasi taseme kontrollidest pole võimalik meelega mööda hiilida või kogemata "mööda tuigerdada".
Ma ei ole kindlasti andmete rakenduse tasemel valideerimise vastu, sest see võimaldab anda kasutajale kiiremat ja selgemat tagasisidet ning vähendada võrguliiklust, sest leitud ebakorrektseid andmeid ei hakata üle võrgu saatma. Kuid kaitse (kui kaitstavat objekti tahetakse tõesti kogu hingest kaitsta) peaks olema mitmekihiline - kui üks kiht veab alt, siis on veel vähemalt üks kiht, mis löögi vastu võtab ja tagasi põrgatab. Autol panete uksed lukku, panete eraldi rooliluku panete kõigele lisaks veel signalisatsiooni peale. Mõni jätab isegi kurja koera autosse. Keegi ei tule selle pealegi, et seda oleks "liiga palju". Kui rakenduses x jäi vormile y kontroll peale panemata, siis testimisel tekib veateade ja kohe on selge, et vormi juures on jäänud midagi tegemata.
Möönan, et kitsenduste kontrolli realiseerimine lisaks andmebaasile ka rakendustes tähendab lisatööd ja dubleerimist. Kontrolliloogika dubleerimisega tekivad samad probleemid kui andmete liiasusega - muudatusi tuleb teha mitmes kohas (st tööd on rohkem) ning kui muudatusi ei tehta kõigis vajalikes kohtades, siis tulemuseks on süsteemi erinevate osade vastuoluline käitumine.
Lisaks andmete valideerimisele on veel põhjuseid, miks andmebaasi tasemel deklareeritud kitsendused osutuvad kasulikuks. Möönan, et järgnevate võimaluste kasutuselevõtu osas on tänapäeva tarkvarasüsteemidel veel palju ära teha.
- Andmekäitluskeele lausete (päringud ja andmemuudatused) optimeerimine ja automaatne lihtsustamine. Eesmärgiks on saavutada lausete kiirem täitmine. Kitsendused annavad andmebaasisüsteemile infot andmebaasis olevate andmete tähenduse kohta ja selle info alusel saaks andmebaasisüsteem asendada nii mõnegi käivitatava lause oluliselt lihtsama kuid semantiliselt samaväärse lausega. Sellise semantilise teisendamise
esimeseks pääsukeseks on tabelite elimineerimise teisendus,
mida muuhulgas toetavad PostgreSQL ja Oracle.
- Arendussüsteemides, mille puhul genereeritakse rakendus andmebaasi põhjal (nagu näiteks Oracle APEX), saaks põhimõtteliselt teha nii, et andmebaasi tasemel jõustatud ja süsteemikataloogis talletatud kitsenduste põhjal luuakse automaatselt rakenduse kood, mis samuti kitsenduse täidetust kontrollib. Näiteks APEX puhul võiks automaatselt tekkida tabeli alusel loodud lehega seotud Valideerimised (validations). Omaette keerukus tõuseb muidugi sellest, kuidas taolises olukorras kitsenduste muudatusi sünkroniseerida.
- Kitsendused aitavad andmebaasisüsteemil mõista andmete tähendust ja aitavad seda teha ka arendajatel. Sisuliselt dokumenteerivad need andmetele esitatavaid nõudeid - see on eriti kasulik olukorras kus dokumentatsiooni peaaegu ei ole või on sellel lastud vananeda.
- Samuti annavad kitsendused olulist infot, mille alusel otsida andmebaasi skeemist automaatselt mitmesuguseid disainivigu (näiteks erinevate SQL-andmebaasi disaini antimustrite esinemisi). Vigu saab
otsida päringutega andmebaasi süsteemikataloogi põhjal.
- Kui rakenduse lähtekood on suletud ja sellesse ei ole võimalik muudatusi teha või kui tegemist on pärandkoodiga, mida keegi ei oska/taha muuta, siis on andmebaasi tasemel jõustatud kitsendused viis, kuidas täiendavaid andmete kontrolle ikkagi süsteemi sisse viia.
Väide:
Andmebaasis kontrollide realiseerimine on liiga keeruline.
Vastus: Tõsi - kui kasutada trigereid keerukamate reeglite kontrollimiseks, siis on nendesse
lihtne teha vigu nii, et teatud olukorras laseb kontroll läbi ebakorrektseid andmeid. Samu vigu saab muide teha ka rakenduses. Deklaratiivsete kitsenduste puhul selliseid probleeme ei teki, sest ütlete süsteemile
mida on vaja kaitsta ning süsteem ise valib parima algoritmi
kuidas kontrolli läbi viia. See, et tänapäeva SQL-andmebaasisüsteemid ei võimalda luua üldiseid deklaratiivseid kitsendusi (CREATE ASSERTION) on minu hinnangul üks tänapäeva SQL-andmebaasisüsteemide suuremaid puuduseid. Abi on generaatorsüsteemidest nagu
RuleGen.
Väide: Andmete valideerimine andmebaasi tasemel on halb, sest muudatuste sisseviimiseks peab andmebaasi töö peatama.
Vastus: Võimalused nagu näiteks Online Table Redefinition ja Edition-Based Redefinition aitavad seda probleemi leevendada.
Tänapäeva andmebaasisüsteemid võimaldavad kitsendusi kiiresti sisse ja välja lülitada ning sama saab teha trigeritega. Olen nõus, et paljugi on veel vaja ära teha. Samas mõelge ka sellele, et kitsendus, mille jõustate andmebaasis jõustub kohe loomise järel ja rakendub kõigile muudatustele sõltumata sellest, millisest allikast (rakendusest, skriptist, administreerimise programmist) need pärinevad. Kas see kui jõustatava reegli muutumise tõttu tuleb korraga asendada kõik rakendused uue versiooniga on kuidagi olemuslikult lihtsam ja parem? Kas see kui erinevates sama baasi kasutavates rakendustes on realiseeritud erinevad versioonid andmete kontrolli reeglitest (üks rakendus leiab, et isikukood peab olema Eesti isikukood; teist rakendust on juba uuendatud ja see lubab Eesti ning Läti isikukoode) on olemuslikult hea? Toodi näide selle kohta, et on vaja hakata registreerima ka Läti ja Leedu isikukoodiga isikuid. Kena! Andmebaasist kitsenduse kustutamine või kitsenduse väljalülitamine võtab vaid hetke. Kas tõesti leiate, et sama asja tegemine m rakenduse z vormis ja lisaks veel g skriptis võtab sama vähe aega?!
Ma võin andmebaasis muuta tabelite struktuuri ja see, et mõne kitsenduse rakenduse tasemel kontroll seetõttu enam ei toimi tuleb välja alles testimisel. Samas andmebaasis on andmebaasiobjektide vahelised seosed andmebaasisüsteemi jälgimise all, info nende kohta on süsteemikataloogis ja a) süsteem ei lase mul teha struktuurimuudatusi, mis viivad mõne teise objekti ebakorrektsesse seisu või b) ma saan nende seoste kohta vähemalt süsteemikataloogist päringutega infot otsida.
Väide: Andmete valideerimine andmebaasi tasemel mõjub halvasti jõudlusele.
Vastus: Suure hulga andmete tabelisse laadimisel on sõltuvalt süsteemist võimalik kitsendusi ajutiselt välja lülitada ning laadimise lõppedes uuesti sisse lülitada. Kui Teil on ühe tabeli mitut rida või mitme tabeli ridu hõlmavad kontrollid (näiteks välisvõtme kitsenduse kontroll), siis selle rakenduse tasemel realiseerimine tähendab ikkagi päringuid baasi vastu, vajadusel andmeelementide lukustamist. Mille alusel arvatakse, et selline lahendus on kuidagi jõudluse poolest parem?!
Andmebaaside lisamaterjalide kodulehel on lõputöö Ärireeglite realiseerimine PHP ja PostgreSQLi abil. Tsiteerin selle töö lõppjäreldusi: "Nende uuringute tulemuste põhjal jõuti järeldusele, et enamuse ärireegli tüüpide realiseerimise puhul on PostgreSQLi kasutamine realisatsiooniks mõistlikum, mis tähendab,
et kood on seal lihtsam, kompaktsem ja muudatuste sisseviimisel mugavam. Ka süsteemi töökiirus ärireegli kontrolli läbiviimisel ja realiseerimisel oli suurem. Vigade parandus oli PostgreSQLi puhul tihtipeale kergem, kuid mõningatel juhtudel ei olnud mõlemad süsteemid
võimelised arusaadavalt vea põhjust kuvama. Muudatuste sisseviimine on andmebaasi tasandil kergem selles osas, et siis ei pea muutmist vajavat kohta kaua otsima ning pole vaja ka rakendust toimingusse kaasata: kõik muudatused saab andmebaasis ära teha. Lisaks pakub andmebaas palju võimalusi ärireeglite realiseerimiseks, mida PHPs teha ei saa: vaated, domeenid, klassist klassi pärimine (disjoint), trigerid ja muud. Ainult realisatsiooni arendamise käigus kasutatud abiinfo maht oli mõlema realiseerimisviisi puhul piisav ning ka kood oli üldiselt arusaadav."
Paljud andmebaasirakendused on veebirakendused. Nende vastu suunatud levinud rünnakumeetodiks on skriptisüstimine. Ründaja üritab anda veebirakendusele sisendi, et veebilehitseja hakkaks rakenduse kasutamisel käitama tema soovitud koodi. Halva tagamõttega sisend võib tulla nii lõppkasutaja poolt vormidesse sisestatult, kui ka andmebaasist, kus keegi on teinud pahatahtlikke andmemuudatusi. Vastumeetmed andmebaasi tasemel on:
- sisendi valideerimine (SQL-andmebaasis veergudel sobivad tüübid, CHECK kitsendused),
- vaba teksti väljade hulga vähendamine (SQL-andmebaasis klassifikaatori tabelid, välisvõtme kitsendused).
Need on üks osa suuremast meetmete hulgast. Lugege (PHP) veebirakenduste sisendi valideerimise kohta täpsemalt siit.
Kitsenduste andmebaasi tasemel deklaratiivsele jõustamisele tuleks mõelda kohe andmebaasi loomisel, mitte tagantjärgi. Deklaratiivset kitsendust ei saa andmebaasis luua, kui andmebaasis juba olemasolevad andmed ei ole sellega kooskõlas. Kui luua alguses deklaratiivsete kitsendusteta andmebaas ja üritada hiljem deklaratiivseid kitsendusi lisada, siis võite põrkuda probleemiga, et andmebaasi on juba sattunud valideerimata andmeid ja mingit kitsendust ei saa luua. Selliste andmete andmebaasi sattumise põhjuseks võivad olla näiteks:
- vead rakenduste töös,
- rakenduste programmeerijate teadmatus ärireeglitest, mida peab andmete tasemel jõustama
- lõppkasutaja hooletus.
Siis on valikud:
- Hakata olemasolevaid andmeid parandama (võtab aega; sageli pole enam kelleltki küsida, millised peaksid olema paremad andmed). Parandamise järel saab jõustada deklaratiivsed kitsendused.
- Loobuda ühe või teise kitsenduse deklaratiivsest jõustamisest ning realiseerida kontroll kas andmebaasi tasemel rutiinides või trigerites või üldse ainult rakenduses. Selline lahendus võimaldab jätta andmebaasis olemasolevad andmed selliseks nagu need on, kuid vähemasti kontrollida uusi andmeid.
Lõpetuseks - tänapäeval on populaarsust kasvatamas ärireeglite mootorid. Nende kasutamisel on sama eesmärk, mis kitsenduste andmebaasis defineerimisel - võtta süsteemi tööd juhtivad reeglid tarkvarast välja ning muuta need reeglid tsentraalselt hallatavaks. Reeglite muutmine mõjutab kõiki nende reeglite alusel töötavaid rakendusi.
Kokkuvõttes ma jään enda juurde - kitsenduste andmebaasi tasemel jõustamine on kasulik. Alati on erandeid, aga need kinnitavad reeglit erandiga mitte kaetud juhtudel. Lugege palun lisaks seda artiklit!
Mõttearendus andmebaasisüsteemi võimaluste kasutamise kohta PostgreSQL näitel.
2017. aastal avaldati teadusartikkel andmebaasirakenduste vastu suunatud ründemeetodist ACIDRain. See on ründemeetod, mis kasutab ära rakenduste nõrkust, mille korral saab rakendust manipuleerida nii, et selle antud korralduste alusel hakkab andmebaasisüsteem koostama mitteserialiseeritud tööplaane. Nende tööplaanide läbimise tulemusena satuvad andmebaasi olulised andmed, mis ei ole kooskõlas kitsendustega (invariantidega).
Warszawski, T., Bailis, P., 2017. ACIDRain: Concurrency-related attacks on database-backed web applications. In Proceedings of the 2017 ACM International Conference on Management of Data. ACM. pp. 5–20. [WWW] http://www.bailis.org/papers/acidrain-sigmod2017.pdf
Autorid uurisid 12 e-kaubanduse programmi, mida on kokku installeeritud üle kahe miljoni korra. Uuring tuvastas nendes programmides kokku 22 haavatavust, mida saab ACIDRain rünnakuga ära kasutada. Näiteks saab ründaja kasutada kinkekaarte üle etteseatud limiidi ja osta e-poest tasuta kaupu. ACIDRain rünnakute vältimises peavad arendajad tundma transaktsioone, lukustamist, transaktsioonide isolatsioonitasemeid ning oskama neid õiges kohas ja õigel viisil kasutada.
Väidan, et paljud (kui mitte kõik) nendest haavatavustest ei oleks probleemiks, kui andmebaasi tasemel oleksid jõustatud deklaratiivsed kitsendused. Siis ei saa tekkida probleemi, et rakendustes on tulenevalt nende kitsenduste kontrolli ebapiisavast/halvast realiseerimisest võimalik nendest kitsendustest mööda minna. Enamike selliste kitsenduste deklaratiivseks andmebaasi tasemel jõustamiseks oleks vaja SQL-andmebaasides kasutada CREATE ASSERTION lauset, sest nende kitsenduste kontroll hõlmab sama tabeli erinevaid ridu või mitut tabelit. Kuigi CREATE ASSERTION lause on SQL standardis ette nähtud ei toeta seda hetkel mitte ükski laiatarbe SQL-andmebaasisüsteem.