【问题标题】:Encrypted file or db in pythonpython中的加密文件或数据库
【发布时间】:2010-11-02 10:51:03
【问题描述】:

我有一个 sqlite3 db,我在 python 中插入/选择。该应用程序运行良好,但我想对其进行调整,这样没有密码就没有人可以从数据库中读取。我怎么能在python中做到这一点?请注意,我不知道从哪里开始。

【问题讨论】:

    标签: python sqlite encryption


    【解决方案1】:

    SQLite 数据库非常易于阅读,并且没有任何内置加密。

    您是否担心有人直接访问和读取数据库文件,或通过您的程序访问它们?

    我假设前者,因为后者实际上与数据库无关——这是您要询问的应用程序的安全性。

    想到几个选项:

    1. 使用文件系统权限而不是加密来保护数据库。您还没有提到您的环境是什么,所以我不能说这是否适合您,但这可能是最简单和最可靠的方法,因为您无法尝试解密您无法阅读的内容。
    2. 写前用Python加密,读后用Python解密。相当简单,但是您失去了 SQL 基于集合的匹配操作的大部分功能。
    3. 切换到另一个数据库;用户身份验证和权限是大多数多用户数据库的标准功能。当您发现自己面临工具的限制时,可能更容易环顾其他工具,而不是在当前工具中加入新功能。

    【讨论】:

    • 我有同样的问题,除了我不能使用其他数据库,因为 sqlite 对于我打算编写的桌面应用程序(私人日记软件)来说是轻量级的
    【解决方案2】:

    您可以使用 SQLCipher。

    http://sqlcipher.net/

    用于 SQLite 的开源全数据库加密

    SQLCipher 是一个 SQLite 扩展,它为数据库文件提供透明的 256 位 AES 加密。页面在写入磁盘之前被加密,并在回读时被解密。由于占用空间小且性能出色,它非常适合保护嵌入式应用程序数据库,并且非常适合移动开发。

    1. 以低至 5-15% 的开销实现超快性能 许多操作的加密
    2. 数据库文件中的数据 100% 已加密 使用良好的安全性 实践(CBC 模式、密钥派生)
    3. 零配置和应用级加密广泛平台
    4. 支持:适用于 C/C++、Obj-C、QT、Win32/.NET、Java、Python、 Windows、Linux、iPhone/iOS 上的 Ruby 等……

    【讨论】:

    • 它是开源的,所以它是免费的,对吧?然而你可以“买”它。你在买什么'? (另外,和迈克尔有同样的问题,“究竟是如何让它在 Python 中工作的?”)
    【解决方案3】:

    我遇到了同样的问题。我的应用程序可能同时运行多个实例。因此,我不能只加密 sqlite db 文件并完成它。我也不认为在 python 中加密数据是一个好主意,因为在这种状态下你不能在数据库中进行任何严重的数据操作。

    考虑到这些限制,我想出了以下两个解决方案:

    1. 使用前面提到的 SQLCipher。我在这里看到的问题是,我必须为 Python 编写自己的绑定,然后自己编译(或付费)。无论哪种情况,我都可能会这样做,因为对于其他 Python 开发人员来说,这将是一个很好的解决方案。如果我成功了,我会回复解决方案。

    2. 如果选项 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 上发布最终的代码库以及构建说明。

    【讨论】:

    • 不幸的是这个项目失败了,我再也没有回来。
    【解决方案4】:

    正如 Frontware 所建议的,您可以使用 sqlcipher。

    pysqlcipherpython包使用sqlcipher代码合并编译扩展,使用方便。

    应该像使用常规 sqlite.dbapi2 一样使用 pysqlcipher,只需设置正确的加密 pragma。

    【讨论】:

      【解决方案5】:

      您可以使用存储在内存 (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()
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-11-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-12-03
        • 1970-01-01
        相关资源
        最近更新 更多