从 H2 控制台访问加密数据库
Posted
技术标签:
【中文标题】从 H2 控制台访问加密数据库【英文标题】:Access encrypted database from H2 console 【发布时间】:2016-04-08 08:49:22 【问题描述】:我想将我的 H2 数据库存储为加密文件并访问其 Web 界面。
我配置了H2数据库,这样我就可以访问web界面来操作console/db
地址下的数据库了。
当我不使用加密时,一切正常。
当我将CIPHER=AES
添加到db.url
时,我无法登录数据库并出现以下异常:
File corrupted while reading record: null. Possible solution: use the recovery tool [90030-191] 90030/90030 (Help)
org.h2.jdbc.JdbcSQLException: Uszkodzenie pliku podczas wczytywania rekordu: null
File corrupted while reading record: null. Possible solution: use the recovery tool [90030-191]
at org.h2.message.DbException.getJdbcSQLException(DbException.java:345)
at org.h2.message.DbException.get(DbException.java:168)
at org.h2.mvstore.db.MVTableEngine$Store.convertIllegalStateException(MVTableEngine.java:195)
at org.h2.mvstore.db.MVTableEngine$Store.open(MVTableEngine.java:167)
at org.h2.mvstore.db.MVTableEngine.init(MVTableEngine.java:99)
at org.h2.engine.Database.getPageStore(Database.java:2460)
at org.h2.engine.Database.open(Database.java:692)
at org.h2.engine.Database.openDatabase(Database.java:270)
at org.h2.engine.Database.<init>(Database.java:264)
at org.h2.engine.Engine.openSession(Engine.java:65)
at org.h2.engine.Engine.openSession(Engine.java:175)
at org.h2.engine.Engine.createSessionAndValidate(Engine.java:153)
at org.h2.engine.Engine.createSession(Engine.java:136)
at org.h2.engine.Engine.createSession(Engine.java:28)
at org.h2.engine.SessionRemote.connectEmbeddedOrServer(SessionRemote.java:349)
at org.h2.jdbc.JdbcConnection.<init>(JdbcConnection.java:107)
at org.h2.jdbc.JdbcConnection.<init>(JdbcConnection.java:91)
at org.h2.Driver.connect(Driver.java:72)
at org.h2.server.web.WebServer.getConnection(WebServer.java:735)
at org.h2.server.web.WebApp.login(WebApp.java:955)
at org.h2.server.web.WebApp.process(WebApp.java:211)
at org.h2.server.web.WebApp.processRequest(WebApp.java:170)
at org.h2.server.web.WebServlet.doGet(WebServlet.java:125)
at org.h2.server.web.WebServlet.doPost(WebServlet.java:162)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:648)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:292)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:121)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:212)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:141)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:616)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:522)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1095)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:672)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1502)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1458)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.IllegalStateException: Store header is corrupt: nio:/home/robak/db/adzfo.mv.db [1.4.191/6]
at org.h2.mvstore.DataUtils.newIllegalStateException(DataUtils.java:773)
at org.h2.mvstore.MVStore.readStoreHeader(MVStore.java:603)
at org.h2.mvstore.MVStore.<init>(MVStore.java:353)
at org.h2.mvstore.MVStore$Builder.open(MVStore.java:2888)
at org.h2.mvstore.db.MVTableEngine$Store.open(MVTableEngine.java:154)
... 47 more
数据库配置
db.driver=org.h2.Driver
db.url=jdbc:h2:file:~/db/app_name;AUTO_SERVER=TRUE;CIPHER=AES
db.username=user
db.password=password
Servlet 上下文
private void configureDatabaseConsole(ServletContext servletContext)
ServletRegistration.Dynamic h2Servlet = servletContext.addServlet("h2console", WebServlet.class);
h2Servlet.setLoadOnStartup(2);
h2Servlet.addMapping("/console/db/*");
数据来源
@Bean
public DataSource dataSource()
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(getProperty(DRIVER));
dataSource.setUrl(getProperty(URL));
dataSource.setUsername(getProperty(USERNAME));
dataSource.setPassword(FILE_PASSWORD + " " + getProperty(PASSWORD));
return dataSource;
如何将加密数据库作为文件保存在硬盘上并通过 Web 界面访问其控制台?
【问题讨论】:
【参考方案1】:您确定您使用了正确的密码。引用 H2 文档File Encryption
The encryption algorithm is set in the database URL, and the file
password is specified in the password field, before the user
password. A single space separates the file password and the user
password; the file password itself may not contain spaces. File
passwords and user passwords are case sensitive. Here is an example
to connect to a password-encrypted database:
Class.forName("org.h2.Driver");
String url = "jdbc:h2:~/test;CIPHER=AES";
String user = "sa";
String pwds = "filepwd userpwd";
conn = DriverManager.
getConnection(url, user, pwds);
如果您不提供正确的密码,您将无法建立连接。
【讨论】:
是的,密码正确dataSource.setPassword(FILE_PASSWORD + " " + getProperty(PASSWORD));
。这一定是别的东西。
启用加密时是否创建了新的数据库?
是的,我做到了。我认为可能与AUTO_SERVER=TRUE
选项有关,但我仍然没有找到答案。
您是否尝试在连接字符串中没有 AUTO_SERVER
的情况下访问它(将 AES 留在那里)? ps:您还可以使用任何通用 JDBC 客户端(如 SquirrelSQL)访问在服务器模式下运行的 H2。也许你可以检查你是否可以通过这种方式访问数据库。
ps:我很快查看了 H2 MVStore 代码,在类的初始化过程中它似乎读取了存储,请参见第 336 行(在您的情况下加密),然后立即尝试读取标题(方法 readStoreHeader() 第 548 行),这也是引发异常的方法(第 593 行)。以上是关于从 H2 控制台访问加密数据库的主要内容,如果未能解决你的问题,请参考以下文章