mschop/securemy

面向对象、不可变且100%安全的PHP SQL查询构建器

v0.1.0-alpha.1 2018-03-06 11:15 UTC

This package is auto-updated.

Last update: 2024-09-19 10:16:12 UTC


README

SecureMy是一个MySQL查询构建器,专注于安全性。在使用SecureMy时,不应可能创建SQL注入漏洞。

基本用法

$qb = QueryBuilder::create();
$qb = $qb
    ->from('products', 'p')
    ->join(
        'product_categories',
        $qb->eq(
            $qb->column('pc.productId'),
            $qb->column('p.productId')
        ),
        'pc'
    )
    ->join(
        'categories',
        $qb->eq(
            $qb->column('pc.categoryId'),
            $qb->column('c.categoryId')
        ),
        'c'
    )
    ->groupBy('p.productId')
    ->select('p.productId', 'id')
    ->select($qb->func('count', '*'));
    
$build = $qb->build();
$stmt = $pdo->prepare($build->getQuery());
$stmt->execute($build->getParams());

安全漏洞示例

通过列名等进行的SQL注入

有时开发者认为根据用户输入动态创建列等是一个好主意。这可能会非常危险,因为数据库和PDO不支持将表或列名作为参数传递。

这将是一个理想的解决方案(但不幸的是,它不受支持)

$pdo = new PDO(...);
$query = "
    SELECT :column
    FROM producttable
    WHERE id = :id
";
$stmt = $pdo->prepare($query);
$stmt->execute([
    'column' => $_POST['column'],
    'id' => $_POST['id'],
]);

我经常看到非常危险的实施方案,如果不小心应用,可能会造成SQL注入漏洞。SecureMy通过字符白名单保护标识符。因此,它通过正则表达式 /^[a-z0-9._ ]+$/i 检查每个标识符。如您所注意到的,这与包含特殊字符的表或列名的数据库不兼容。见“缺点”。

通过条件进行的SQL注入

大多数查询构建器允许这样做

$qb = QueryBuilder::create();
$qb
    ->from('products')
    ->where("products.name = 'shirt'"); // most libs recomment doing ->where('roducts.name = :name') but none I found, ensures this

这并不安全,因为这可能导致非常危险的SQL注入漏洞。想象一下一个不太经验的开发者这样做

$qb = QueryBuilder::create();
$qb
    ->from('products')
    ->where("products.name = {$_GET['productName']}");

您无法使用SecureMy陷入这个陷阱。SecureMy阻止您这样做。这需要一些与代码冗余有关的权衡

$qb = QueryBuilder::create();
$qb
    ->from('products')
    ->where(
        $qb->eq($qb->column('products.name'), $_GET['productName'])
    );

优点和缺点(与其他查询构建器相比)

优点

  • 100%安全
  • 不可变查询构建器
  • 无需现有连接即可工作

缺点

  • 更冗长
  • 不兼容包含特殊字符的表名、列名、视图名或存储过程名