mschop / securemy
面向对象、不可变且100%安全的PHP SQL查询构建器
v0.1.0-alpha.1
2018-03-06 11:15 UTC
Requires
- php: >= 7.0
Requires (Dev)
- phpunit/phpunit: ~6.5
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%安全
- 不可变查询构建器
- 无需现有连接即可工作
缺点
- 更冗长
- 不兼容包含特殊字符的表名、列名、视图名或存储过程名