C# týden November Black Friday
Black Friday je tu! Využij jedinečnou příležitost a získej až 80 % znalostí navíc zdarma! Více zde
Pouze tento týden sleva až 80 % na e-learning týkající se C#

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

Unicorn College Tento obsah je dostupný zdarma v rámci projektu IT lidem.
Vydávání, hosting a aktualizace umožňují jeho sponzoři.

V minulé lekci, Derby DB - Ukládání/Získání objektů 2 (User Defined Type), jsme se věnovali ukládání objektů. V následujících několika článcích si předvedeme různé způsoby zabezpečení DerbyDB.

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.

Tento výukový obsah pomáhají rozvíjet následující firmy, které dost možná hledají právě tebe!

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

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

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

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

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ě

 

Stáhnout

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

 

 

Článek pro vás napsal Robert Michalovič
Avatar
Jak se ti líbí článek?
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
Předchozí článek
Derby DB - Ukládání/Získání objektů 2 (User Defined Type)
Všechny články v sekci
DerbyDb
Miniatura
Následující článek
DERBY DB - Bezpečnost - Šifrovaná komunikace SSL/TLS
Aktivity (2)

 

 

Komentáře

Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zatím nikdo nevložil komentář - buď první!