dnoegel/pdo-inspector

此包的最新版本(dev-master)没有提供许可信息。

检查PDO查询以发现可能的SQL注入

dev-master 2015-11-24 12:03 UTC

This package is auto-updated.

Last update: 2024-09-04 15:55:20 UTC


README

将装饰应用程序的PDO连接并记录所有查询,其中可能包含可能的SQL注入。

它是如何工作的?

每个查询都被拦截并解析。在解析的查询中,找到硬编码的常量值(例如 SELECT * FROM my_table WHERE value = 'hi')并将它们声明为可能的SQL注入。

您可以在定义的输出文件夹中找到那些查询的堆栈跟踪、请求信息以及更多详细信息。

如何使用它?

在您想测试的应用程序中,找到创建PDO连接的地方。大多数PHP软件都使用PDO,ORM如Doctrine也使用它。

示例

假设您有一个使用PDO的应用程序,如下所示

$this->_connection = new PDO(
    $dsn,
    $username,
    $password,
    $options
);

使用这个

use \\Dnoegel\\DatabaseInspection\\PDOInspectionDecorator;

try {
    $this->_connection = new PDOInspectionDecorator(
        new PDO(
            $dsn,
            $username,
            $password,
            $options
        )
    );

    $this->_connection->setProblemInspector(new \\Dnoegel\\DatabaseInspection\\SqlProblemInspector(
            new \\Dnoegel\\DatabaseInspection\\Storage\\JsonStorage('/tmp/sql_inspector_output'),
    ));

您可以装饰您的PDO连接。

因此,实际上有这三个步骤

  • 包含/要求此库的自动加载器。如果您已通过composer将其安装到您的应用程序中,则可以跳过此步骤。
  • 使用PDOInspectionDecorator装饰PDO连接,该装饰器对PDO连接完全透明,因此您的应用程序将正常使用它。
  • \Dnoegel\DatabaseInspection\SqlProblemInspector的实例注入到PDOInspectionDecorator中。SqlProblemInspector只有一个强制要求:JsonStorage,您可以根据需要配置以将配置文件保存到您喜欢的位置。

白名单

如果您检查了一个查询并认为它是安全的(例如,值在之前被转换为int),您可以将其移动到输出文件夹的whitelist文件夹中。脚本将不再打扰您。

白名单将确定查询的常量部分,例如 SELECT * FROM my_table WHERE value = 'hi'SELECT * FROM my_table WHERE value = 'another string' 从技术角度来看将是相同的查询。

创建问题检查器

$parser = new \\Dnoegel\\DatabaseInspection\\SqlProblemInspector(
    new \\Dnoegel\\DatabaseInspection\\Storage\\JsonStorage(),
    new \\Dnoegel\\DatabaseInspection\\RouteProvider\\RouteProvider(),
    new \\Dnoegel\\DatabaseInspection\\Trace\\DebugTrace(),
    true
)

最后一个参数将决定是否将所有发现保存到problem文档,还是脚本应尝试区分“问题”和“问题”。“问题”是只包含标量值的发现,这仍然可能是SQL注入,这绝对不是“一切正常”——只是一个“首先检查问题”。

读取“问题”文件

每个问题文件提供以下信息

  • route:触发该查询的路由/请求
  • problems:静态值的列表,在这种情况下 0 - 因此这可以可能是白名单的
  • code:触发有问题查询的函数的代码
  • sql:正在执行的SQL
  • trace:SQL的跟踪——因此您可以了解哪个文件/哪一行执行了它
  • normalized:解析和规范化的SQL查询——因此在这里移除了所有常量值,以便匹配其他硬编码值相同的查询
{
    "route": "\/media\/checkout\/confirm",
    "problems": [
        {
            "expr_type": "const",
            "base_expr": "0",
            "sub_tree": false
        }
    ],
    "code": {
        "999": "    public function sCountBasket()",
        "1000": "    {",
        "1001": "        return $this->db->fetchOne(",
        "1002": "            'SELECT COUNT(*) FROM s_order_basket WHERE modus = 0 AND sessionID = ?',",
        "1003": "            array($this->session->get('sessionId'))",
        "!!!": "        );",
        "1005": "    }"
    },
    "sql": "SELECT COUNT(*) FROM s_order_basket WHERE modus = 0 AND sessionID = ?",
    "trace": {
        "7": "sBasket: sCountBasket:  84",
        "8": "Shopware_Controllers_Frontend_Checkout: postDispatch:  161",
        "9": "Enlight_Controller_Action: dispatch:  524",
        "10": "Enlight_Controller_Dispatcher_Default: dispatch:  227",
        "11": "Enlight_Controller_Front: dispatch:  148",
        "12": "Shopware\\Kernel: handle:  492",
        "13": "Symfony\\Component\\HttpKernel\\HttpCache\\HttpCache: forward:  255",
        "14": "Shopware\\Components\\HttpCache\\AppCache: forward:  449",
        "15": "Symfony\\Component\\HttpKernel\\HttpCache\\HttpCache: fetch:  349",
        "16": "Symfony\\Component\\HttpKernel\\HttpCache\\HttpCache: lookup:  178",
        "17": "Shopware\\Components\\HttpCache\\AppCache: lookup:  213",
        "18": "Symfony\\Component\\HttpKernel\\HttpCache\\HttpCache: handle:  114",
        "19": "Shopware\\Components\\HttpCache\\AppCache: handle:  101"
    },
    "normalized": {
        "SELECT": [
            {
                "expr_type": "aggregate_function",
                "alias": false,
                "base_expr": "COUNT",
                "sub_tree": [
                    {
                        "expr_type": "colref",
                        "base_expr": "*",
                        "sub_tree": false
                    }
                ],
                "delim": false
            }
        ],
        "FROM": [
            {
                "expr_type": "table",
                "table": "s_order_basket",
                "no_quotes": {
                    "delim": false,
                    "parts": [
                        "s_order_basket"
                    ]
                },
                "alias": false,
                "hints": false,
                "join_type": "JOIN",
                "ref_type": false,
                "ref_clause": false,
                "base_expr": "s_order_basket",
                "sub_tree": false
            }
        ],
        "WHERE": [
            {
                "expr_type": "colref",
                "base_expr": "modus",
                "no_quotes": {
                    "delim": false,
                    "parts": [
                        "modus"
                    ]
                },
                "sub_tree": false
            },
            {
                "expr_type": "operator",
                "base_expr": "=",
                "sub_tree": false
            },
            {
                "expr_type": "const",
                "base_expr": "NORMALIZED",
                "sub_tree": false
            },
            {
                "expr_type": "operator",
                "base_expr": "AND",
                "sub_tree": false
            },
            {
                "expr_type": "colref",
                "base_expr": "sessionID",
                "no_quotes": {
                    "delim": false,
                    "parts": [
                        "sessionID"
                    ]
                },
                "sub_tree": false
            },
            {
                "expr_type": "operator",
                "base_expr": "=",
                "sub_tree": false
            },
            {
                "expr_type": "colref",
                "base_expr": "?",
                "no_quotes": {
                    "delim": false,
                    "parts": [
                        "?"
                    ]
                },
                "sub_tree": false
            }
        ]
    }
}

注意

这绝不是一层安全层。 不要 这样使用它。它是一个开发工具,用于解析SQL查询,以便找到可以替换为预处理语句的常量查询部分。不要在生产环境中使用它。