来自 MS SQL Server 通过 Linux 上的 PHP 的非模拟准备语句支持

Ste*_*ith 5 php linux sql-server pdo freetds

概括

我正在尝试使用准备好的语句来停止 SQL 注入,但我无法找到保证它正常工作所需的支持。


设想

我在 Linux 上托管一个站点,该站点连接到带有 FreeTDS 0.91 版的 Microsoft SQL Server,特别是使用 FreeTDS 的dblib. 我已将tds数据库连接的版本设置为 7.4,并且正在使用 PHP 的PDO对象。

根据FreeTDS 文档,4.2 不支持准备好的语句:

TDS 4.2 有限制

  • 当然,只有ASCII。
  • 不支持 RPC。
  • 不支持 BCP。
  • varchar 字段限制为 255 个字符。如果您的表定义了更长的字段,它们将被截断。
  • 不支持动态查询(也称为准备语句)。

然而,没有任何迹象表明 7.4 不支持准备好的语句,这给了我合理的信心,它们至少不会引发驱动程序错误。

PHP 的 PDO 支持通过PDO::setAttribute(). 我有兴趣PDO::ATTR_ERRMODE将所有错误设置为异常,并PDO::ATTR_EMULATE_PREPARES在兼容时强制数据库执行准备好的语句。


问题

测试连接时,我收到以下错误:

数据库错误:SQLSTATE[IM001]:驱动程序不支持此功能:驱动程序不支持设置属性

无法设置PDO::ATTR_EMULATE_PREPARES,我无法保证数据库实际上按预期执行准备好的语句。

无论如何要修改我的方法,或者是否有替代方法来保证准备好的语句在来自 Linux 的 MS SQL Server 上安全地执行?

Ste*_*ith 3

解决方案

使用ODBC代替dblib,它提供了 PDO 的全部功能。请注意,ODBC 有两种可能的配置:独立 ODBC带有 ODBC 驱动程序的 FreeTDS。根据我的经验,要设置连接的字符集,必须使用 ODBC 驱动程序通过 FreeTDS 来完成,这使得组合配置更可取。


ODBC 设置

我在网上搜索了许多不同的 StackOverflow 帖子和各种文档源,了解如何正确安装 ODBC。我从以下三个参考文献的混合中提取了我的解决方案:

下面是我在基于 Debian 的系统上配置ODBC使用的步骤列表。FreeTDS

TDS 8.0 支持准备好的语句。

注意:将不支持SET NAMES aSET CHARSET a在连接上;需要通过设置 FreeTDS 属性使用组合配置来定义字符集。使用独立的 ODBC 驱动程序将字符集默认为ASCII,这会产生奇怪的结果。有关可能问题的示例,请参阅我的另一篇文章。

安装需要的包:

sudo apt-get install freetds-bin freetds-common unixodbc tdsodbc php5-odbc

  • freetds-bin提供了FreeTDS,以及tsqland isql(用于后面调试)。
  • freetds-common系统上已安装,但不包括这两个调试工具。freetds-bin定义配置后稍后安装不会出现问题。
  • unixodbc是 ODBC 驱动程序
  • tdsodbc为 ODBC 提供 TDS 协议
  • php5-odbc是使用 ODBC 驱动程序的 php 模块。请注意,您的 php 版本可能与我的不同。

配置独立 unixODBC

ODBC 驱动程序设置/etc/odbcinst.ini

[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
Run Code Online (Sandbox Code Playgroud)

在以下位置创建系统范围的数据源名称配置/etc/odbc.ini

[datasourcename]
 Driver         = odbc
 Description    = Standalone ODBC
 Server         = <IP or hostname>
 Port           = <port>
 TDS_Version    = 8.0
Run Code Online (Sandbox Code Playgroud)

配置 unixODBC 和 FreeTDS:

ODBC 驱动程序设置/etc/odbcinst.ini

[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
Run Code Online (Sandbox Code Playgroud)

在以下位置创建系统范围的数据源名称配置/etc/odbc.ini

[datasourcename]
Driver          = FreeTDS_odbc
Description     = Uses FreeTDS configuration settings defined in /etc/freetds/freetds.conf
Servername      = datasourcename
TDS_Version     = 8.0
Run Code Online (Sandbox Code Playgroud)

将 ODBC 数据源名称配置添加到 FreeTDS 中/etc/freetds/freetds.conf

[datasourcename]
    host = <IP or hostname>
    port = <port>
    client charset = UTF-8
    tds version = 8.0
    text size = 20971520
    encryption = required
Run Code Online (Sandbox Code Playgroud)

重要信息:确保 odbc 文件可由将读取它们的进程读取。如果您使用用户运行网络服务器 www-data,他们必须具有读取这些文件的适当权限!

您现在可以设置连接字符集freetds.conf并使用 PDO 连接到数据库:

$pdo = new PDO('odbc:datasourcename');
Run Code Online (Sandbox Code Playgroud)

测试:

用于tsql检查 FreeTDS 是否已配置并且可以连接到数据库。

tsql -S 数据源名称 -U 用户名 -P 密码

用于isql检查 ODBC 是否正确连接。

isql -v 数据源名称 用户名 密码

将 ODBC 与 PHP 链接:

php.ini通过添加以下内容来添加 ODBC PHP 模块:

扩展名=odbc.so

请注意,您的php.ini位置取决于您使用的网络服务器。<?php phpinfo(); ?>通过网络服务器使用和查看它以查找其位置。

重新启动阿帕奇

编辑:添加了有关驱动程序字符集功能的信息,因为我遇到了独立 ODBC 配置的问题,它将忽略任何更改连接字符集的尝试。