python ast.literal_eval和datetime

python ast.literal_eval和datetime,python,Python,我有一个字符串“{'datetime':datetime.datetime(2010,11,21,0,56,58)}”,我想将其转换为它所表示的对象。使用ast.literal\u eval() ValueError: malformed string; 因为它不允许构建对象(即datetime调用)。是否需要获取ast以正确处理此问题,或者保护eval以防止代码注入?使用将其编译为ast,遍历ast以确保其仅包含白名单节点集,然后执行它。您可以提取(2010、11、21、0、56、58)使

我有一个字符串
“{'datetime':datetime.datetime(2010,11,21,0,56,58)}”
,我想将其转换为它所表示的对象。使用
ast.literal\u eval()

ValueError: malformed string; 

因为它不允许构建对象(即
datetime
调用)。是否需要获取
ast
以正确处理此问题,或者保护
eval
以防止代码注入?

使用将其编译为ast,遍历ast以确保其仅包含白名单节点集,然后执行它。

您可以提取
(2010、11、21、0、56、58)使用
regex
从字符串中提取字符,将其传递到
ast.literal\u eval()
以获取元组,然后将该元组传递到
datetime.datetime(*a\u tuple)
以获取对象。听起来很多,但每个步骤都非常简单(而且安全)。 下面是我要说的:

import ast
import datetime
import re

s = "{'datetime': datetime.datetime(2010, 11, 21, 0, 56, 58)}"
m = re.search(r"""datetime(\((\d+)(,\s*\d+)*\))""", s)
if m:  # any matches?
    args = ast.literal_eval(m.group(1))
    print datetime.datetime(*args)
    # 2010-11-21 00:56:58
这将在字符串中搜索模式
“datetime()”
,并仅将文本整数值列表传递给
ast.literal\u eval()
,以转换为元组,元组应始终成功,并且不允许代码注入。我相信它被称为“上下文敏感字符串评估”或CSSE。

跟进idea:

屈服

{'the_datetime': datetime.datetime(2010, 11, 21, 0, 56, 58)} ... [PASSED]
__import__('os'); os.unlink ... [REJECTED]
import os; os.unlink ... [REJECTED]
import(os) ... [REJECTED]
使用repr(datetime.datetime.utcnow())保存到dict或文件中。看,

>>> import datetime
>>> oarg = datetime.datetime.utcnow()
>>> oarg
datetime.datetime(2013, 2, 6, 12, 39, 51, 709024)
>>> butiwantthis = repr(oarg)
>>> butiwantthis
'datetime.datetime(2013, 2, 6, 12, 39, 51, 709024)'
>>> eval(oarg)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: eval() arg 1 must be a string, bytes or code object
>>> eval(butiwantthis)
datetime.datetime(2013, 2, 6, 12, 39, 51, 709024)
导入日期时间 >>>oarg=datetime.datetime.utcnow() >>>桨 datetime.datetime(2013,2,6,12,39,51709024) >>>但这=报告(oarg) >>>但是我想要这个 'datetime.datetime(2013,2,6,12,39,51709024)' >>>评估(划桨) 回溯(最近一次呼叫最后一次): 文件“”,第1行,在 TypeError:eval()arg 1必须是字符串、字节或代码对象 >>>评估(但不包括此) datetime.datetime(2013,2,6,12,39,51709024)
酷!eval()有效! 注意进口

>>> from datetime import datetime, date, time
>>> oarg = datetime.datetime.utcnow()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: type object 'datetime.datetime' has no attribute 'datetime'
>>> oarg = datetime.utcnow()
>>> oarg
datetime.datetime(2013, 2, 6, 12, 41, 51, 870458)
>>> butiwantthis = repr(oarg)
>>> butiwantthis
'datetime.datetime(2013, 2, 6, 12, 41, 51, 870458)'
>>> eval(butiwantthis)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<string>", line 1, in <module>
AttributeError: type object 'datetime.datetime' has no attribute 'datetime'
>>> # wrong import
>>从日期时间导入日期时间、日期、时间
>>>oarg=datetime.datetime.utcnow()
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
AttributeError:类型对象“datetime.datetime”没有属性“datetime”
>>>oarg=datetime.utcnow()
>>>桨
datetime.datetime(2013,2,6,12,41,51870458)
>>>但这=报告(oarg)
>>>但是我想要这个
'datetime.datetime(2013,2,6,12,41,51870458)'
>>>评估(但不包括此)
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
文件“”,第1行,在
AttributeError:类型对象“datetime.datetime”没有属性“datetime”
>>>#输入错误
太好了


Ps:Python3.3

当您必须解析datetime objs时,不要编写大量代码,而不要使用ast。您可以运行eval()。顺便说一句,请注意,如果字符串可能包含狡猾的python命令,那么使用此函数可能会出现安全问题

以下是它的工作原理:

>>> x="{'datetime': datetime.datetime(2010, 11, 21, 0, 56, 58)}"
>>> b=eval(x)
>>> b
{'datetime': datetime.datetime(2010, 11, 21, 0, 56, 58)}
>>> b["datetime"].year
2010

享受吧D

我遇到了这个问题,通过用如下字符串替换datetime对象解决了这个问题:

            if mystrobj.__contains__('datetime.datetime('):
                mystrobj = re.sub(r"datetime.datetime([(),0-9 ]*),", r"'\1',", mystrobj)

IMHO听起来像是做了很多工作(和代码),如果你错过了一些或允许了一些你认为安全的东西,那么IMHO很容易出错。正如OP提到的(“或者保护eval以防止代码注入?”)的问题是,
eval
是一种安全风险,你不应该对不可信的输入执行它。
            if mystrobj.__contains__('datetime.datetime('):
                mystrobj = re.sub(r"datetime.datetime([(),0-9 ]*),", r"'\1',", mystrobj)