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:
FlipperPA
à la mise en place de FreeTDS (accessoirement avec ODBC) 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.