IT rekvalifikácia. Seniorní programátori zarábajú až 6 000 €/mesiac a rekvalifikácia je prvým krokom. Zisti, ako na to!

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 DerbySecurity­Guide.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ť len true alebo false. true znamená šifrovať a false 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 (encryptionAl­gorithm)

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, OFB
  • padding - 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:

IJ nástroj - DerbyDb

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:

TvorbaProjektu - DerbyDb

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
nastavenie projektu - DerbyDb

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.

VytvoreniDatabaze - DerbyDb

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ť.

Prečítanie dát z zašifrované DerbyDB databázy v Jave - DerbyDb

 

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é 3x (6.27 kB)
Aplikácia je vrátane zdrojových kódov v jazyku Java

 

Predchádzajúci článok
Derby DB - Ukladanie / Získanie objektov 2 (User Defined Type)
Všetky články v sekcii
DerbyDb
Preskočiť článok
(neodporúčame)
DERBY DB - Bezpečnosť - Šifrovaná komunikácia SSL / TLS
Článok pre vás napísal Robert Michalovič
Avatar
Užívateľské hodnotenie:
Ešte nikto nehodnotil, buď prvý!
Programuji převážně v Javě SE,EE a trochu nativním C a CUDA. více viz.https://cz.linkedin.com/in/robert-michalovic
Aktivity