Derby 安全
在下一章中,我们将提到 Derby 的安全性选项。
我们将在本章中简要提及两个基本安全概念。 用户认证和用户授权。 用户认证正在验证用户凭据,然后再授予对 Derby 系统的访问权限。 用户授权是授予读取和/或写入 Derby 数据库权限的手段。
此外,Derby 允许对磁盘上存储的数据库文件进行加密。 Derby 网络流量可以使用 SSL/TLS 加密协议进行加密。
Derby 默认
默认情况下,Derby 不需要用户认证。 用户名成为程序中的默认架构,并且用户密码将被忽略。 要启用认证,我们必须修改 Derby 属性。 用户授权已关闭。 另外,Derby 没有数据库超级用户。
数据库所有者
数据库所有者是创建数据库的用户。 如果创建数据库时没有提供用户,则数据库所有者将设置为默认授权标识符 APP。 当我们启用 SQL 授权时,控制数据库所有者很重要。
数据库加密
Derby 为我们提供了一种加密磁盘上数据的方法。 引导数据库的用户必须提供启动密码。 创建数据库时可以对其进行加密。 也可以加密现有的未加密数据库。 在加密数据库时,还必须指定启动密码,该密码是用于生成加密键的字母数字字符串。
ij> CONNECT 'jdbc:derby:testdb;create=true;dataEncryption=true;
bootPassword=3344kkllqq**';
创建数据库时,我们可以对其进行加密。 我们将dataEncryption
属性设置为true
,并提供启动密码。 现在,每次启动数据库时,我们都必须提供启动密码。
ij> CONNECT 'jdbc:derby:testdb';
ERROR XJ040: Failed to start database 'testdb' with class loader
sun.misc.Launcher$AppClassLoader@360be0, see the next exception for details.
ERROR XBM06: Startup failed. An encrypted database cannot be accessed without
the correct boot password.
在嵌入式模式下,当我们连接到数据库时,我们还将引导它。 当我们尝试在没有启动密码的情况下连接到加密数据库时,Derby 将显示以上错误消息。
ij> CONNECT 'jdbc:derby:testdb;bootPassword=3344kkllqq**';
ij> SHOW CONNECTIONS;
CONNECTION0* - jdbc:derby:testdb
* = current connection
使用正确的启动密码,我们已成功连接到testdb
数据库。
认证方式
认证限制了对正确用户的访问。 默认情况下,Derby 中的认证处于关闭状态。
Derby 通过三种方式提供认证。
- LDAP 外部认证
- 自定义 Java 类
- 内置系统
Derby 官方文档警告说 Derby 的内置认证机制仅适用于开发和测试目的。 强烈建议生产系统依赖 LDAP 或用户定义的类进行认证。
嵌入
认证可以设置为两个级别。 在系统级别或数据库级别。
ij> CALL SYSCS_UTIL.SYSCS_SET_DATABASE_PROPERTY('derby.user.user12', '34klq*');
0 rows inserted/updated/deleted
ij> CALL SYSCS_UTIL.SYSCS_SET_DATABASE_PROPERTY('derby.connection.requireAuthentication',
'true');
0 rows inserted/updated/deleted
以上两个语句可在数据库级别为当前连接的数据库启用用户认证。 我们使用密码创建了一个用户,并启用了derby.connection.requireAuthentication
属性。
ij> CONNECT 'jdbc:derby:testdb';
ERROR 08004: Connection authentication failure occurred. Reason: Invalid authentication..
ij> CONNECT 'jdbc:derby:testdb;user=user12;password=34klq*';
ij> SHOW CONNECTIONS;
CONNECTION0* - jdbc:derby:testdb
* = current connection
启用用户认证后,当我们要连接到testdb
数据库时,我们必须提供用户凭据。
客户端服务器
在下一个示例中,我们将在客户端/服务器模式下使用 Derby。 我们有一个加密的testdb
数据库。
$ startNetworkServer &
Derby 服务器已启动。
ij> CONNECT 'jdbc:derby://localhost:1527/dbs/testdb;bootPassword=3344kkllqq**';
首次连接testdb
数据库时,必须提供启动密码。 这是因为以前我们已经加密了testdb
数据库。
ij> CONNECT 'jdbc:derby://localhost:1527/dbs/testdb';
ij> SHOW CONNECTIONS;
CONNECTION0* - jdbc:derby://localhost:1527/dbs/testdb
* = current connection
一旦数据库已经启动,我们就不需要以客户端/服务器模式启动数据库。 与嵌入式模式不同,在嵌入式模式下,我们每次都连接到数据库时,也会对其进行引导。
在下一步中,我们将在客户端/服务器模式下启用用户认证。 为此,我们需要编辑derby.properties
文件。
$ stopNetworkServer
首先,如果 Derby 服务器正在运行,我们将其停止。 请注意,启用用户认证后,我们需要提供用户凭据才能停止服务器。 stopNetworkServer
脚本带有-user
和-password
选项。
$ cat dbs/derby.properties
derby.connection.requireAuthentication=true
derby.user.user12=34klq*
derby.authentication.provider=BUILTIN
在 Derby 系统目录中,我们修改derby.properties
文件。 如果文件不存在,我们将创建它。 在属性文件中,我们启用身份验证并使用密码创建用户。 我们还将认证供应器设置为 Derby BUILTIN
。
$ startNetworkServer &
我们启动 Derby 服务器。
$ java -Dderby.system.home=/home/janbodnar/programming/derby/dbs \
-Dij.protocol=jdbc:derby: -jar $DERBY_HOME/lib/derbyrun.jar ij
ij version 10.8
ij>
我们启动ij
工具。
ij> CONNECT 'jdbc:derby:testdb;bootPassword=3344kkllqq**';
ERROR 08004: Connection authentication failure occurred. Reason: Invalid authentication..
我们尝试连接到testdb
数据库。 由于 Derby 服务器已重新启动,因此我们提供了启动密码。 但是,我们看到一条错误消息。 这是因为我们启用了用户认证。 我们还必须提供用户凭据。
ij> CONNECT 'jdbc:derby:testdb;user=user12;password=34klq*;
bootPassword=3344kkllqq**';
使用此连接字符串,我们已成功连接到testdb
数据库。
用户授权
通过 Derby 中的用户授权,可以授予和撤消访问系统,数据库,对象或 SQL 操作的权限。 我们可以在 Derby 中将用户授权属性设置为系统级属性或数据库级属性。
Derby 具有一些影响用户授权的属性。 derby.database.defaultConnectionMode
属性控制默认访问模式。 如果未设置该属性,则该属性默认为fullAccess
,即具有读写访问权限。 其他两个选项是noAccess
和readOnlyAccess
。 通过derby.database.fullAccessUsers
和derby.database.readOnlyAccessUsers
,我们可以控制哪些用户可以读写,哪些用户可以对数据库进行只读访问。 derby.database.sqlAuthorization
属性启用 SQL 标准授权。 当derby.database.sqlAuthorization
属性设置为true
时,对象所有者可以使用GRANT
和REVOKE SQL
语句来设置特定数据库对象或特定 SQL 操作的用户权限。
我们可以授予或撤销的特权是:DELETE
,EXECUTE
,INSERT
,SELECT
,REFERENCES
,TRIGGER
和UPDATE
。
为derby.database.defaultConnectionMode
属性指定的访问模式将覆盖数据库对象所有者授予的权限。
$ cat dbs/derby.properties
derby.connection.requireAuthentication=true
derby.user.user12=34klq*
derby.user.user13=33kl33
derby.user.user14=14kl14
derby.user.user15=35rr++
derby.authentication.provider=BUILTIN
derby.database.defaultConnectionMode=readOnlyAccess
derby.database.fullAccessUsers=user12
我们修改derby.properties
文件。 我们添加了三个用户。 一个用户user12
拥有对数据库的完全访问权限。 其他三个具有默认的只读访问权限。
export DERBY_OPTS=-Dderby.system.home=/home/janbodnar/programming/derby/dbs
请注意,为了使网络服务器知道带有derby.property
的系统目录在哪里,我们将DERBY_OPTS
变量设置为包含 derby 系统目录。
$ stopNetworkServer
$ startNetworkServer &
$ java -Dderby.system.home=/home/janbodnar/programming/derby/dbs \
-Dij.protocol=jdbc:derby: -jar $DERBY_HOME/lib/derbyrun.jar ij
我们重新启动网络服务器并启动ij
工具。
ij> CONNECT 'jdbc:derby://localhost/testdb;user=user13;
password=33kl33;bootPassword=3344kkllqq**';
我们使用user13
用户连接到testdb
数据库。 由于我们是第一次连接数据库,因此我们也将其引导。 因此,我们需要启动密码,因为该数据库先前已加密。
ij> SELECT * FROM USER12.CARS;
ID |NAME |PRICE
------------------------------------------------------
1 |Audi |52642
2 |Mercedes |57127
3 |Skoda |9000
4 |Volvo |29000
5 |Bentley |350000
6 |Citroen |21000
7 |Hummer |41400
8 |Volkswagen |21600
8 rows selected
user13
有权查看位于USER12
模式中的CARS
表中的数据。
ij> INSERT INTO USER12.CARS VALUES(9, 'Toyota', 27000);
ERROR 25502: An SQL data change is not permitted for a read-only connection,
user or database.
但是,尝试修改CARS
表中的数据会导致错误。 未授予执行更改的权限。
ij> DISCONNECT;
ij> CONNECT 'jdbc:derby://localhost/testdb;user=user12;
password=34klq*';
我们关闭连接,并连接为user12
。 该用户在属性文件中具有完全访问权限。 即使user12
是数据库的所有者和CARS
表的所有者,他也不能修改表,除非使用 Derby 属性具有完全访问权限。
ij> INSERT INTO CARS VALUES(9, 'Toyota', 27000);
1 row inserted/updated/deleted
ij> SELECT * FROM CARS WHERE ID = 9;
ID |NAME |PRICE
------------------------------------------------------
9 |Toyota |27000
1 row selected
我们已经成功地在CARS
表中添加了新行。
SQL 授权
数据库或表之类的对象的所有者可以进一步限制使用数据库对象的权限。 我们可以使用GRANT
和REVOKE
语句来授予或撤消权限。 数据库和表的所有者是创建它们的当前用户。 请注意,derby.database.defaultConnectionMode
会覆盖GRANT
语句赋予的权限。 因此,如果用户具有通过默认连接方式指定的readOnlyAccess
,则即使GRANT
语句授予了该权限,该用户也无法修改数据库对象。
当derby.database.sqlAuthorization
属性设置为true
时,对象所有者可以使用GRANT
和REVOKE SQL
语句来设置特定数据库对象或特定 SQL 操作的用户权限。 请注意,在derby.properties
文件中设置系统范围的属性仅对新数据库有效。 对于现有数据库,我们只能设置数据库范围的derby.database.sqlAuthorization
属性。 在将derby.database.sqlAuthorization
属性设置为true
之后,我们无法将该属性设置回false
。
ij> CALL SYSCS_UTIL.SYSCS_SET_DATABASE_PROPERTY('derby.database.sqlAuthorization',
'true');
derby.database.sqlAuthorization
属性已设置为 true。 该属性是静态的。 我们必须重新启动testdb
数据库以使该属性正常工作。
ij> CONNECT 'jdbc:derby://localhost/testdb;shutdown=true;
user=user12;password=34klq*';
ij> CONNECT 'jdbc:derby://localhost/testdb;user=user12;
password=34klq*;bootPassword=3344kkllqq**';
我们关闭了testdb
数据库,然后重新启动它。
ij(CONNECTION1)> GRANT SELECT ON CARS TO user15;
0 rows inserted/updated/deleted
我们向表CARS
的user15
提供SELECT
特权。
ij(CONNECTION1)> UPDATE CARS SET PRICE=27001 WHERE ID=9;
1 row inserted/updated/deleted
ij(CONNECTION1)> SELECT * FROM CARS;
ID |NAME |PRICE
------------------------------------------------------
1 |Audi |52642
2 |Mercedes |57127
3 |Skoda |9000
4 |Volvo |29000
5 |Bentley |350000
6 |Citroen |21000
7 |Hummer |41400
8 |Volkswagen |21600
9 |Toyota |27001
作为表所有者的user12
具有完全特权。 上面的命令确认他在CARS
表上具有UPDATE
和SELECT
特权。
ij(CONNECTION1)> DISCONNECT;
ij> CONNECT 'jdbc:derby://localhost/testdb;user=user14;
password=14kl14';
ij(CONNECTION1)> SELECT * FROM USER12.CARS;
ERROR 42502: User 'USER14' does not have SELECT permission
on column 'ID' of table 'USER12'.'CARS'.
我们从数据库断开连接,并以user14
身份连接。 尝试执行SELECT
语句会导致错误。 user14
不具有对CARS
表中SELECT
数据的特权。
ij(CONNECTION1)> DISCONNECT;
ij> CONNECT 'jdbc:derby://localhost/testdb;user=user15;
password=35rr++';
ij> SELECT * FROM USER12.CARS;
ID |NAME |PRICE
------------------------------------------------------
1 |Audi |52642
2 |Mercedes |57127
3 |Skoda |9000
4 |Volvo |29000
5 |Bentley |350000
6 |Citroen |21000
7 |Hummer |41400
8 |Volkswagen |21600
9 |Toyota |27000
8 rows selected
接下来,我们以user15
连接。 用户可以从CARS
表中选择数据。
ij(CONNECTION1)> SELECT * FROM USER12.AUTHORS;
ERROR 42502: User 'USER15' does not have SELECT
permission on column 'ID' of table 'USER12'.'AUTHORS'.
但是他不能从AUTHORS
表中选择数据。 表所有者user12
没有授予从该表中选择数据的权限。
ij(CONNECTION1)> UPDATE USER12.CARS SET PRICE=27000 WHERE ID=9;
ERROR 25502: An SQL data change is not permitted for a read-only
connection, user or database.
user15
在CARS
表上也没有UPDATE
特权。
在本章中,我们讨论了 Derby 中的安全性选项。