Access 数据库本身没有内置的“加密字段”功能(即不像某些商业数据库那样提供透明数据加密 TDE 或字段级加密),我们可以通过以下几种方式实现“字段解密”或数据保护:
常见场景分析
你拥有加密密钥/算法
如果你知道字段是如何加密的(例如使用 AES、DES、自定义算法等),并且拥有密钥,那么你可以:
- 在 VBA 中编写解密函数
- 使用外部工具(如 Python、C#)读取并解密
字段被混淆或编码(非真正加密)
有时数据只是经过 Base64、Hex 编码或简单替换,这种情况下“解密”其实是“解码”。
数据库文件本身被加密
Access 支持整个数据库文件加密(通过“加密数据库”功能),但这不是字段级加密,而是文件级加密,你需要:
- 使用正确的密码打开
.accdb或.mdb文件 - 一旦打开,字段数据就是明文可读的
如何在 Access 中实现字段加密/解密
方法 1:使用 VBA + Windows CryptoAPI(推荐用于简单场景)
以下是一个使用 Windows 内置 CryptoAPI 进行 AES 加密/解密的 VBA 示例:
' 需要引用:Microsoft ActiveX Data Objects x.x Library
' 以及导入 Windows API 函数
Private Declare PtrSafe Function CryptAcquireContext Lib "advapi32.dll" Alias "CryptAcquireContextA" ( _
ByRef phProv As LongPtr, ByVal pszContainer As String, ByVal pszProvider As String, _
ByVal dwProvType As Long, ByVal dwFlags As Long) As Long
Private Declare PtrSafe Function CryptCreateHash Lib "advapi32.dll" ( _
ByVal hProv As LongPtr, ByVal Algid As Long, ByVal hKey As LongPtr, _
ByVal dwFlags As Long, ByRef phHash As LongPtr) As Long
Private Declare PtrSafe Function CryptHashData Lib "advapi32.dll" ( _
ByVal hHash As LongPtr, ByVal pbData As String, ByVal dwDataLen As Long, _
ByVal dwFlags As Long) As Long
Private Declare PtrSafe Function CryptDeriveKey Lib "advapi32.dll" ( _
ByVal hProv As LongPtr, ByVal Algid As Long, ByVal hBaseData As LongPtr, _
ByVal dwFlags As Long, ByRef phKey As LongPtr) As Long
P
rivate Declare PtrSafe Function CryptEncrypt Lib "advapi32.dll" ( _
ByVal hKey As LongPtr, ByVal hHash As LongPtr, ByVal Final As Long, _
ByVal dwFlags As Long, ByVal pbData As String, ByRef pdwDataLen As Long, _
ByVal dwBufLen As Long) As Long
Private Declare PtrSafe Function CryptDecrypt Lib "advapi32.dll" ( _
ByVal hKey As LongPtr, ByVal hHash As LongPtr, ByVal Final As Long, _
ByVal dwFlags As Long, ByVal pbData As String, ByRef pdwDataLen As Long) As Long
Private Declare PtrSafe Function CryptReleaseContext Lib "advapi32.dll" ( _
ByVal hProv As LongPtr, ByVal dwFlags As Long) As Long
Const CALG_AES_256 = &H6610
Const PROV_RSA_FULL = 1
Const CRYPT_NEWKEYSET = &H8
Const CRYPT_VERIFYCONTEXT = &F0000000
Public Function EncryptAES(ByVal PlainText As String, ByVal Password As String) As String
Dim hProv As LongPtr
Dim hHash As LongPtr
Dim hKey As LongPtr
Dim DataLen As Long
Dim EncryptedData() As Byte
Dim i As Long
If Len(PlainText) = 0 Then Exit Function
' 初始化加密上下文
If CryptAcquireContext(hProv, vbNullString, vbNullString, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT) <> 0 Then
' 创建哈希对象
If CryptCreateHash(hProv, &H8004, 0, 0, hHash) <> 0 Then
' 用密码生成哈希
If CryptHashData(hHash, Password, Len(Password), 0) <> 0 Then
' 从哈希派生密钥
If CryptDeriveKey(hProv, CALG_AES_256, hHash, 0, hKey) <> 0 Then
DataLen = Len(PlainText)
ReDim EncryptedData(1 To DataLen)
For i = 1 To DataLen
EncryptedData(i) = Asc(Mid(PlainText, i, 1))
Next i
' 加密
If CryptEncrypt(hKey, 0, 1, 0, EncryptedData(1), DataLen, DataLen) <> 0 Then
' 转换为 Base64 字符串以便存储
EncryptAES = EncodeBase64(EncryptedData)
End If
CryptReleaseContext hKey, 0
End If
End If
CryptReleaseContext hHash, 0
End If
CryptReleaseContext hProv, 0
End If
End Function
Public Function DecryptAES(ByVal EncryptedText As String, ByVal Password As String)
As String
Dim hProv As LongPtr
Dim hHash As LongPtr
Dim hKey As LongPtr
Dim DataLen As Long
Dim EncryptedData() As Byte
Dim DecryptedData() As Byte
Dim i As Long
If Len(EncryptedText) = 0 Then Exit Function
' 从 Base64 解码
EncryptedData = DecodeBase64(EncryptedText)
If UBound(EncryptedData) < 1 Then Exit Function
DataLen = UBound(EncryptedData)
ReDim DecryptedData(1 To DataLen)
If CryptAcquireContext(hProv, vbNullString, vbNullString, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT) <> 0 Then
If CryptCreateHash(hProv, &H8004, 0, 0, hHash) <> 0 Then
If CryptHashData(hHash, Password, Len(Password), 0) <> 0 Then
If CryptDeriveKey(hProv, CALG_AES_256, hHash, 0, hKey) <> 0 Then
' 解密
If CryptDecrypt(hKey, 0, 1, 0, EncryptedData(1), DataLen) <> 0 Then
For i = 1 To DataLen
DecryptedData(i) = EncryptedData(i)
Next i
DecryptAES = StrConv(DecryptedData, vbUnicode)
End If
CryptReleaseContext hKey, 0
End If
End If
CryptReleaseContext hHash, 0
End If
CryptReleaseContext hProv, 0
End If
End Function
' Base64 编码/解码函数(需自行实现或使用现有库)
' 此处省略 Base64 实现,可使用第三方类模块 ⚠️ 注意:上述代码需要配合 Base64 编码/解码函数使用,你可以从网上获取标准的 Base64 VBA 类模块。
方法 2:使用外部工具(Python + pyodbc)
如果你不想在 Access 内部处理,可以用 Python 读取并解密:
import pyodbc
from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad
import base64
# 连接 Access 数据库
conn = pyodbc.connect(
r'DRIVER={Microsoft Access Driver (.mdb, .accdb)};'
r'DBQ=C:pathtoyourdatabase.accdb;'
r'PWD=your_password;' # 如果数据库文件被加密
)
cursor = conn.cursor()
# 假设表名为 Users,字段为 EncryptedPassword
cursor.execute("SELECT ID, EncryptedPassword FROM Users")
rows = cursor.fetchall()
for row in ro
ws:
encrypted_b64 = row[1]
encrypted_data = base64.b64decode(encrypted_b64)
# 解密(假设使用 AES-256-CBC,密钥和 IV 已知)
key = b'your_32_byte_key_here!!' # 必须是 32 字节
iv = b'your_16_byte_iv_here!!' # 必须是 16 字节
cipher = AES.new(key, AES.MODE_CBC, iv)
decrypted = unpad(cipher.decrypt(encrypted_data), AES.block_size)
password = decrypted.decode('utf-8')
print(f"ID: {row[0]}, Password: {password}")
cursor.close()
conn.close() 如果字段只是被编码(非加密)
Base64 解码示例(VBA)
Public Function DecodeBase64(ByVal Base64String As String) As String
Dim objXML As Object
Dim objNode As Object
Set objXML = CreateObject("MSXML2.DOMDocument")
Set objNode = objXML.createElement("b64")
objNode.DataType = "bin.base64"
objNode.Text = Base64String
DecodeBase64 = StrConv(objNode.nodeTypedValue, vbUnicode)
Set objNode = Nothing
Set objXML = Nothing
End Function 重要提醒
| 问题 | 说明 |
|---|---|
| Access 无原生字段加密 | 必须自行实现或使用外部工具 |
| 密钥管理至关重要 | 如果丢失密钥,数据永久无法恢复 |
| 性能影响 | 加解密会显著降低查询和更新速度 |
| 安全性 | VBA 中的密钥容易被逆向,敏感数据建议迁移到更安全的数据库(如 SQL Server + TDE) |
| 法律合规 | 确保解密行为符合相关法律法规(如 GDPR、个人信息保护法) |
建议的最佳实践
- 预防优于补救:在数据写入时就加密,而不是事后解密
- 使用强加密算法:AES-256 是当前推荐标准
- 密钥与数据分离存储:不要将密钥硬编码在代码中
- 考虑迁移数据库:对于高安全需求,建议迁移到 SQL Server、PostgreSQL 等支持字段级加密的数据库
【版权声明】:本站所有内容均来自网络,若无意侵犯到您的权利,请及时与我们联系将尽快删除相关内容!
发表回复