Prise en charge des instructions préparées non émulées à partir de MS SQL Server via PHP sous Linux

Résumé

J'essaie d'utiliser des instructions préparées pour arrêter les injections SQL, mais je suis incapable de find le support dont j'ai besoin pour garantir le bon fonctionnement.


Scénario

J'héberge un site sur Linux qui se connecte à un server Microsoft SQL avec FreeTDS version 0.91, en utilisant spécifiquement le dblib de dblib . J'ai mis la version de tds à 7.4 pour la connection de database, et tds object PDO de PHP.

Selon la documentation FreeTDS , 4.2 ne supporte pas les instructions préparées:

TDS 4.2 a des limites

  • ASCII seulement, bien sûr.
  • RPC n'est pas supporté.
  • BCP n'est pas supporté.
  • Les champs varchar sont limités à 255 caractères. Si votre table définit des champs plus longs, ils seront tronqués.
  • Les requêtes dynamics (également appelées instructions préparées) ne sont pas sockets en charge.

Cependant, rien n'indique que le 7.4 ne prenne pas en charge les instructions préparées, ce qui me donne une confiance raisonnable, au less, qu'elles ne provoqueront pas d'erreur de pilote.

Le PDO de PHP supporte les attributes spécifiques à la connection via PDO::setAtsortingbute() . Je suis intéressé par PDO::ATTR_ERRMODE pour définir toutes les erreurs comme exceptions, et PDO::ATTR_EMULATE_PREPARES pour forcer la database à faire des instructions préparées si elle est compatible.


Problème

Lors du test de la connection, l'erreur suivante s'affiche:

Erreur de database: SQLSTATE [IM001]: le pilote ne prend pas en charge cette fonction: le pilote ne prend pas en charge les attributes de définition

Sans pouvoir définir PDO::ATTR_EMULATE_PREPARES , je ne peux pas garantir que la database exécute réellement les instructions préparées comme prévu.

Est-il possible de modifier mon approche, ou existe-t-il une approche alternative pour garantir que les instructions préparées sont exécutées de manière sécurisée sur un server MS SQL à partir de Linux?

Solution

Utilisez ODBC au lieu de dblib , qui fournit toutes les fonctionnalités de PDO. Notez qu'il existe deux configurations possibles d'ODBC: autonome ODBC et FreeTDS avec pilote ODBC . De mon expérience, pour définir le jeu de caractères pour une connection, il doit être fait via FreeTDS en utilisant le pilote ODBC, ce qui rend la configuration combinée préférable.


Configuration ODBC

J'ai cherché à travers de nombreux messages StackOverflow différents et diverses sources de documentation sur le Web sur la façon d'installer correctement ODBC. J'ai extrait ma solution d'un mélange des trois references suivantes:

  • documentation d'installation unixODBC
  • Réponse de FlipperPA à la mise en place de FreeTDS (accessoirement avec ODBC)
  • Réponse de Benny Hill à ce problème d'installation avec FreeTDS

Voici la list des étapes que j'ai utilisées pour configurer ODBC utilisant FreeTDS sur un système basé sur Debian.

TDS 8.0 prend en charge les instructions préparées.

REMARQUE: ne prendra pas en charge SET NAMES a ou SET CHARSET a sur une connection; les jeux de caractères doivent être définis à l'aide de la configuration combinée en définissant un atsortingbut FreeTDS. À l'aide du pilote ODBC autonome, le jeu de caractères ASCII défaut a donné des résultats bizarres. Voir mon autre post pour des exemples de problèmes possibles.

Installez require packages:

sudo apt-get installer freetds-bin freetds-commun unixodbc tdsodbc php5-odbc

  • freetds-bin fournit FreeTDS, ainsi que tsql et isql (utilisé pour le debugging plus tard).
  • freetds-common était déjà installé sur le système, mais n'incluait pas les deux outils de debugging. L'installation de freetds-bin à une date ultérieure après la définition d'une configuration ne cause aucun problème.
  • unixodbc est le pilote ODBC
  • tdsodbc fournit le protocole TDS pour ODBC
  • php5-odbc est le module php pour les pilotes ODBC utilisés. Notez que votre version de php peut différer de la mienne.

Configurer Standalone unixODBC

Paramètres du pilote ODBC dans /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 

Créez une configuration de nom de source de données à l'échelle du système dans /etc/odbc.ini :

 [datasourcename] Driver = odbc Description = Standalone ODBC Server = <IP or hostname> Port = <port> TDS_Version = 8.0 

Configurer unixODBC et FreeTDS:

Paramètres du pilote ODBC dans /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 

Créez une configuration de nom de source de données à l'échelle du système dans /etc/odbc.ini :

 [datasourcename] Driver = FreeTDS_odbc Description = Uses FreeTDS configuration settings defined in /etc/freetds/freetds.conf Servername = datasourcename TDS_Version = 8.0 

Ajoutez la config du nom de source de données ODBC à FreeTDS dans /etc/freetds/freetds.conf :

 [datasourcename] host = <IP or hostname> port = <port> client charset = UTF-8 tds version = 8.0 text size = 20971520 encryption = required 

IMPORTANT: assurez-vous que les files odbc sont lisibles par le process qui les lira. Si vous utilisez votre server web en utilisant un user www-data , ils doivent avoir les permissions appropriées pour lire ces files!

Vous pouvez maintenant définir le jeu de caractères de connection dans freetds.conf et vous connecter à la database avec PDO comme

 $pdo = new PDO('odbc:datasourcename'); 

Essai:

Utilisez tsql pour vérifier que FreeTDS est configuré et peut se connecter à la database.

tsql -S datasourcename -U nom d'user -P mot de passe

Utilisez isql pour vérifier que ODBC se connecte correctement.

isql -v datasourcename nom d'user mot de passe

Lien ODBC avec PHP:

Ajoutez le module PHP ODBC à php.ini en ajoutant ce qui suit:

extension = odbc.so

Notez que votre location php.ini dépend du server Web que vous utilisez. Utilisez <?php phpinfo(); ?> <?php phpinfo(); ?> et affichez-le via le server Web pour find son location.

Redémarrez Apache

EDIT: Ajout d'informations sur les capacités du jeu de caractères du pilote, car j'ai rencontré des problèmes avec la configuration ODBC autonome, où il aurait ignoré toute tentative de modification du jeu de caractères de la connection.