【问题标题】:How to eval arithmetic calculs?如何评估算术演算?
【发布时间】:2016-12-05 17:25:37
【问题描述】:

我必须构建一个计算一些数据的应用程序。我不知道科学家可以问什么计算。

例如, 用户 A 将要计算 (A + 5) * 3 用户 B 将要计算 (A + 14)² * pi

算术公式由科学家定义并由管理员存储在数据库中。

简单的方法是:

<?php

    //Formula is initialized by a query in database
    $formula= '(A + 3) * 5';
    //$ value is an integer entered by UserA and verify by Controller
    $value = 42;

    $arithmetic = str_replace('A', $formula, $value);

    $result = eval($arithmetic);

但是 Eval 是邪恶的,正如 @thpl 在 answer 中所解释的那样

我有两个选择:

  1. 对公式的每个字符进行大量分析和转换, 创建一个很棒的计算类。 (找到两边的操作数 + 并通过调用 addition 方法等替换 + 字符。 等等。
  2. 使用良好的(安全的?)正则表达式检查 $formula 并调用邪恶的 eval 函数。

第一个解决方案似乎更安全,但开发时间很长。

对于第二种解决方案,我在 php 文档中找到了这个:

<?php
    $test = '2+3*pi';

    // Remove whitespaces
    $test = preg_replace('/\s+/', '', $test);

    $number = '(?:\d+(?:[,.]\d+)?|pi|π)'; // What is a number
    $functions = '(?:sinh?|cosh?|tanh?|abs|acosh?|asinh?|atanh?|exp|log10|deg2rad|rad2deg|sqrt|ceil|floor|round)'; // Allowed PHP functions
    $operators = '[+\/*\^%-]'; // Allowed math operators
    $regexp = '/^((' . $number . '|' . $functions . '\s*\((?1)+\)|\((?1)+\))(?:' . $operators . '(?2))?)+$/'; // Final regexp, heavily using recursive patterns

    if (preg_match($regexp, $q)) {
        $test = preg_replace('!pi|π!', 'pi()', $test); // Replace pi with pi function
        eval('$result = ' . $test . ';');
    } else {
        $result = false;
    }

第一个问题:第二个解决方案是否足够安全?

我在互联网上搜索(当然),但找到的最佳解决方案是以前的代码。是否有一些 php 函数、pearl 或 PECL 库可以帮助我? arithmetic_eval 函数?

(我不问Security.SE,因为我的问题只涉及php)

【问题讨论】:

    标签: php database security


    【解决方案1】:

    我认为第一个解决方案(自定义解析器)非常复杂且容易出错。其中最大的风险是仍然允许攻击者运行任意代码的错误。也许你能做对,但很容易出错。

    第二种解决方案(建议的基于正则表达式的验证)可能好坏,很难说。分析 PHP 语法,将其与您的问题中的正则表达式进行比较,查看 PHP 中有哪些微妙的方式来编写语句和表达式等,这将花费大量时间。虽然乍一看它看起来并不是灾难性的,但没有人无需 很多 分析就可以说它是安全的。在此之前使用它会非常冒险。

    您可能决定接受其中任何一种风险,因为您是说这些公式将由管理员存储。管理员可以查看这些公式是否是似乎不包含任何代码的真正数学公式。虽然在看起来像公式的东西中掩盖一些微妙的代码执行可能并非不可能,但如果受信任的管理员在实际使用和评估所有内容之前对其进行审查,风险就会低得多。

    不过,让我提出一些不同的建议。如果您使用沙盒来评估表达式会怎样?以this 为例。您可以轻松地将代码可用的函数限制为仅限数学函数,并且只要您信任沙箱,您就可以放心,不会运行任何恶意软件。这会将问题转移给第三方(您必须信任第三方,这是一个重要的决定!),并且您的代码将保持非常简单但相当安全。您可能还想探索其他沙盒。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-10-04
      • 2021-05-02
      • 2018-05-23
      • 1970-01-01
      • 1970-01-01
      • 2020-09-26
      • 2016-01-16
      • 2020-03-17
      相关资源
      最近更新 更多