需求:
不知道大家有沒有遇到過這樣的需求:自己的服務器出於對數據庫安全的保護,需要對存儲的數據進行加密保護。這樣萬一數據庫被人拿到,別人也不能拿到數據庫里面的內容。這里還有一個前提:前端的展示頁面是不對外公開的,需要驗證才能進入。為什么提這個,就是因為前端所展現的內容一定是明文的,不然管理人員如何閱讀查看呢(這也給爬蟲留下了機會,不過關鍵還是在於你能夠拿到管理人員的密碼)。
背景介紹:
- 系統數據庫采用的是Mongodb;
- 后台使用的語言是Python;
- python與數據庫的交互主要借助於Pymongo。
尋找突破口:
從這里面我們大概可以發現有兩個地方可以下手:
- 每次進行數據庫操作的時候對數據進行加解密操作。具體來說就是:增刪改查之前對數據進行加密(這樣才能在數據庫中找到),查找之后對數據進行解密(這樣才能得到明文的內容進行展示);
- 修改與數據庫進行交互的庫Pymongo,讓其實現加密存儲,解密讀取。
比較下兩種方法的優缺點:
第一種方案:實現很簡單,但不適合大項目。項目一旦大了,對數據庫的操作不太可能完全通過某個數據庫操作模塊來實現,這樣修改起來就很麻煩了;
第二種方案:對業務邏輯是透明的。並不需要對網站代碼進行修改,但需要對pymongo的源碼進行分析,找出增刪改查相應的關鍵點,在這些關鍵點上進行加解密操作。
由於自己的項目確實不小,存在很多模塊。所以選擇了第二種方案。
具體步驟:
- 實現加解密函數庫
既然需要用到加解密操作,那么顯然需要實現自己的加解密函數。具體實現中我使用了pycrypto加密庫,利用其中的AES加密算法對文檔進行加解密。加解密過程不難,利用里遞歸實現,代碼實現如下:
1 from Crypto.Cipher import AES 2 import bson 3 from bson.binary import Binary, UUIDLegacy 4 from pymongo import config 5
6 key = config.key 7
8 obj = AES.new(key) 9
10 def encrypt_helper(s): 11 length = 16 - (len(s) % 16) 12 s += chr(length) * length 13 s = obj.encrypt(s) 14 s = Binary(s, 1) 15 return s 16
17 def decrypt_helper(s): 18 s = obj.decrypt(s) 19 buf = bytearray(s) 20 length = buf[-1] 21 s = s[: -length] 22 return s 23
24 def encrypt_doc(doc): 25 if isinstance(doc, str): 26 return encrypt_helper(doc) 27 if isinstance(doc, dict): 28 for key in doc: 29 if cmp(key, "channel") != 0: 30 doc[key] = encrypt_doc(doc[key]) 31 return doc 32
33 if isinstance(doc, list): 34 for i in range(len(doc)): 35 doc[i] = encrypt_doc(doc[i]) 36 return doc 37 return doc 38
39
40 def decrypt_doc(doc): 41 if isinstance(doc, Binary): 42 return decrypt_helper(doc) 43 if isinstance(doc, dict): 44 temp_doc = {} 45 for key in doc: 46 #version 1
47 #doc[key] = decrypt_doc(doc[key])
48
49 #version 2
50 temp_doc[str(key)] = decrypt_doc(doc[key]) 51 doc = temp_doc 52 return doc 53
54 if isinstance(doc, list): 55 for i in range(len(doc)): 56 doc[i] = decrypt_doc(doc[i]) 57 return doc 58 return doc
2. 找到pymongo中進行增刪改查操作的代碼並插入加解密的操作
經過研讀pymongo的代碼發現,增刪改查的操作主要是在兩個文件里面進行的:collection.py,cursor.py。所以在實現過程中,我只對這兩個文件的相關部分進行了修改(注意,我使用pymongo版本是2.7,如果使用其他版本的可能會有差別)。
我就簡單列舉一下我修改的函數吧,大家有興趣可以上github具體查看下整個實現:
-
- collection.py:
- insert
- update
- find_one
- remove
- aggregate
- cursor.py
- __getitem__
- __send_message
- collection.py:
有興趣的可以看看代碼,github地址:https://github.com/ybAmazing/encrypt_pymongo
思考和總結
這個功能的必要性,我自己是持懷疑態度的。由於對黑客技術也不是很了解,也說不出個所以然來。大家如果有什么想法或建議的,可以留言,相互交流學習一下。

