数据存储加密
- 最佳实践方法:使用SQLCipher。SQLCipher是SQLite的一个加密扩展,它对数据库文件中的每一页数据进行加密。在iOS项目中集成SQLCipher库,通过设置加密密钥来加密数据库。例如,在打开数据库时传入加密密钥:
NSString *key = @"your_secret_key";
NSData *keyData = [key dataUsingEncoding:NSUTF8StringEncoding];
FMDatabase *db = [FMDatabase databaseWithPath:dbPath];
if (![db openWithFlags:SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_URI key:keyData]) {
NSLog(@"Failed to open database");
}
- 原理:SQLCipher使用SQLite的VFS(虚拟文件系统)层来拦截对数据库文件的读写操作。在写入数据时,它使用指定的加密算法(如AES)对数据进行加密后再写入文件;读取数据时,先从文件中读取加密数据,然后解密后返回给应用程序。这样即使数据库文件被窃取,没有密钥也无法获取其中的明文数据。
防止SQL注入攻击
- 最佳实践方法:使用参数化查询。在iOS开发中,如使用FMDB框架,它提供了方便的参数化查询方法。例如,当插入数据时:
FMDatabase *db = [FMDatabase databaseWithPath:dbPath];
if ([db open]) {
NSString *name = @"John";
NSInteger age = 30;
NSString *insertSQL = @"INSERT INTO users (name, age) VALUES (?,?)";
if (![db executeUpdate:insertSQL, name, @(age)]) {
NSLog(@"Failed to insert data");
}
[db close];
}
- 原理:参数化查询将SQL语句和参数分开处理。数据库引擎会对SQL语句进行预编译,参数作为独立的值传递,而不是直接嵌入SQL语句中。这样,恶意用户输入的特殊字符(如单引号、分号等用于构造恶意SQL语句的字符)不会被当作SQL语句的一部分执行,从而有效防止SQL注入攻击。
多线程访问控制
- 最佳实践方法:
- 使用FMDatabaseQueue:在多线程环境下,FMDB提供了FMDatabaseQueue类来管理数据库访问。它会在后台维护一个队列,所有数据库操作都在这个队列中按顺序执行,从而避免多线程同时访问数据库造成的数据不一致或其他问题。例如:
FMDatabaseQueue *queue = [FMDatabaseQueue databaseQueueWithPath:dbPath];
[queue inDatabase:^(FMDatabase *db) {
NSString *selectSQL = @"SELECT * FROM users";
FMResultSet *rs = [db executeQuery:selectSQL];
while ([rs next]) {
NSString *name = [rs stringForColumn:@"name"];
NSInteger age = [rs intForColumn:@"age"];
NSLog(@"Name: %@, Age: %ld", name, (long)age);
}
[rs close];
}];
- **线程安全的连接池**:对于更复杂的多线程应用场景,可以使用线程安全的连接池来管理数据库连接。连接池会维护一组数据库连接,每个线程从连接池中获取连接进行数据库操作,操作完成后将连接返回给连接池。这样可以避免频繁创建和销毁数据库连接带来的性能开销,同时保证多线程访问的安全性。
- 原理:FMDatabaseQueue通过GCD(Grand Central Dispatch)队列来顺序执行数据库操作,同一时间只有一个操作在执行,避免了多线程竞争。线程安全的连接池通过锁机制来控制连接的获取和释放,确保在多线程环境下连接的正确使用和管理,防止多个线程同时对同一个连接进行操作导致的数据损坏或其他错误。