从 MS SQL 服务器到 Linux 上的 PHP 的非模拟准备语句支持
Non-Emulated Prepared Statement support from MS SQL Server through PHP on Linux
总结
我正在尝试使用准备好的语句来停止 SQL 注入,但无法找到我需要的支持来保证它正常工作。
场景
我在 Linux 上托管一个站点,该站点连接到装有 FreeTDS 0.91 版的 Microsoft SQL 服务器,特别是使用 FreeTDS 的 dblib
。我已将数据库连接的 tds
版本设置为 7.4,并且正在使用 PHP 的 PDO 对象。
根据FreeTDS documentation,4.2不支持预处理语句:
TDS 4.2 has limitations
- ASCII only, of course.
- RPC is not supported.
- BCP is not supported.
- varchar fields are limited to 255 characters. If your table defines
longer fields, they'll be truncated.
- dynamic queries (also called prepared statements) are not supported.
然而,没有任何迹象表明 7.4 不支持准备好的语句,这让我有理由相信它们至少不会引发驱动程序错误。
PHP 的 PDO 通过 PDO::setAttribute()
支持连接特定属性。
我感兴趣的是 PDO::ATTR_ERRMODE
将所有错误设置为异常,PDO::ATTR_EMULATE_PREPARES
如果兼容则强制数据库执行准备好的语句。
问题
测试连接时,我收到以下错误:
Database error: SQLSTATE[IM001]: Driver does not support this function: driver does not support setting attributes
无法设置 PDO::ATTR_EMULATE_PREPARES
,我无法保证数据库确实按预期执行准备好的语句。
有没有办法修改我的方法,或者有其他方法来
保证准备好的语句在 Linux?
的 MS SQL 服务器上安全执行
解决方案
使用ODBC
代替dblib
,它提供了PDO的全部功能。
请注意,ODBC 有两种可能的配置:standalone ODBC and FreeTDS with ODBC driver。根据我的经验,要为连接设置字符集,必须使用 ODBC 驱动程序通过 FreeTDS 完成,使组合配置更可取。
ODBC 设置
我在网上搜索了许多不同的 Whosebug 帖子和各种文档资源,了解如何正确安装 ODBC。我从以下三个参考文献中提取了我的解决方案:
- unixODBC setup documentation
FlipperPA
对 setting up FreeTDS 的回答(顺便用 ODBC 完成)
Benny Hill
对此setup issue with FreeTDS 的回答
下面是我在基于 Debian 的系统上使用 FreeTDS
配置 ODBC
的步骤列表。
TDS 8.0 支持准备好的语句。
注意:将不支持连接上的 SET NAMES a
或 SET CHARSET a
;需要通过设置 FreeTDS 属性使用组合配置来定义字符集。使用独立的 ODBC 驱动程序将字符集默认为 ASCII
,这会产生奇怪的结果。有关可能问题的示例,请参阅我的 other post。
安装需要的包:
sudo apt-get install freetds-bin freetds-common unixodbc tdsodbc
php5-odbc
freetds-bin
提供了FreeTDS,还有tsql
和isql
(后面调试用)
freetds-common
已经安装在系统上,但不包括这两个调试工具。在定义配置后稍后安装 freetds-bin
没有问题。
unixodbc
是 ODBC 驱动程序
tdsodbc
为ODBC提供TDS协议
php5-odbc
是使用 ODBC 驱动程序的 php 模块。请注意,您的 php 版本可能与我的不同。
配置独立 unixODBC
/etc/odbcinst.ini
中的 ODBC 驱动程序设置:
[odbc]
Description = ODBC driver
Driver = /usr/lib/x86_64-linux-gnu/odbc/libtdsodbc.so
Setup = /usr/lib/x86_64-linux-gnu/odbc/libtdsS.so
UsageCount = 1
在 /etc/odbc.ini
:
中创建系统范围的数据源名称配置
[datasourcename]
Driver = odbc
Description = Standalone ODBC
Server = <IP or hostname>
Port = <port>
TDS_Version = 8.0
配置unixODBC和FreeTDS:
/etc/odbcinst.ini
中的 ODBC 驱动程序设置:
[odbc]
Description = ODBC driver
Driver = /usr/lib/x86_64-linux-gnu/odbc/libtdsodbc.so
Setup = /usr/lib/x86_64-linux-gnu/odbc/libtdsS.so
UsageCount = 1
在 /etc/odbc.ini
:
中创建系统范围的数据源名称配置
[datasourcename]
Driver = FreeTDS_odbc
Description = Uses FreeTDS configuration settings defined in /etc/freetds/freetds.conf
Servername = datasourcename
TDS_Version = 8.0
将 ODBC 数据源名称配置添加到 /etc/freetds/freetds.conf
中的 FreeTDS:
[datasourcename]
host = <IP or hostname>
port = <port>
client charset = UTF-8
tds version = 8.0
text size = 20971520
encryption = required
IMPORTANT: make sure that the odbc files are readable by the process
that will be reading them. If you are running your webserver using a
www-data
user, they must have the proper permissions to read those
files!
您现在可以在 freetds.conf
中设置连接字符集并使用 PDO 连接到数据库
$pdo = new PDO('odbc:datasourcename');
测试中:
使用 tsql
检查 FreeTDS 是否已配置并且可以连接到数据库。
tsql -S datasourcename -U username -P password
使用 isql
检查 ODBC 连接是否正确。
isql -v datasourcename username password
Link ODBC 与 PHP:
通过添加以下内容将 ODBC PHP 模块添加到 php.ini
:
extension = odbc.so
请注意,您的 php.ini
位置将取决于您使用的网络服务器。
使用 <?php phpinfo(); ?>
并通过网络服务器查看它以找到它的位置。
重新启动 Apache
编辑:
添加了有关驱动程序字符集功能的信息,因为我 运行 解决了独立 ODBC 配置的问题,它会忽略任何更改连接字符集的尝试。
总结
我正在尝试使用准备好的语句来停止 SQL 注入,但无法找到我需要的支持来保证它正常工作。
场景
我在 Linux 上托管一个站点,该站点连接到装有 FreeTDS 0.91 版的 Microsoft SQL 服务器,特别是使用 FreeTDS 的 dblib
。我已将数据库连接的 tds
版本设置为 7.4,并且正在使用 PHP 的 PDO 对象。
根据FreeTDS documentation,4.2不支持预处理语句:
TDS 4.2 has limitations
- ASCII only, of course.
- RPC is not supported.
- BCP is not supported.
- varchar fields are limited to 255 characters. If your table defines longer fields, they'll be truncated.
- dynamic queries (also called prepared statements) are not supported.
然而,没有任何迹象表明 7.4 不支持准备好的语句,这让我有理由相信它们至少不会引发驱动程序错误。
PHP 的 PDO 通过 PDO::setAttribute()
支持连接特定属性。
我感兴趣的是 PDO::ATTR_ERRMODE
将所有错误设置为异常,PDO::ATTR_EMULATE_PREPARES
如果兼容则强制数据库执行准备好的语句。
问题
测试连接时,我收到以下错误:
Database error: SQLSTATE[IM001]: Driver does not support this function: driver does not support setting attributes
无法设置 PDO::ATTR_EMULATE_PREPARES
,我无法保证数据库确实按预期执行准备好的语句。
有没有办法修改我的方法,或者有其他方法来 保证准备好的语句在 Linux?
的 MS SQL 服务器上安全执行解决方案
使用ODBC
代替dblib
,它提供了PDO的全部功能。
请注意,ODBC 有两种可能的配置:standalone ODBC and FreeTDS with ODBC driver。根据我的经验,要为连接设置字符集,必须使用 ODBC 驱动程序通过 FreeTDS 完成,使组合配置更可取。
ODBC 设置
我在网上搜索了许多不同的 Whosebug 帖子和各种文档资源,了解如何正确安装 ODBC。我从以下三个参考文献中提取了我的解决方案:
- unixODBC setup documentation
FlipperPA
对 setting up FreeTDS 的回答(顺便用 ODBC 完成)Benny Hill
对此setup issue with FreeTDS 的回答
下面是我在基于 Debian 的系统上使用 FreeTDS
配置 ODBC
的步骤列表。
TDS 8.0 支持准备好的语句。
注意:将不支持连接上的 SET NAMES a
或 SET CHARSET a
;需要通过设置 FreeTDS 属性使用组合配置来定义字符集。使用独立的 ODBC 驱动程序将字符集默认为 ASCII
,这会产生奇怪的结果。有关可能问题的示例,请参阅我的 other post。
安装需要的包:
sudo apt-get install freetds-bin freetds-common unixodbc tdsodbc php5-odbc
freetds-bin
提供了FreeTDS,还有tsql
和isql
(后面调试用)freetds-common
已经安装在系统上,但不包括这两个调试工具。在定义配置后稍后安装freetds-bin
没有问题。unixodbc
是 ODBC 驱动程序tdsodbc
为ODBC提供TDS协议php5-odbc
是使用 ODBC 驱动程序的 php 模块。请注意,您的 php 版本可能与我的不同。
配置独立 unixODBC
/etc/odbcinst.ini
中的 ODBC 驱动程序设置:
[odbc]
Description = ODBC driver
Driver = /usr/lib/x86_64-linux-gnu/odbc/libtdsodbc.so
Setup = /usr/lib/x86_64-linux-gnu/odbc/libtdsS.so
UsageCount = 1
在 /etc/odbc.ini
:
[datasourcename]
Driver = odbc
Description = Standalone ODBC
Server = <IP or hostname>
Port = <port>
TDS_Version = 8.0
配置unixODBC和FreeTDS:
/etc/odbcinst.ini
中的 ODBC 驱动程序设置:
[odbc]
Description = ODBC driver
Driver = /usr/lib/x86_64-linux-gnu/odbc/libtdsodbc.so
Setup = /usr/lib/x86_64-linux-gnu/odbc/libtdsS.so
UsageCount = 1
在 /etc/odbc.ini
:
[datasourcename]
Driver = FreeTDS_odbc
Description = Uses FreeTDS configuration settings defined in /etc/freetds/freetds.conf
Servername = datasourcename
TDS_Version = 8.0
将 ODBC 数据源名称配置添加到 /etc/freetds/freetds.conf
中的 FreeTDS:
[datasourcename]
host = <IP or hostname>
port = <port>
client charset = UTF-8
tds version = 8.0
text size = 20971520
encryption = required
IMPORTANT: make sure that the odbc files are readable by the process that will be reading them. If you are running your webserver using a
www-data
user, they must have the proper permissions to read those files!
您现在可以在 freetds.conf
中设置连接字符集并使用 PDO 连接到数据库
$pdo = new PDO('odbc:datasourcename');
测试中:
使用 tsql
检查 FreeTDS 是否已配置并且可以连接到数据库。
tsql -S datasourcename -U username -P password
使用 isql
检查 ODBC 连接是否正确。
isql -v datasourcename username password
Link ODBC 与 PHP:
通过添加以下内容将 ODBC PHP 模块添加到 php.ini
:
extension = odbc.so
请注意,您的 php.ini
位置将取决于您使用的网络服务器。
使用 <?php phpinfo(); ?>
并通过网络服务器查看它以找到它的位置。
重新启动 Apache
编辑: 添加了有关驱动程序字符集功能的信息,因为我 运行 解决了独立 ODBC 配置的问题,它会忽略任何更改连接字符集的尝试。