0.時間を無駄にしたくない方向けの要約
この記事はpythonでprivateメンバを無理やり実装するため、nonceや暗号化を取り入れたけど、可読性下がるしすぐに破られるから意味なかったってだけの記事です。
1.アイデア
暗号化nonceを設計すればいいじゃん。
暗号化機構についてはteitei_tkさんの記事を丸パクリさせていただいた。
特にaes_cipher.py
はそのままディレクトリに保存した。
ただしpip install pycrypto
はwindows環境ではビルドエラーになるようなので、
pip install pycryptodome
で代替のこと。
2.実装
import numpy as np
from aes_cipher import AESCipher
import string, random;
# importはすべてprivateメソッド用
class Test:
def __init__(self):
self.cipher = AESCipher(''.join([random.choice(string.ascii_letters + string.digits) for i in range(50)])) #鍵の作成、即登録
self.nonce # nonce
def caller(self):
print('callerから_private_calleeを呼ぶ')
self.nonce = np.random.rand() #nonce更新
self._private_callee(self.cipher.encrypt(self.nonce)) #新しいnonceを暗号化してprivateメソッドへ送る
def _private_callee(self, ciphered_nonce):
nonce = cipher.decrypt(ciphered_nonce) #送られてきた暗号化済みnonceを復号
if nonce==self.nonce:
print('ノンスが一致したのでおそらcallerからの想定通りの呼び出し')
#ここに処理をかく
else:
print('不正な呼び出し')
もちろん、外部からobj._private_callee(obj.cipher.encrypt(obj.nonce))
とやれば不正な呼び出しに成功してしまうため、セキュリティ的には論外もいいところである。
でもまあ、これくらいしておけば「うっかりprivateメソッドを呼んでしまう」ということは考えにくい。
そもそもjavaのprivateメソッドでさえ、リフレクションを使えば外部から呼べてしまう。
知らない人がついprivateメソッドを呼んでしまうことを防ぐだけであればこれで十分ではないだろうか。
また、同じアプローチで、privateフィールドを作って、getter、setterを定義することも可能。
import numpy as np
from aes_cipher import AESCipher
import string, random;
# importはすべてprivateフィールド用
class Test:
def __init__(self):
self.cipher = AESCipher(''.join([random.choice(string.ascii_letters + string.digits) for i in range(50)])) #鍵の作成、即登録
self._private_field = self.cipher.encrypt('「最悪見られてもいい」が「うっかり見られたくはない」内容')
def setter(self, value):
self._private_field = self.cipher.encrypt(value)
def getter(self):
return self.cipher.decrypt(self._private_field)
2.結論
やっぱり暗号化したりnonceを導入したりしないで、素直に「先頭に_
のついてるものはprivateだと思ってね!」と取り決めるだけにとどめておく方がよさそう。
無理やりそれっぽいことを実装しても、大した意味がないわりに、コードの可読性がめちゃくちゃ落ちるからだ。