18. diel - Derby DB - Bezpečnosť - Šifrovanie databázy
V minulej lekcii, Derby DB - Ukladanie / Získanie objektov 2 (User Defined Type) , sme sa venovali ukladanie objektov. V nasledujúcich niekoľkých článkoch si predvedieme rôzne spôsoby zabezpečenia DerbyDB.
V tomto tutoriále objasníme a predvedieme zabezpečenia databázy cez
šifrovanie. Ako to funguje? Nastavíme ho pri tvorbe databázy, prakticky iba
pridáme tri parametre. Jedna sa o dataEncryption
,
encryptionAlgorithm
a bootPassword
. Pri tvorbe
databázy sú tieto parametre vzaté DerbyDB do úvahy a databázy sa vytvorí
šifrované. Čo znamená len to, že dáta ktoré už tak nie sú ľahko
prístupné sa ešte zašifrujú. Popis nájdete v DerbySecurityGuide.pdf.
Takže ak sa chcete potom k databáze pripojiť, je nutné pridať ešte
ďalšie parameter a ďalšie heslo. Len pripomeniem pochopiteľné vyššie
nároky šifrované databázy na systémové prostriedky pri I / O
operáciách.
/** Zde provedeme vytvoreni zasifrovane databaze **/ try { connect = DriverManager.getConnection("jdbc:derby:C:/Program Files/JavaJDK08/db/bin/databazeSifr;create=true;user=Uzivatel;password=Heslo;" + "dataEncryption=true;encryptionAlgorithm=Blowfish/CBC/NoPadding;bootPassword=mojeHeslo"); System.out.println("Databaze se podarila vyrobit"); } catch (IOException e) { System.out.println("Databaze se nepodarila vyrobit"); e.printStackTrace(); }
Objasnenie parametrov pripojenia
Objasnime si teraz parametre, ktoré sme použili v reťazci pripojenia v kóde vyššie:
dataEncryption
- Umožňuje nastaviť lentrue
alebofalse
.true
znamená šifrovať afalse
Nešifrovať.encryptionAlgorithm
- Nastavenie šifrovacieho algoritmu v tomto tvare:algorithmName/feedbackMode/padding
. Tento tvar si ďalej ešte vysvetlíme.bootPassword
- Heslo pre šifrovanú databáz. Bez tohto hesla sa jednoducho nepripojíte, ak je databáza zašifrovaná. Heslo prakticky slúži na generovanie šifrovacieho kľúča o určitej dĺžke.encryptionKey
- Pokiaľ nechceme používať heslo, je možné zadávať priamo šifrovací kľúč. Avšak v článku budeme pracovať s heslom.
Nastavenie šifrovacieho algoritmu (encryptionAlgorithm)
Derby podporuje iba určité šifrovacie algoritmy a nie je ich moc. Ak chcete vedieť viac, je v DerbyDB implementovaná podpora pre šifrovacie sprostredkovateľa, ktoré je nutné naštudovať (tzv. Encrypted providers, napr. BouncyCastle, viac viď. JCE - Java Cryptography Extension). Tu prípadne nájdete zoznam rôznych algoritmov a módov podporovaných napr. V Java10 v základnom providerom. Len pripomínam, že rôzne algoritmy majú rôzne dĺžky kľúčov, ak chcete využívať kľúča.
Pri nastavení algoritmu uvádzame:
algorithmName
- meno algoritmu (napr. DES, DESede, AES, atd ...)feedbackMode
- mód algoritmu, podporovaný iba CBC, CFB, ECB, OFBpadding
- podporovaný iba NoPadding mód
Nastavenení šifrovanie databázy a pripojenie cez IJ
Najskôr si šifrovanie predvedieme cez konfiguračný príkaz IJ.
Prihlásime sa a vytvoríme databázu. Ak spúšťate databáze cez
startNetworkServer
, potom slovom vypnúť je myslené použiť
príkaz stopNetworkServer
a nie Ctrl + C.
Potom sa už k danej databáze prihlásime ako novo vytvorenie užívatelia. V
mojom príklade sa pripájam priamo a teda reštart databázy sa vykonáva
Disconnect:
ij> connect 'jdbc:derby:databaze11;create=true;user=Uzivatel1;password=Heslo1;dataEncryption=true;encryptionAlgorithm=Blowfish/CBC/NoPadding; bootPassword=hesloDerby'; ij> CREATE TABLE DerbyCRYPT1(sloupec1 CHAR(10), sloupec2 CHAR(20), sloupec3 INTEGER); ij> INSERT INTO DerbyCRYPT1 VALUES ('text11','text12',7),('text21','text22',6),('text31','text32',14); ij> INSERT INTO DerbyCRYPT1 VALUES ('text41','text42',12),('text51','text52',354),('text61','text62',778); ij> SELECT * FROM DerbyCRYPT1; ij> disconnect; ij> exit;
Teraz je nutné DerbyDB vypnúť a znovu zapnúť. Tzv. resetovať, pretože nastavenie šifrovania sa prejavia až po novom spustení DerbyDB. Ak sa chceme znova pripojiť k databáze, príkaz na pripojenie vyzerá takto:
ij> connect 'jdbc:derby:databaze11;user=Uzivatel1;password=Heslo1;bootPassword=hesloDerby'; ij> SELECT * FROM DerbyCRYPT1; ij> disconnect; ij> exit;
Ak chceme zmeniť heslo u už existujúcej zašifrovanej databázy, príkaz na pripojenie vyzerá takto. (Opäť je nutné databázu vypnúť a znovu zapnúť):
ij> connect 'jdbc:derby:databaze11;user=Uzivatel1;password=Heslo1;bootPassword=hesloDerby;newBootPassword=novehesloDerby'; ij> show tables; ij> disconnect; ij> exit;
Ako vidíte na priloženom obrázku, ako prvý som sa o pripojení pokúsil bez zadaného bootPasswordu, spojenie zamrzlo. Pomohlo až Ctrl + C. Potom som daný parameter vložil a prihlásenie prebehlo v poriadku:
Nastavenení šifrovanie databázy a pripojenia programovo
Vytvoríme si aj testovacie príklad ako Java SE projekt v IDE. V menu vyberieme File -> New -> Java Project. Pomenujeme projekt a nastavíme JRE Java8:
Pridáme opäť externé knižnice do nášho projektu do CLASSPATH. Ide o tieto externé knižnice:
derbyclient.jar
derby.jar
derbytools.jar
derbyoptionaltools.jar
Nižšie je vidieť riešený zdrojový kód. Priložený program sa dá použiť v prvej časti pre pripojenie a tvorbu šifrované databázy, potom vytvorí tabuľku, vloží do nej dáta a pre kontrolu si ich aj vypíšeme. V druhej fáze sa už pripájame k funkčnej databáze a dané dáta si rovnako vypíšeme:
package test; import java.sql.*; public class SifrovanaDatabaze { private static Connection connect = null; private static Statement statement = null; static { try { // nutne pridat do CLASSPATH - derbyclient.jar Class.forName("org.apache.derby.jdbc.ClientDriver").newInstance(); } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) { System.out.println("Problem s nactenim driveru - nutne pridat do CLASSPATH - derbyclient.jar"); } } @SuppressWarnings("unused") private static void pripojeniDatabaze(){ try { connect = DriverManager.getConnection("jdbc:derby:D:/Java/JavaJDK08/db/bin/databaze12;create=true;user=Uzivatel1;password=Heslo1" + ";dataEncryption=true;encryptionAlgorithm=DES/ECB/NoPadding;bootPassword=jineHeslo"); System.out.println("Podarilo se vytvorit databazi12"); statement = connect.createStatement(); } catch (Exception e) { System.err.println("Nepodarilo se vytvorit databazi12"); } } private static void opetovnePripojeni(){ try { connect = DriverManager.getConnection("jdbc:derby:D:/Java/JavaJDK08/db/bin/databaze12;user=Uzivatel1;password=Heslo1;bootPassword=jineHeslo"); System.out.println("Podarilo se pripojit k databazi12"); statement = connect.createStatement(); } catch (Exception e) { System.err.println("Nepodarilo se pripojit k databazi12"); } } @SuppressWarnings("unused") private static void vytvoreniTabulky(String s){ try { statement.executeUpdate("create table "+s+" ( " + " id INT PRIMARY KEY, sloupec1 VARCHAR(20), sloupec2 VARCHAR(20), sloupec3 VARCHAR(20), cislo INT )"); System.out.println("Podarilo se vytvorit tabulku : "+s); } catch (SQLException e) { System.out.println("Nepovedlo se vytvorit tabulku :"); e.printStackTrace(); } } @SuppressWarnings("unused") private static void naplneniDatTabulky(String s){ try { // kazdy executeUpdate provede ulozeni do databaze statement.executeUpdate("INSERT INTO "+s+"(id,sloupec1,sloupec2,sloupec3,cislo) VALUES (1,'text11','text12','text13',11)"); statement.executeUpdate("INSERT INTO "+s+"(id,sloupec1,sloupec2,sloupec3,cislo) VALUES (2,'text21','text22','text23',27)"); statement.executeUpdate("INSERT INTO "+s+"(id,sloupec1,sloupec2,sloupec3,cislo) VALUES (3,'text31','text32','text33',33)"); statement.executeUpdate("INSERT INTO "+s+"(id,sloupec1,sloupec2,sloupec3,cislo) VALUES (4,'text41','text42','text43',42)"); statement.executeUpdate("INSERT INTO "+s+"(id,sloupec1,sloupec2,sloupec3,cislo) VALUES (5,'text51','text52','text53',15)"); statement.executeUpdate("INSERT INTO "+s+"(id,sloupec1,sloupec2,sloupec3,cislo) VALUES (6,'text61','text62','text63',45)"); System.out.println("Podarilo se ulozit data :"); } catch (SQLException e) { System.out.println("Nepovedlo se ulozit data :"); e.printStackTrace(); } } private static void vypisemeDatabazi(String s){ ResultSet odpoved = null; try { odpoved = statement.executeQuery("SELECT * FROM "+s+" ORDER BY id"); System.out.println("Podarilo se ziskat data :"); while(odpoved.next()) { System.out.print(odpoved.getString(2)+"\t"+odpoved.getString(3)+"\t"+odpoved.getString(4)+"\t"+odpoved.getInt(5)+"\n"); } } catch (SQLException e) { System.out.println("Nepovedlo se ziskat data :"); e.printStackTrace(); } } private static void odpojimeDatabazi() { try { if (statement != null) { statement.close(); } if (connect != null) { connect.close(); } System.out.println("\nPodarilo se odpojit od databaze"); } catch (SQLException e) { e.printStackTrace(); } } public static void main(String[] args) { System.out.println("Start programu"); // 1 spusteni - vytvoreni databaze, vlozeni dat a jejich zobrazeni /* pripojeniDatabaze(); vytvoreniTabulky("JinaTabulka"); naplneniDatTabulky("JinaTabulka"); vypisemeDatabazi("JinaTabulka"); */ // 2 spusteni - pripojeni k sifrovane databazi a zobrazeni dat opetovnePripojeni(); vypisemeDatabazi("JinaTabulka"); odpojimeDatabazi(); System.out.println("Konec programu"); } }
Samozrejme najskôr musíme spustiť DerbyDB server, na ktorý sa pripojíme.
To vykonáme skriptom startNetworkServer
. Potom necháme
prebehnúť náš program. Ako vidíte, všetko funguje. Po úspešnom
prebehnutí musíme DerbyDB opäť vypnúť a to príkazom
stopNetworkServer
. Iba tak docielime, že sa daná databázy
zašifruje.
Pretože sme databázu vypli, je nutné ju opäť spustiť pomocou
startNetworkServer
. Teraz sa už možno pripojiť napriamo k
zašifrovanej databáze a nechať si dáta uložené v databáze vypísať.
Mal si s čímkoľvek problém? Stiahni si vzorovú aplikáciu nižšie a porovnaj ju so svojím projektom, chybu tak ľahko nájdeš.
Stiahnuť
Stiahnutím nasledujúceho súboru súhlasíš s licenčnými podmienkami
Stiahnuté 2x (6.27 kB)
Aplikácia je vrátane zdrojových kódov v jazyku Java