【问题标题】:Python's accessible class variables, sensitive data, and malicious coders (black-hat hackers)Python 可访问的类变量、敏感数据和恶意编码器(黑帽黑客)
【发布时间】:2019-12-25 08:36:53
【问题描述】:

我试图让我正在做的项目无法访问变量,我在Does Python have “private” variables in classes? 上看到了一个 SO 帖子。对我来说,它提出了一些有趣的问题,为了让这个问题得到解答,我会用 Q1Q2 等标记。我环顾四周,但我没有找到我所问问题的答案,尤其是那些关于敏感数据的问题。

我在 that post 中找到了有用的东西,但似乎普遍的共识类似于 如果你看到一个带有 _ 的变量,表现得像个成年人并意识到你不应该搞砸用它。对于__ 前面的变量也提出了同样的想法。在那里,我有一个大致的想法,即您相信人们不会使用here 和(更详细地)here 所描述的技巧。我还在this SO post找到了一些很好的信息。

当您谈论良好的编码实践时,这都是非常好的建议。

我在我分享的帖子中发布了一些关于 cmets 的想法。我的主要问题was posted 作为评论。

我很惊讶没有更多关于那些想要引入恶意代码的人的讨论。这是一个真正的问题:Python 中是否没有办法阻止黑帽黑客访问您的变量和方法并插入可能拒绝服务、泄露个人(或专有公司)信息的代码/数据Q1 如果 Python 不允许这种类型的安全性,是否应该将其用于敏感数据Q2

我是否完全遗漏了什么:恶意编码员甚至可以访问变量和方法来插入可能拒绝服务或泄露敏感数据的代码/数据Q3

我想我可能误解了一个概念,遗漏了某些东西,将问题放在不属于它的地方,或者完全不知道计算机安全是什么。但是,我想了解这里发生了什么。如果我完全不合时宜,我想要一个能告诉我的答案,但我也想知道我是如何完全不合时宜的,以及如何重新开始。

我在这里提出的问题的另一部分来自我对这些帖子/答案的另一条评论。 @SLott said(有点意译)

...我发现privateprotected 是非常非常重要的设计概念。但实际上,在数万行 Java 和 Python 代码中,我实际上从未使用过privateprotected。 ...这是我的问题“受谁保护[或私有]?”

为了弄清楚我的担忧是否值得关注,我在那个帖子上commented。在这里,已编辑。

问:“受谁保护?” A:“来自想要访问变量和函数以便能够拒绝服务的恶意黑帽黑客,访问敏感信息,......”似乎A._no_touch = 5 方法会导致这样的恶意编码器嘲笑我的“请不要碰这个”。我的A.__get_SSN(self) 似乎只是一厢情愿地希望 B.H. (黑帽)不知道x = A(); x._A__get_SSN() 把戏(trick by @Zorf)。

我可能把问题放在了错误的地方,如果是这样,我希望有人告诉我我把问题放在了错误的地方,但也要解释一下。 有没有使用基于类的方法来保证安全的方法Q4还有哪些其他非类和变量解决方案可用于处理 Python 中的敏感数据Q5

这里有一些代码说明了为什么我认为这些问题的答案是我想知道是否应该将 Python 用于敏感数据Q2的原因。它不是完整的代码(为什么我要放下这些私有值和方法而不在任何地方使用它们?),但我希望它显示了我想要询问的事情的类型。我在 Python 交互式控制台上输入并运行了所有这些。

## Type this into the interpreter to define the class.
class A():
  def __init__(self):
    self.name = "Nice guy."
    self.just_a_4 = 4
    self.my_number = 4
    self._this_needs_to_be_pi = 3.14
    self.__SSN = "I hope you do not hack this..."
    self.__bank_acct_num = 123
  def get_info():
    print("Name, SSN, bank account.")
  def change_my_number(self, another_num):
    self.my_number = another_num
  def _get_more_info(self):
    print("Address, health problems.")
  def send_private_info(self):
    print(self.name, self.__SSN, self.__bank_acct_num)
  def __give_20_bucks_to(self, ssn):
    self.__SSN += " has $20"
  def say_my_name(self):
    print("my name")
  def say_my_real_name(self):
    print(self.name)
  def __say_my_bank(self):
    print(str(self.__bank_acct_num))
>>> my_a = A()
>>> my_a._this_needs_to_be_pi
3.14
>>> my_a._this_needs_to_be_pi=4 # I just ignored begins-with-`_` 'rule'.
>>> my_a._this_needs_to_be_pi
4

## This next method could actually be setting up some kind of secure connection,  
## I guess, which could send the private data. I just print it, here.
>>> my_a.send_private_info()
Nice guy. I hope you do not hack this... 123

## Easy access and change a "private" variable
>>> my_a.__SSN
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'A' object has no attribute '__SSN'
>>> my_a.__dict__
{'name': 'Nice guy.', 'just_a_4': 4, 'my_number': 4, '_this_needs_to_be_pi': 4, 
'_A__SSN': 'I hope you do not hack this...', '_A__bank_acct_num': 123}
>>> my_a._A__SSN
'I hope you do not hack this...'

# (maybe) potentially more dangerous
>>> def give_me_your_money(self, bank_num):
      print("I don't know how to inject code, but I can")
      print("access your bank account number:")
      print(my_a._A__bank_acct_num)
      print("and use my bank account number:")
      print(bank_num)
>>> give_me_your_money(my_a,345)
I don't know how to inject code, but I can
access your bank account number:
123
and use my account number:
345

此时,我重新进入了类定义,这可能没有必要。

>>> this_a = A()
>>> this_a.__give_20_bucks_to('unnecessary param')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'A' object has no attribute '__give_20_bucks_to'
>>> this_a._A__give_20_bucks_to('unnecessary param')
>>> this_a._A__SSN
'I hope you do not hack this... has $20'

## Adding a fake "private" variable, `this_a.__SSN`
>>> this_a.__SSN = "B.H.'s SSN"
>>> this_a.__dict__
{'name': 'Nice guy.', 'just_a_4': 4, 'my_number': 4, '_this_needs_to_be_pi': 3.14, 
'_A__SSN': 'I hope you do not hack this... has $20', '_A__bank_acct_num': 123, 
'__SSN': "B.H.'s SSN"}
>>> this_a.__SSN
"B.H.'s SSN"

## Now, changing the real one and "sending/stealing the money"
>>> this_a._A__SSN = "B.H.'s SSN"
>>> this_a._A__give_20_bucks_to('unnecessary param')
>>> this_a._A__SSN
"B.H.'s SSN has $20"

我实际上在之前的合同工作中做过一些处理敏感数据的工作 - 不是 SSN 和银行帐号,而是人们的年龄、地址、电话号码、个人历史、婚姻和其他关系历史、犯罪记录等. 我没有参与保护这些数据的编程;我帮助尝试提取有用的信息,方法是帮助确定数据的真实性,为机器学习做准备。我们获得了使用此类数据的许可和法律许可。另一个主要问题是:如何在 Python 中收集、管理、分析这些敏感数据并得出有用的结论Q6?从我在这里讨论的内容来看,类(或任何其他数据结构,我没有在这里讨论,但似乎有同样的问题)似乎不会允许安全地完成此操作(私下或以受保护的方式。我想基于类的解决方案可能与编译有关。这是真的Q7吗?

最后,由于不是安全性,而是代码可靠性将我带到这里,我将发布另一篇我找到的帖子并发表评论以完成我的问题。

@Marcin posted,

[回应 OP 的话]“问题很简单。我希望只在类内部访问和更改私有变量。” [Marcin 回应] 所以,不要在访问以__ 开头的变量的类之外编写代码。使用pylint 或类似的东西来捕捉这样的样式错误。

my following reply comment 的目标是看看我的想法是否代表了实际的编码问题。我希望它没有被认为是粗鲁的

如果您编写代码只是为了您自己的个人享受,而不必将其交给其他人来维护它,那么这个答案似乎会很好。任何时候您处于协作编码环境中(任何高等教育和/或工作经验),该代码都会被许多人使用。下线的人会想要使用一种简单的方法来更改您的 __you_really_should_not_touch_this 变量。他们这样做可能有充分的理由,但您可能会设置您的代码,以便他们的“简单方法”会破坏事情。

我的观点是正确的,还是大多数编码人员都尊重双下划线Q8有没有更好的方法,使用 Python 来保护代码的完整性 - 比 __ 策略更好Q9

【问题讨论】:

  • 为了保护代码的完整性,不要让每个人都在您的生产机器上更改它。
  • 您混淆了多个安全级别。一旦有人可以触摸您的代码,无论您的语言是否强制执行私有属性,您都是不安全的。如果您不信任的人维护您的代码,那么无论您的编程语言做什么,您都无法再信任您的代码。私有访问只是为了防止代码库的其他部分,主要是为了强制执行正确的模式。不幸的是,它包括库——这是唯一开放的攻击媒介。如果您审查您的库,这不是问题。如果您使用的库的完整性您不信任,那就是个问题。
  • 我只能代表我(以及我工作的公司):如果有人更改代码,他/她就是开发人员并且有权这样做。我可以通过强制保护获得什么?如果我可以访问代码库,我可以将私有属性更改为公共属性。
  • “受谁保护”确实是正确的问题。由于物理安全、防火墙、正确的 PAM 设置、良好的密码、任何针对良好安全实践进行编码的暴露服务以及所有这些杂乱无章的原因,您已经受到了随机黑帽黑客的保护,他们无法访问您的计算机。如果黑帽黑客访问了你的机器,并不是因为 Python 没有私有变量,而是因为你公司的某个人搞砸了物理或逻辑安全,或者他们设法雇佣了恶意的人。然后,即使是具有强大访问检查功能的 Java 或 C++ 也无法为您提供帮助。
  • 您必须考虑如何 代码可以被注入。主要方式是缓冲区溢出(在没有适当保护的二进制代码上 - 不适用于 Python),针对未经检查的用户输入的臭名昭著的 eval 函数,将用户输入写入未经检查的用户指定的文件路径,插入未经检查的用户输入进入原始 SQL 查询。不使用eval,只需要注意用户输入。 (eval 有有效的用途,但很可能你几乎永远不会遇到。每当想使用eval 时,想想是否可以通过其他方式完成,几乎可以肯定你会发现它可以。)跨度>

标签: python class security data-science private


【解决方案1】:

privateprotected 不存在安全。它们的存在是为了在您的代码中执行合同,即逻辑encapsulation。如果你将一个片段标记为protectedprivate,则表示它是实现类的逻辑实现细节,其他代码不应直接触及它,因为其他代码可能无法 [能够] 正确使用它并且可能会弄乱状态。

例如,如果您的逻辑规则是每当您更改 self._a 时,您还必须将 self._b 更新为某个值,那么您不希望外部代码修改这些变量,因为您的内部状态可能会变得混乱如果外部代码不遵循此规则。你只希望你的一个班级在内部处理这个问题,因为这会定位潜在的故障点。

最终,无论如何,所有这些都会被编译成一个大字节球,并且所有数据在运行时都存储在内存中。在那一点上,无论如何都没有保护应用程序范围内的单个内存偏移量,这一切都只是字节汤。 protectedprivate 是程序员对自己的代码施加的约束,以保持自己的逻辑正确。为此,_ 这样的非正式约定或多或少就足够了。

攻击者无法在单个属性级别进行攻击。运行的软件对他们来说是一个黑匣子,无论内部发生什么都无关紧要。 如果攻击者能够实际访问单个内存偏移量,或者实际上注入代码,那么无论哪种方式都差不多。 protectedprivate 在那一点上并不重要。

【讨论】:

  • 这完美地涵盖了我从人们的 cmets 那里学到的所有东西。我是一名物理学家,他学会了为研究编写代码,享受其中,并成为一名开发人员和研究员。这使得我遇到了这些不属于我教育的基本概念。我不确定我从哪里得到privateprotected 和下划线是计算机安全的一部分(可能是受保护这个词)的想法,但您的回答非常简洁地填补了我的知识空白。谢谢。
  • 我想很多程序员都有同样的误解;如果您确实尝试访问标记为此类的属性,则使用实际 protected 关键字的语言通常也会引发错误。这可能会强制执行您“无法”访问它们的概念。 (实际上,你总是可以的,你只需要认真考虑一下。)从这个意义上说,我确实喜欢 Python 的方法。它甚至不假装这些属性不可访问,它只是想让你成为一个成年人来访问它们。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-09
  • 1970-01-01
  • 1970-01-01
  • 2015-07-12
  • 1970-01-01
相关资源
最近更新 更多