Vydělávej až 160.000 Kč měsíčně! Akreditované rekvalifikační kurzy s garancí práce od 0 Kč. Více informací.
Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.

Lekce 18 - Derby DB - Bezpečnost - Zašifrování databáze

V tomto tutoriálu objasníme a předvedeme zabezpečení databáze přes šifrování. Jak to funguje? Nastavíme jej při tvorbě databáze, prakticky pouze přidáme tři parametry. Jedna se o dataEncryption, encryptionAlgorithm a bootPassword. Při tvorbě databáze jsou tyto parametry vzaté DerbyDB v potaz a databáze se vytvoří šifrovaná. Což znamená pouze to, že data která již tak nejsou snadno přístupná se ještě zašifrují. Popis naleznete v DerbySecurity­Guide.pdf. Takže pokud se chcete poté k databázi připojit, je nutné přidat ještě další parametr a další heslo. Jen připomenu pochopitelné vyšší nároky šifrované databáze na systémové prostředky při I/O operací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();
}

Objasnění parametrů připojení

Objasněme si nyní parametry, které jsme použili v připojovacím řetězci v kódu výše:

  • dataEncryption - Umožňuje nastavit pouze true nebo false. true znamená šifrovat a false nešifrovat.
  • encryptionAlgorithm - Nastavení šifrovacího algoritmu v tomto tvaru: algorithmName/feedbackMode/padding. Tento tvar si dále ještě vysvětlíme.
  • bootPassword - Heslo pro šifrovanou databází. Bez tohoto hesla se jednoduše nepřipojíte, pokud je databáze zašifrovaná. Heslo prakticky slouží ke generování šifrovacího klíče o určité délce.
  • encryptionKey - Pokud nechceme používat heslo, lze zadávat přímo šifrovací klíč. Nicméně v článku budeme pracovat s heslem.

Nastavení šifrovacího algoritmu (encryptionAl­gorithm)

Derby podporuje pouze určité šifrovací algoritmy a není jich moc. Pokud chcete vědět více, je v DerbyDB implementovaná podpora pro šifrovací zprostředkovatele, které je nutné nastudovat (tzv. encrypted providers, např. bouncycastle, více viz. JCE - Java Cryptography Extension). Zde případně naleznete seznam různých algoritmů a módů podporovaných např. v Java10 v základním providerem. Jenom připomínám, že různé algoritmy mají různé délky klíčů, pokud chcete využívat klíče.

Při nastavení algoritmu uvádíme:

  • algorithmName - jméno algoritmu (např. DES, DESede, AES, atd...)
  • feedbackMode - mód algoritmu, podporován pouze CBC, CFB, ECB, OFB
  • padding - podporován pouze NoPadding mód

Nastavenení šifrování databáze a připojení přes IJ

Nejdříve si šifrování předvedeme přes konfigurační příkaz IJ. Přihlásíme se a vytvoříme databázi. Pokud spouštíte databázi přes startNetworkServer, pak slovem vypnout je myšleno použít příkaz stopNetworkServer a nikoliv Ctrl + C. Pak se již k dané databázi přihlásíme jako nově vytvoření uživatelé. V mém příkladě se připojuji přímo a tudíž restart databáze se provádí disconnectem:

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;

Nyní je nutné DerbyDB vypnout a znovu zapnout. Tzv. resetovat, protože nastavení šifrování se projeví až po novém spuštění DerbyDB. Pokud se chceme znovu připojit k databázi, příkaz k připojení vypadá takto:

ij> connect 'jdbc:derby:databaze11;user=Uzivatel1;password=Heslo1;bootPassword=hesloDerby';
ij> SELECT * FROM DerbyCRYPT1;
ij> disconnect;
ij> exit;

Pokud chceme změnit heslo u již stávající zašifrované databáze, příkaz k připojení vypadá takto. (Opět je nutno databázi vypnout a znovu zapnout):

ij> connect 'jdbc:derby:databaze11;user=Uzivatel1;password=Heslo1;bootPassword=hesloDerby;newBootPassword=novehesloDerby';
ij> show tables;
ij> disconnect;
ij> exit;

Jak vidíte na přiloženém obrázku, jako první jsem se o připojení pokusil bez zadaného bootPasswordu, spojení zamrzlo. Pomohlo až Ctrl + C. Poté jsem daný parametr vložil a přihlášení proběhlo v pořádku:

IJ nástroj - Derby DB

Nastavenení šifrování databáze a připojení programově

Vytvoříme si i testovací příklad jako Java SE projekt v IDE. V menu vybereme File -> New -> Java Project. Pojmenujeme projekt a nastavíme JRE Java8:

TvorbaProjektu - Derby DB

Přidáme opět externí knihovny do našeho projektu do CLASSPATH. Jedná se o tyto externí knihovny:

  • derbyclient.jar
  • derby.jar
  • derbytools.jar
  • derbyoptionaltools.jar
Nastavení projektu - Derby DB

Níže je vidět řešený zdrojový kód. Přiložený program se dá použít v první části pro připojení a tvorbu šifrované databáze, pak vytvoří tabulku, vloží do ní data a pro kontrolu si je i vypíšeme. V druhé fázi se již připojujeme k funkční databázi a daná data si rovněž 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");
    }
}

Samozřejmě nejdříve musíme spustit DerbyDB server, na který se připojíme. To provedeme skriptem startNetworkServer. Poté necháme proběhnout náš program. Jak vidíte, vše funguje. Po úspěšném proběhnutí musíme DerbyDB opět vypnout a to příkazem stopNetworkServer. Pouze tak docílíme, že se daná databáze zašifruje.

VytvoreniDatabaze - Derby DB

Protože jsme databázi vypnuli, je nutné ji opět spustit pomocí startNetworkServer. Nyní se již lze připojit napřímo k zašifrované databázi a nechat si data uložena v databázi vypsat.

Přečtení dat z zašifrované DerbyDB databáze v Javě - Derby DB

V příští lekci, Derby DB - Bezpečnost - Šifrovaná komunikace SSL/TLS, si pustíme DerbyDB na localhostu.


 

Měl jsi s čímkoli problém? Stáhni si vzorovou aplikaci níže a porovnej ji se svým projektem, chybu tak snadno najdeš.

Stáhnout

Stažením následujícího souboru souhlasíš s licenčními podmínkami

Staženo 2x (6.27 kB)
Aplikace je včetně zdrojových kódů v jazyce Java

 

Předchozí článek
Kvíz - Ukládání a získávání objektů UDT Derby DB v Javě
Všechny články v sekci
Derby DB
Přeskočit článek
(nedoporučujeme)
Derby DB - Bezpečnost - Šifrovaná komunikace SSL/TLS
Článek pro vás napsal Robert Michalovič
Avatar
Uživatelské hodnocení:
Ještě nikdo nehodnotil, buď první!
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