HarmonyOS鸿蒙Next中ArkData关系型数据库Rdb加密问题
HarmonyOS鸿蒙Next中ArkData关系型数据库Rdb加密问题
- 本地数据库创建的时候,配置有必须需要密码才能打开数据库文件;那么该密码是否能支持自定义加密方式?
- rdb StoreConfig -->encrypt, 只是个开关,这是怎么工作的呢?
- 从安全角度讲,数据库防止暴力导出db文件后,直接外部可以读取,这点 鸿蒙是怎么考虑的?
1、不支持自定义加密
2、加密机制:HarmonyOS数据库加密时,应用无需传入密钥,只需要设置数据库加密的状态即可。系统会自动帮助将数据库加密,使用huks通用密钥库系统,完成数据库密钥的生成及加密保护
数据库加密机制:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/data-reliability-security-overview-V5#
数据库默认在本应用沙箱目录下创建RdbStore示例,因此当前无法导出数据库查看
3、加密后的数据库只能通过接口进行访问,无法通过其它方式打开数据库文件
demo参考:https://developer.huawei.com/consumer/cn/codelabsPortal/carddetails/tutorials_NEXT-Rdb
简易demo参考:
import fs from '@ohos.file.fs';
import buffer from '@ohos.buffer';
import { ValuesBucket } from '@ohos.data.ValuesBucket';
import common from '@ohos.app.ability.common';
import relationalStore from '@ohos.data.relationalStore'; // 导入模块
import { BusinessError } from '@ohos.base';
import hilog from '@ohos.hilog';
import promptAction from '@ohos.promptAction';
import { File } from '@system.file';
let store: relationalStore.RdbStore | undefined = undefined;
let predicates = new relationalStore.RdbPredicates("EMPLOYEE");
const table_name: string = 'EMPLOYEE'
// 建表Sql语句
const SQL_CREATE_TABLE =
`CREATE TABLE IF NOT EXISTS ${table_name} (`
+ 'ID INTEGER PRIMARY KEY AUTOINCREMENT, '
+ 'NAME TEXT NOT NULL, AGE INTEGER, '
+ 'SALARY REAL, '
+ 'CODES BLOB'
+ ')';
@Entry
@Component
struct Index {
@State message: string = 'Hello World';
@State database_version: number = 0;
@State database_name: string = '未创建';
@State database_flag: number = -1;
@State create_flag: number = -1
@State table_name1: string = 'EMPLOYEE'
context = getContext(this) as common.UIAbilityContext;
build() {
Column() {
//1、数据库创建
Row() {
Text(`数据库名:${this.database_name}`)
.textAlign(TextAlign.Start)
.fontSize(12)//.border({ width: 1 })
.padding(10)
.width('50%')
}
.width('90%')
.border({ width: 1 })
//2、建表
Row() {
if (this.create_flag === 1) {
Text(`表名:${this.table_name1}`)
.textAlign(TextAlign.Start)
.fontSize(12)
.padding(10)
.width('50%')
} else {
Text(`表名:未建表`)
.textAlign(TextAlign.Start)
.fontSize(12)
.padding(10)
.width('50%')
}
}
.width('90%')
.border({ width: 1 })
Button('1、创建数据库')
.onClick(() => {
if (this.database_flag === -1) {
this.getDataStore()
} else {
if (this.database_flag === 1) {
promptAction.showToast({
message: '数据库已创建'
});
}
}
})
Button('2、建表')
.onClick(() => {
if (this.database_flag === -1) {
promptAction.showToast({
message: '数据库未创建,请先创建数据库'
});
return;
}
this.createDatabase()
})
Button('3、插入数据')
.onClick(() => {
this.insertDate()
})
Button('4、删除数据')
.onClick(() => {
this.deleteData()
})
Button('5、修改数据')
.onClick(() => {
this.updateData()
})
Button('6、查询数据表')
.onClick(() => {
this.queryData()
})
}
}
//获取store,创建数据库
getDataStore() {
//设置数据库基本配置信息
const STORE_CONFIG: relationalStore.StoreConfig = {
name: "RdbTest.db", // 数据库文件名
securityLevel: relationalStore.SecurityLevel.S1 // 数据库安全级别
// encrypt: false, // 可选参数,指定数据库是否加密,默认不加密
// dataGroupId: 'dataGroupID', // 可选参数,仅可在Stage模型下使用,表示为应用组ID,需要向应用市场获取。指定在此Id对应的沙箱路径下创建实例,当此参数不填时,默认在本应用沙箱目录下创建。
// customDir: 'customDir/subCustomDir' // 可选参数,数据库自定义路径。数据库将在如下的目录结构中被创建:context.databaseDir + '/rdb/' + customDir,其中context.databaseDir是应用沙箱对应的路径,'/rdb/'表示创建的是关系型数据库,customDir表示自定义的路径。当此参数不填时,默认在本应用沙箱目录下创建RdbStore实例
};
relationalStore.getRdbStore(this.context, STORE_CONFIG).then(async (rdbStore: relationalStore.RdbStore) => {
store = rdbStore; //操作关系型数据库
console.info('成功获取RdbStore:' + store)
this.database_name = STORE_CONFIG.name
this.database_flag = 1
}).catch((err: BusinessError) => {
console.error(`获取RdbStore失败, code is ${err.code},message is ${err.message}`);
})
}
//建表
createDatabase() {
if (store != undefined) {
(store as relationalStore.RdbStore).executeSql(SQL_CREATE_TABLE, (err) => {
if (err) {
console.error(`数据表创建失败, code is ${err.code},message is ${err.message}`);
return;
}
console.info('数据表创建成功');
this.create_flag = 1
// 设置数据库版本
if(store != undefined) {
// this.database_version=(store as relationalStore.RdbStore).version+1;
(store as relationalStore.RdbStore).version = 3;
// 获取数据库版本
console.info(`RdbStore version is ${store.version}`);
}
})
}
}
//插入数据
insertDate() {
//数据初始化
let value1 = 'Lisa';
let value2 = 18;
let value3 = 100.5;
let value4 = new Uint8Array([1, 2, 3, 4, 5]);
// 以下三种方式可用
const valueBucket1: ValuesBucket = {
'NAME': value1,
'AGE': value2,
'SALARY': value3,
'CODES': value4,
};
if (store != undefined) {
(store as relationalStore.RdbStore).insert("EMPLOYEE", valueBucket1, (err: BusinessError, rowId: number) => {
if (err) {
console.error(`插入失败, code is ${err.code},message is ${err.message}`);
return;
}
console.info(`插入成功, rowId是:${rowId}`);
promptAction.showToast({
message: `插入成功`
});
})
}
}
//删除数据
deleteData() {
predicates = new relationalStore.RdbPredicates("EMPLOYEE");
predicates.equalTo("NAME", "Lisa");
if (store != undefined) {
(store as relationalStore.RdbStore).delete(predicates, (err, rows) => {
if (err) {
console.error(`删除失败, code is ${err.code},message is ${err.message}`);
return;
}
console.info(`删除成功,Delete rows: ${rows}`);
promptAction.showToast({
message: `删除成功`
});
})
}
}
//修改数据
updateData() {
let value1 = 'Lisa';
let value2 = 22;
let value3 = 200.5;
let value4 = new Uint8Array([1, 2, 3, 4, 5]);
// 以下三种方式可用
const valueBucket1: ValuesBucket = {
'NAME': value1,
'AGE': value2,
'SALARY': value3,
'CODES': value4,
};
// 修改数据
predicates = new relationalStore.RdbPredicates('EMPLOYEE'); // 创建表'EMPLOYEE'的predicates
predicates.equalTo('NAME', 'Lisa'); // 匹配表'EMPLOYEE'中'NAME'为'Lisa'的字段
if (store !== undefined) {
(store as relationalStore.RdbStore).update(valueBucket1, predicates, (err: BusinessError, rows: number) => {
if (err) {
console.error(`Failed to update data. Code:${err.code}, message:${err.message}`);
return;
}
console.info(`Succeeded in updating data. row count: ${rows}`);
})
}
}
queryData() {
predicates = new relationalStore.RdbPredicates("EMPLOYEE");
predicates.equalTo("NAME", "Lisa");
if (store != undefined) {
(store as relationalStore.RdbStore).query(predicates, (err, resultSet) => {
if (err) {
console.error(`查询失败, code is ${err.code},message is ${err.message}`);
return;
}
console.log(`结果集:ResultSet column names: ${resultSet.columnNames}, column count: ${resultSet.columnCount}`);
if (resultSet.rowCount === 0) {
console.log(`结果集行数:${resultSet.rowCount},没有查询到数据`)
return;
} else {
console.log(`查询到:${resultSet.rowCount}行数据`)
}
let str:string = ''
// resultSet是一个数据集合的游标,默认指向第-1个记录,有效的数据从0开始。
while (resultSet.goToNextRow()) {
const id = resultSet.getLong(resultSet.getColumnIndex("ID"));
const name = resultSet.getString(resultSet.getColumnIndex("NAME"));
const age = resultSet.getLong(resultSet.getColumnIndex("AGE"));
const salary = resultSet.getDouble(resultSet.getColumnIndex("SALARY"));
console.log(`查询结果:id=${id}, name=${name}, age=${age}, salary=${salary}`);
str+=`查询结果:id=${id}, name=${name}, age=${age}, salary=${salary}\n`
}
promptAction.showToast({
message: str
});
// 释放数据集的内存
resultSet.close();
})
}
}
}
更多关于HarmonyOS鸿蒙Next中ArkData关系型数据库Rdb加密问题的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
在HarmonyOS鸿蒙Next中,ArkData关系型数据库(Rdb)支持数据加密功能。ArkData Rdb使用SQLCipher库来实现加密,SQLCipher是一个开源的SQLite扩展,提供透明的256位AES加密。开发者可以通过设置密码来加密数据库文件,确保数据在存储时的安全性。
在ArkData Rdb中,加密功能通过RdbStoreConfig类进行配置。开发者可以在创建或打开数据库时,通过setEncryptKey方法设置加密密钥。密钥的长度必须为32字节,并且需要妥善保管,因为丢失密钥将导致无法访问加密数据。
以下是一个简单的示例代码:
import relationalStore from '@ohos.data.relationalStore';
let config: relationalStore.RdbStoreConfig = {
name: 'encrypted_database.db',
securityLevel: relationalStore.SecurityLevel.S1,
encryptKey: new Uint8Array([ /* 32-byte encryption key */ ])
};
relationalStore.getRdbStore(context, config, function (err, store) {
if (err) {
console.error(`Failed to get RdbStore. Code:${err.code},message:${err.message}`);
return;
}
console.info('Succeeded in getting RdbStore.');
});
在以上代码中,encryptKey是用于加密数据库的32字节密钥。开发者需要确保密钥的安全性,并根据应用需求选择合适的加密级别。
ArkData Rdb的加密功能可以有效保护存储在设备上的敏感数据,防止未经授权的访问和数据泄露。
在HarmonyOS鸿蒙Next中,ArkData关系型数据库(Rdb)支持通过SQLCipher进行加密。开发者可以在创建或打开数据库时,通过设置密码参数来启用加密功能,确保数据在存储和传输过程中的安全性。具体实现可参考官方文档中的加密接口和示例代码,合理配置加密策略以保护敏感数据。

