【发布时间】:2010-11-02 10:51:03
【问题描述】:
我有一个 sqlite3 db,我在 python 中插入/选择。该应用程序运行良好,但我想对其进行调整,这样没有密码就没有人可以从数据库中读取。我怎么能在python中做到这一点?请注意,我不知道从哪里开始。
【问题讨论】:
标签: python sqlite encryption
我有一个 sqlite3 db,我在 python 中插入/选择。该应用程序运行良好,但我想对其进行调整,这样没有密码就没有人可以从数据库中读取。我怎么能在python中做到这一点?请注意,我不知道从哪里开始。
【问题讨论】:
标签: python sqlite encryption
SQLite 数据库非常易于阅读,并且没有任何内置加密。
您是否担心有人直接访问和读取数据库文件,或通过您的程序访问它们?
我假设前者,因为后者实际上与数据库无关——这是您要询问的应用程序的安全性。
想到几个选项:
【讨论】:
您可以使用 SQLCipher。
用于 SQLite 的开源全数据库加密
SQLCipher 是一个 SQLite 扩展,它为数据库文件提供透明的 256 位 AES 加密。页面在写入磁盘之前被加密,并在回读时被解密。由于占用空间小且性能出色,它非常适合保护嵌入式应用程序数据库,并且非常适合移动开发。
【讨论】:
我遇到了同样的问题。我的应用程序可能同时运行多个实例。因此,我不能只加密 sqlite db 文件并完成它。我也不认为在 python 中加密数据是一个好主意,因为在这种状态下你不能在数据库中进行任何严重的数据操作。
考虑到这些限制,我想出了以下两个解决方案:
使用前面提到的 SQLCipher。我在这里看到的问题是,我必须为 Python 编写自己的绑定,然后自己编译(或付费)。无论哪种情况,我都可能会这样做,因为对于其他 Python 开发人员来说,这将是一个很好的解决方案。如果我成功了,我会回复解决方案。
如果选项 1 对我来说太难,或者太耗时,我会使用这种方法。这种方法没有那么安全。我将使用 pycrypto 加密数据库文件。我将实现一个 SQL“服务器”,它将解密数据库文件,然后处理来自各种客户端的请求。只要没有未完成的请求,它就会重新加密数据库。总体而言,这会变慢,并使数据库处于临时解密状态。
希望这些想法对下一个人有所帮助。
编辑 2013 年 1 月 13 日
我放弃了 SQLCipher,因为我似乎无法编译它,并且代码库正在尝试使用 OpenSSL,它虽然是一个健全的库,但对于简单的 AES 128 来说是相当庞大的代码库。
我找到了另一个选项 wxSQLite3,我发现了如何仅分离出 SQLite 加密部分:https://github.com/shenghe/FreeSQLiteEncryption。我能够让它编译和工作(使用最新版本的 SQLite3)。 wxSQLite3 还支持 AES 256,这真的很酷。我的下一步将是尝试使用修改后的 sqlite3.dll 编译 pysqlite(它是内置于 python 中的 sqlite 库)。如果可行,我将调整 pysqlite 以支持 wxSQLite3 的 sqlite3.dll 的扩展加密部分。无论如何,我会尝试用我的结果更新这个线程,如果成功,我会在 Github 上发布最终的代码库以及构建说明。
【讨论】:
正如 Frontware 所建议的,您可以使用 sqlcipher。
pysqlcipherpython包使用sqlcipher代码合并编译扩展,使用方便。
应该像使用常规 sqlite.dbapi2 一样使用 pysqlcipher,只需设置正确的加密 pragma。
【讨论】:
您可以使用存储在内存 (RAM) 中的数据库,并且只保存您使用加密模块获得的加密版本。然后,您可以通过解密您存储的内容并在内存中重新创建数据库来访问它。
##imports
from cryptography.fernet import Fernet
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.backends import default_backend
import base64
from os import getcwd
import sqlite3
import gzip
##creating key
def key_creation(password):
kdf=PBKDF2HMAC(algorithm = hashes.SHA256(), salt=b'\xfaz\xb5\xf2|\xa1z\xa9\xfe\xd1F@1\xaa\x8a\xc2', iterations=1024, length=32, backend=default_backend())
key=Fernet(base64.urlsafe_b64encode(kdf.derive(password)))
return key
## encryption
def encryption(b, password):
f=key_creation(password)
safe=f.encrypt(b)
return safe
## decryption
def decryption(safe, password):
f=key_creation(password)
b=f.decrypt(safe)
return b
##
def open_cdb(name,password):
f=gzip.open(getcwd()+name+'_crypted.sql.gz','rb')
safe=f.read()
f.close()
content=decryption(safe,password)
content=content.decode('utf-8')
con=sqlite3.connect(':memory:')
con.executescript(content)
return con
##
def save_cdb(con,name,password):
fp=gzip.open(getcwd()+name+'_crypted.sql.gz','wb')
b=b''
for line in con.iterdump():
b+=bytes('%s\n','utf8') % bytes(line,'utf8')
b=encryption(b,password)
fp.write(b)
fp.close()
##test
if __name__=='__main__':
password=b'Sw0rdFish'
name='PRODUCTS'
conn = sqlite3.connect(':memory:')
conn.execute('CREATE TABLE PRODUCTS (ID INT PRIMARY KEY NOT NULL,\nNAME TEXT NOT NULL,\nPRICE REAL NOT NULL,\nTAXES REAL NOT NULL);')
save_cdb(conn,name,password)
conn.close()
conn = open_cdb(name,password)
cursor = conn.execute('select * from ' + name)
headers = list(map(lambda x: x[0], cursor.description))
print(headers)
for x in cursor:
for j in range(len(x)):
print(headers[j]+' ',x[j])
print('\n')
conn.close()
【讨论】: