2010-06-08 75 views
7

这对我来说真的只是一个概念性问题。Lisp数据安全/验证

在Lisp中,程序是数据,数据是程序。 REPL完全是这样 - 读取并评估。

那么如何才能以安全的方式从用户那里获得输入呢?显然这是可能的 - 我的意思是viaweb - 现在Yahoo!商店是非常安全的,那么它是如何完成的?

回答

16

REPL代表Read Eval Print Loop。

(loop (print (eval (read)))) 

以上只是概念性的,真正的REPL代码更加复杂(带有错误处理,调试,...)。

您可以阅读Lisp中的各种数据,而无需对其进行评估。评估是一个独立的步骤 - 独立于阅读数据。

Lisp中有各种IO函数。所提供的功能中最复杂的通常是READ,它读取s表达式。 Common Lisp中有一个允许在READ期间进行评估的选项,但是在读取数据时可以并且应该关闭该选项。

因此,Lisp中的数据不一定是一个程序,即使数据是一个程序,Lisp也可以将程序读取为数据 - 无需评估。 REPL只能由开发人员使用,不应暴露给任意用户。为了从用户获取数据,需要使用普通的IO函数,包括像READ这样的函数,它可以读取S表达式,但不会对它们进行评估。

这里有几件事情之一不该做的事:

  • 使用READ读取任意数据。阅读例如允许读取真正的大数据 - 没有限制。

  • 在READ('read eval')期间评估。这应该被关闭。从I/O

  • 读符号,并呼吁他们的象征功能

  • 读取READ周期性数据结构,当你的函数期望平原名单。走下一个循环列表可以让你的程序忙一段时间。

  • 不处理从数据读取期间的语法错误。

+0

+1好的答案。 – rook 2010-06-08 19:22:29

2

这是一个杀手级的问题,当我读到Lisp时,我想到了同样的事情。虽然我在LISP中没有做任何有意义的事情,所以我的答案非常有限。

我可以告诉你的是,eval()is nasty。有一种说法,我喜欢“如果eval是答案,那么你问的是错误的问题。” - 未知。

如果攻击者可以控制随后评估的数据,那么您的远程代码执行漏洞非常严重。这可以减轻,我会告诉你用PHP的例子,因为这是我所知道的:

$id=addslashes($_GET['id']); 
eval('$test="$id";'); 

如果你不这样做的附加斜杠,则攻击者可以通过这样获得远程执行代码:

http://localhost?evil_eval.php?id="; phpinfo();/* 

但加斜杠将会把"\",从而保持从“数据”的“突破”,并能执行代码攻击。这与sql注入非常相似。

+0

+1。这可能适用于大多数任何语言。当然,任何时候我使用PHP,输入总是包装在一个htmlspecialchars() – 2010-06-09 12:19:18

6

你这样做是所有人都这样做的。您从流中读取一串数据,为您的命令和参数解析它,验证命令和参数,然后解释命令和参数。

这里没有魔法。

简而言之,你不要做的是,你不要将你的Lisp监听器暴露给未经验证的不安全的数据源。

如前所述,REPL是read-eval - print。 @ The Rook专注于eval(有理由),但不打折READ。 READ在Common Lisp中是一个非常强大的命令。读者可以自行评估代码,然后才能进行“评估”。

不要将READ暴露给任何你不信任的东西。

有了足够的工作,你可以制作一个定制的软件包,限制该软件包可用的功能范围等等。但是,我认为这比单纯地编写一个简单的命令解析器而不是担心一些副作用我错过了。

+0

这正是我担心的地方 - 读者可以评估代码。是否有一些与Python 2.6'raw_input()'等价的类型? – 2010-06-09 12:15:28

+1

http://www.lispworks.com/documentation/HyperSpec/Body/f_rd_lin.htm – Ken 2010-06-09 17:36:51

0

我发现这个问题退出有争议。除非您明确要求,否则评估不会评估您的输入。 我的意思是你的输入不会被视为一个LISP代码,而是一个字符串。

是不是因为你的语言有强大的概念,如评估它不是“安全”的。

我认为混淆来自SQL,其中您实际上将输入视为SQL的一部分。

(query (concatenate 'string "SELECT * FROM foo WHERE id = " input-id)) 

这里input-id正在由SQL引擎评估。 这是因为你没有很好的方式来编写SQL,或者其他什么,但重点是你的输入成为正在评估的一部分。

所以eval不会给你带来不安全感,除非你用它闭着眼睛。

编辑忘了告诉这适用于任何语言。

4
  1. 创建您自己的阅读表并填写必要的钩子:SET-MACRO-CHARACTER,SET-DISPATCH-MACRO-CHARACTER et al。
  2. 绑定READTABLE到您自己的可读取表格。
  3. 绑定READ-EVAL为了防止#。 (如果第1步做对可能不是必要的)
  4. 阅读

也许别的东西。

此外,还有一个在阅读时在临时包装中实习符号的技巧。

如果不LL数据(1)-ish,简单地写通常解析器。