Bienvenue à Blogs CodeS-SourceS Identification | Inscription | Aide

CoqBlog

.NET is good :-)
{ Blog de Gaël Covain }

Actualités

Fatigué de supprimer le fichier "AuthoringTests.txt" (et Co) dans les projets de test ?

Je viens tout juste de découvrir via Greg l'existance de l'option qui va bien : il suffit d'aller décocher la checkbox "About Test Projects introduction file" (et en profiter pour régler 2/3 autres choses) dans les options de VS, section Test Tools/Test Project, que ce soit sous Visual Studio 2005

Options de Visual Studio 2005, Test Tools/Test Project

ou Visual Studio 2008

Options de Visual Studio 2008, Test Tools/Test Project

Voilà, il fallait juste savoir que l'option existait, personnellement je n'ai jamais penser que c'était le cas donc je n'ai jamais réellement chercher après...
On en apprend tous les jours :p

PowerGUI 1.5.1 RTM disponible

Une nouvelle version de PowerGUI est disponible.

Parmis les nouveautés, une qui devrait plaire aux amateurs de langue française : les localisations, dont le français dont je vous avais parler, sont maintenant intégrées au setup et sélectionnables facilement dans les 2 outils :

PowerGUI - sélection de la langue

PowerGUI Script Editor - sélection de la langue

 

Support de l'intellisense sur env et function :

PowerGUI Script Editor

 

Et il est aussi annoncé une intégration aux outils VMWare.
La liste complète des changements est disponible ici.

PowerGUI

Projet CLR Security sur CodePlex

Un nouveau projet Microsoft a été lancé sur CodePlex cette semaine : CLR Security.
Il s'agit tout simplement du projet du team du même nom et devrait être destiné à recevoir divers sous projets visant à étendre et apporter de nouvelles fonctionnalités aux APIs de sécurité intégrées au framework .NET, et probablement fournir des outils liés au développement avec ces APIs.

Le premier élément disponible est la libraire Security.Cryptography 1.0 (Security.Cryptography.dll) qui offre notamment des wrappers autours des APIs CNG (Cryptography API: Next Generation) :

L'utilisation de ces wrappers nécessite bien évidemment de cibler une plateforme Vista / Server 2008 (et supérieurs).

Avis aux amateurs.

.NET Security Blog : CLR Security Team CodePlex Site

PowerShell : Compare-Object est votre amie (exemple sur synchronisation répertoire par répertoire)

Aujourd'hui je me suis retrouvé avec un besoin relativement basique : effectuer un mirroir d'un répertoire donné.

Jusque là, pas de problème, l'ami robocopy et son paramètre MIR sont plutôt sympas pour ce genre de choses :

robocopy.exe ".\Rep" "\\Dest\Mirroirs\Rep" /MIR /FFT

Seulement voilà, executer cette commande avec une destination ne contenant aucun des fichiers de la source équivaut bien évidemment à la copie de toutes les données, dans mon cas ça veut dire 9 sous-répertoires totalisant 60Go de données.
Vu le volume et la vitesse du réseau (un petit 100Mbps), je préfère faire une copie sous-répertoire par sous-répertoire vers la destination avant de mettre en place la commande de mirroir qui se chargera de garder tout celà à jour.

Rien de bien compliqué :

robocopy.exe ".\Rep\SousRep1" "\\Dest\Mirroirs\Rep\SousRep1" /ZB /E

Sauf que je suis du genre flemmard et que je n'ai pas envie de faire 9 fois la modification de la commande à la main.
L'idéal serait donc de pouvoir lancer 9 fois (je veux garder le choix du moment de démarrage de chaque copie) un script qui choissise automatiquement le premier sous-répertoire de la source qui n'existe pas encore dans la destination.
Facile avec PowerShell : vous disposez de base de la sympathique Cmdlet Compare-Object qui comme l'indique permet de faire des comparaisons entre les paramètres ReferenceObject et DifferenceObject.
C'est exactement ce qu'il nous faut, une liste de répertoires pouvant bien entendu servir d'entrée pour cette cmdlet :-)

 

Prenez ce code, Src\Rep contenant 9 sous-répertoires et Dest\Rep étant vide :

$srcDir="D:\Temp\Tests\Src\Rep"
$targetDir="D:\Temp\Tests\Dest\Rep"
Compare-Object $(dir $srcDir | where{$_.PSIsContainer}) $(dir $targetDir | where{$_.PSIsContainer})

Vous obtenez :

InputObject       SideIndicator
-----------       -------------
SousRep1          <=
SousRep2          <=
SousRep3          <=
SousRep4          <=
SousRep5          <=
SousRep6          <=
SousRep7          <=
SousRep8          <=
SousRep9          <=

SideIndicator indique de quel côté se trouve le répertoire qui manque de l'autre côté : ici nous voyons donc que les sous-répertoires n'existent que dans la source.
La même commande executée avec le sous-répertoire "SousRep1" dans le répertoire cible donnera la sortie suivante :

InputObject       SideIndicator
-----------       -------------
SousRep2          <=
SousRep3          <=
SousRep4          <=
SousRep5          <=
SousRep6          <=
SousRep7          <=
SousRep8          <=
SousRep9          <=

Si vous désirez voir les répertoires existants des 2 côtés, le paramètre IncludeEqual est fait pour vous.
Mais là ça ne nous intéresse bien évidemment pas, nous allons de toute façon filtrer sur SideIndicator = "<=".

 

Dans le cas qui nous intéresse l'utilisation sera la suivante :

# répertoire source
$srcDir="D:\Temp\Tests\Src\Rep"

# répertoire cible
$targetDir="D:\Temp\Tests\Dest\Rep"

# définition du template de commande pour Robocopy
$robocopyCommand='robocopy.exe "$srcDir\$currentFolder" "$targetDir\$currentFolder" /ZB /E'

# Execution : 
# 1) Comparaison des listes des répertoires
# 2) Filtrage pour obtenir seulement la liste de ceux absent de la destination
# 3) Sélection du premier qui se trouve dans ce cas
# 4) Execution de la commande Robocopy pour effectuer la copie
Compare-Object $(dir $srcDir | where{$_.PSIsContainer}) $(dir $targetDir | where{$_.PSIsContainer}) | where {$_.SideIndicator -eq "<="} | select -First 1 | % { $currentFolder=$_.InputObject; Invoke-Expression -Command $robocopyCommand }

 

Ce script lancera ainsi une commande différente à chaque execution :

  1. robocopy.exe "D:\Temp\Tests\Src\Rep\SousRep1" "D:\Temp\Tests\Dest\Rep\SousRep1" /ZB /E
  2. robocopy.exe "D:\Temp\Tests\Src\Rep\SousRep2" "D:\Temp\Tests\Dest\Rep\SousRep2" /ZB /E
  3. etc

Ce qui me permet de faire ma mise en place en 9 fois sans me fatiguer plus que ça.

 

L'exemple pris ici n'est pas forcément parlant (et utile) pour tout le monde mais je pense qu'il s'agit cependant d'un exemple assez intéressant de l'utilisation de Compare-Object.

Bon scripting.

PowerGUI en Français

Pour ceux qui préfèrent avoir leurs outils en français (personnellement je me suis habitué aux softs US depuis longtemps), une traduction FR pour PowerGUI est maintenant disponible, grâce au travail de Mathieu Chateau.

PowerGUI avec la traduction FR

Une nouvelle traduction rejoint donc les autres déjà disponibles, avis aux amateurs.

PowerGUI.org - French Localization

 

PS : si vous vous trouvez dans le cas où la bascule ne se fait pas seule vers les ressources FR (le changement semble être basé sur la langue de l'OS et pas les paramètres régionaux), et que en éditant le fichier de configuration (quest.powergui.xml) comme indiqué vous ne trouvez pas la section spécifiant la langue (default ui language), c'est peut être dû à votre utilisation de PowerGUI assez ancienne : pour ma part j'ai opter pour la méthode "douce" suppression du profil, mais il y a peut être moins violent. A tout hasard je vous met la section en question :

<?xml version="1.0" encoding="utf-8"?>
<configuration id="57cbb640-6232-4995-99aa-f68bb734e51e">
 
<items>
   
<container id="0b8eebbc-08c6-472b-ae1b-57f1a96f3467" name="HostFactory" type="Quest.PowerGUI.WinFormFactory">
     
<value>Quest.PowerGUI.UI.WinForm, Version=1.5.0.434, Culture=neutral, PublicKeyToken=a69c32b63191909f</value>
     
<items>
       
<item id="08a2a9f3-6d8e-49cc-a59a-36f34166f603" name="default ui language">
         
<value>fr-FR</value>
       
</item>
     
</items>
   
</container>
...
 
</items>
</configuration>
L'injection SQL n'est PAS un problème QUE pour les développeurs web !

J'ai l'impression que pas mal de personnes sont parties sur une fausse idée avec ce problème d'injection SQL : certains ont l'air de penser qu'il s'agit uniquement d'un problème rencontré avec les applications dotées d'une interface utilisateur web (dans l'écosystème qui nous intéresse : ASP.NET, et toute les technologies reposant dessus).

 

 

L'injection SQL est uniquement un problème de développeur Web ?

Ce n'est absolument pas le cas : une application WinForm/WPF/Console/... sera impactée elle aussi.
Certes une application web offre probablement un risque d'exploitation de la faille plus élevé de par son exposition à un plus grand nombre de sources d'attaques, et certainement un nombre de points d'entrées plus important (zones de saisie, querystring, cookies, etc), mais il n'en demeure pas moins que l'utilisateur agissant de l'intérieur n'est pas plus digne de confiance qu'un anonyme sur le réseau (de l'entreprise ou internet).

 

 

Mais qu'est ce que l'injection SQL ?

L'attaque par injection SQL est une attaque reposant sur une faille de sécurité (défaut de vérification et sécurisation des entrées) dont le but à parvenir à provoquer l'exécution d'un code malicieux, initialement non prévu par le système vulnérable.
Pour cela, on procède tout simplement par insertion de ce code dans des chaînes de caractères qui seront par la suite utilisées pour bâtir un ordre SQL envoyé au serveur SQL pour exécution, en s'arrangeant pour qu'au final l'insertion dans une requête SQL rende notre code exécutable. Le serveur SQL n'a aucune raison valable de ne pas l'exécuter à partir du moment où il est valide.

Il se présente donc notamment si vous utilisez certains types d'informations pour les insérer dans des requêtes SQL sans prendre de précautions particulières :

  • saisies par l'utilisateur dans un formulaire (quelle que soit la technologie utilisée, pas forcément web)
  • provenant de champs cachés dans le formulaire
  • provenant de paramètre d'url (querystring)
  • provenant de cookies
  • ...

Mais recadrons les choses différemment : le problème d'injection SQL n'est pas seulement lié à un type d'interface de saisie, il n'est même pas lié seulement au fait que la donnée est saisie : il est lié à la donnée en elle même.
Le souci peut très bien se présenter dans un processus sans intervention humaine directe, avec par exemple traitement de données issues de fichier CSV/XML/... provenant de sources diverses. Ces données ont donc potentiellement été traitées par un être humain à un lointain bout de la chaîne, directement ou pas : le texte manipulé peut provenir d'une opération d'OCR par exemple.
Un autre point important à garder à l'esprit est que l'attaque par injection SQL n'est pas forcément à effet direct lorsque l'utilisateur saisi son code "malicieux" au travers du moyen approprié : ses effets peuvent être déclenchés durant toute la durée de vie de la donnée.

 

 

Seulement un problème de sécurité ?

Hormis le côté sécurité (vol, destruction, etc) du problème, il y a un autre aspect de la chose identique en tout point hormis le côté volontaire qui caractérise l'attaque par injection SQL : la corruption involontaire de l'ordre SQL. Cet aspect là, tout le monde doit le connaitre.
Certes il ne s'agit pas directement à proprement parler d'injection SQL vu qu'il ne s'agit pas réellement d'une attaque mais le fond est le même, et l'existence de ce problème de corruption rend l'attaque par injection SQL possible.

Un exemple courant est celui tout simple de la gestion de personnes : vous enregistrez des noms et prénoms, avec un code de ce genre pour la production du code SQL :

// NE PAS UTILISER CECI ! / DON'T USE THAT !
String query = String.Format(CultureInfo.InvariantCulture,
  "INSERT INTO [MonSchema].[MaTable] ([FirstName], [LastName]) VALUES ('{0}', '{1}');"
,
 
firstName,
 
lastName
 
);

Pas de chance, un beau jour vous devez enregistrer les informations d'une personne dont le nom comporte une apostrophe, et la requête générée a alors cet aspect là :

INSERT INTO [MonSchema].[MaTable] ([FirstName], [LastName]) VALUES ('Jean', 'D'upont');

Dans le meilleur des cas nous avons un ordre invalide et une erreur d'exécution, causant probablement des blocages, pertes financières, etc le temps de corriger le code mais peut être pas de corruption/destruction de données.
Par contre dans le pire des cas nous avons involontairement un code exécutable par le serveur différent de celui que nous avions prévu, qui ne sera peut être pas détecté dans l'immédiat si les effets produits ne sont pas flagrants, mais qui peut donc présenter un fort risque de corruption/perte de données.
Imaginez ici que l'opération d'OCR d'où provient le texte à persister porte sur un livre parlant de SQL, avec un exemple de code montrant comment supprimer les enregistrements de toutes les tables de la base courante...

Pour la suite de ce post, je considèrerais que les deux aspects du problème ne font qu'un, d'ailleurs les solutions pour l'un empêchent l'autre de se produire.
Les exemples sont quant à eux basés sur .NET (en C#) et SQL Server, mais le problème ne touche bien évidemment pas que ces technologies là.

 

 

Les solutions ?

Comment palier à ce problème ?
"Nettoyer" soit même les entrées est illusoire : vous ne connaissez probablement pas toutes les subtilités des différents moteurs de base de données, et ces moteurs sont de toute façon amenés à évoluer. "Nous modifierons le code à ce moment là" n'est pas une réponse valide : le code risque de mal vieillir.

Attention, soyons clair, je parlais bien ici de nettoyage en vue d'éviter la corruption de l'ordre SQL, pas de la nécessaire validation des entrées qui n'est pas directement attachée au problème dont nous parlons.
Il s'agit par exemple de la vérification des tailles, longueurs : si vous offrez une zone "commentaires", il y a des chances que vous ayez besoin pour elle de plus de 4000 caractères, auquel cas elle sera sans doute persistée en base sous forme d'un type nvarchar(MAX). Mais ça ne veut pas pour autant dire que vous voulez que la personne puisse envoyer 2Go de texte en base.

 

Les solutions en général proposées sont :

  • utiliser des requêtes paramétrées
  • utiliser des procédures stockées

Nous n'entrerons pas ici dans le débat de fond pour ou contre l'utilisation de procédures stockées, ce n'est pas le sujet.
A la liste précédente, nous pouvons ajouter : utiliser un outil de mapping objet/relationnel. Mais nous nous assurerons que le code SQL qu'il génère est bien évidemment paramétré et non pas basé sur de bêtes concaténations. Il ne s'agit pas de déporter le problème loin de nos yeux, mais d'ajouter une chance supplémentaire que les développeurs finaux ne fassent pas d'erreurs.
Cet outil va donc au final reposer sur une des solutions proposées, et donc est plus une couche supplémentaire qu'une solution directe. Sur le sujet qui nous concerne au travers de ce post, il aura surtout l'avantage de permettre aux architectes de limiter encore plus les risques de dérapage de la part des personnes qui exécutent le travail.

Est ce que ces 2 solutions se suffisent à elles mêmes ? Est ce que le simple fait de les utiliser suffit pour garantir la sécurité des données ? Non, il faut réellement que les personnes qui vont intervenir sur l'accès aux données comprennent ce problème.

Concernant les requêtes paramétrées, l'élément le plus proche de la requête dynamique habituelle (et dangereuse), et donc le plus simple à mettre en oeuvre à la place de cette dernière, il n'y a pas (à ma connaissance) grand chose de plus à faire pour sécuriser un peu plus.
Si la requête effectue un ordre INSERT, il faut que l'utilisateur ait directement ce droit sur les objets cibles.
Concernant les procédures stockées, il y a plus à dire. Le simple fait de déporter l'ordre INSERT dans une procédure stockée ne vous permet pas de passer magiquement d'un risque majeur à un risque zéro : encore faut t'il que l'appel de la procédure soit effectué de façon... paramétrée. En effet au final l'utilisation de procédures stockées est plus une couche supplémentaire qu'une solution directe au problème.

Rappelons qu'il y a au moins 2 moyens d'exécuter une procédure stockée depuis du code .NET : utiliser directement les facilités offertes par les objets d'accès aux données au travers de IDbCommand.CommandType en lui affectant CommandType.StoredProcedure, ou utiliser l'ordre EXECUTE dans un requête tout ce qu'il y a de plus commun.
On a tendance à oublier ce second moyen, mais le danger est pourtant bien à ce niveau là.
En utilisant CommandType.StoredProcedure, les données seront forcément spécifiée via l'implémentation de IDataParameter spécifique au provider utilisé, alors qu'au contraire avec l'utilisation de l'ordre EXECUTE vous avez le risque qu'un de vos développeurs écrive quelque chose de ce genre :

// NE PAS UTILISER CECI ! / DON'T USE THAT ! 
String query = String.Format(CultureInfo.InvariantCulture,
  "EXECUTE [MonSchema].[AddPerson] @FirstName='{0}', @LastName='{1}';"
,
 
firstName,
 
lastName
 
);

Du coup, vous avez ici un formidable exemple de fausse impression de sécurité : la personne a utiliser une procédure stockée, c'est donc sécurisé. Ce n'est bien sûr pas du tout le cas, la requête ayant cet aspect là pour notre ami Jean D'upont :

EXECUTE [MonSchema].[AddPerson] @FirstName='Jean', @LastName='D'upont';

Placez maintenant un ordre SQL là où il faut...
Vous devez donc bien faire attention à la façon dont sont compris les conseils que vous donnez.

 

C'est là qu'on arrive sur un autre aspect à prendre en compte lorsque l'on a opté pour l'utilisation exclusive de procédures stockées : la seule permission dont a réellement besoin l'identité utilisée (qui n'a bien entendu pas reçu le rôle db_owner, n'est ce pas) par l'application cliente pour l'accès à la base de données est EXEC sur ces fameuses procédures et rien d'autre, limitant ainsi les impacts d'une éventuelle attaque réussie.
C'est là que vous aurez besoin de dialoguer un peu avec votre DBA préféré, il doit aimer jouer avec ces choses là.

Il s'agit ici d'une autre "solution" directement couplée à l'utilisation de procédures stockées qu'on voit parfois abordée quand on parle de ce problème d'injection SQL : utiliser des permissions en exécution seule.
Je ne l'ai pas citée plus haut car ce n'en est pas réellement une. En effet elle ne permet en rien de résoudre directement le problème mais elle vient plutôt en complément et permet en partie de limiter les impacts d'une attaque réussie.

Attention, comprenons nous bien : la limitation des droits de l'utilisateur à de simples permissions en exécution ne vous permettrons pas pour autant de faire l'appel de la procédure stockée n'importe comment en tout sécurité.
En reprenant notre exemple précédent, si le code SQL injecté par l'assaillant est un ordre INSERT/UPDATE/etc sur une table, il échouera. Mais s'il s'agit encore de notre WHILE, il sera exécuté, provoquant une consommation excessive de ressources.
L'attaquant pourra aussi se reposer sur l'appel d'autres procédures stockées auxquelles à accès l'utilisateur, qui lui permettront peut être d'altérer/détruire les données.
Il se peut aussi qu'au travers d'une attaque il puisse accéder à un serveur lié et que cette liaison aie été effectuée, pour diverses raisons, avec des credentials possédant un niveau de privilèges plus élevé.
Sans parler des manipulations qui pourraient permettre d'arriver à une élévation de privilèges.

De manière générale limiter les privilèges de l'utilisateur au strict nécessaire n'est jamais une mauvaise chose (par exemple empêcher l'utilisation de choses comme xp_cmdshell, Database Mail, ... si l'utilisateur n'a aucune raison valable d'y avoir accès), mais vous ne pouvez pas considérer cette seule action comme suffisante.

 

 

J'ai vérifié le code traitant des données externes, je peux me reposer sur mes lauriers maintenant ?

Absolument pas !
Souvenez vous, j'ai dit plus haut que l'attaque n'était pas forcément à effet direct : si vous avez fait en sorte qu'un code malicieux saisi ne soit pas exécuté lors de l'enregistrement des données en base, vous ne pouvez pas arrêter oublier l'injection SQL et penser que vos données sont maintenant dénuées de tout risque.

Imaginez que votre utilisateur s'est identifié en tant que "Jean" / "Dupont'); WHILE 1=1 DECLARE @nb int; --".
Grâce à votre enregistrement des données avec une requête paramétrée, il dispose maintenant d'un nom assez ridicule dans votre application. Mais justement, son nom est bel et bien "Dupont'); WHILE 1=1 DECLARE @nb int; --" en base, sans aucune conséquence réelle pour l'instant vu que c'est une donnée.

Mais que se passe t'il si vous partez du principe qu'une fois en base vos données sont saines et que fort de ce sentiment vous utilisez une concaténation de chaînes pour bâtir un ordre au lieu de faire encore et toujours une requête paramétrée ?
Dans notre cas le "WHILE 1=1 DECLARE @nb int;" devient exécutable, vous aimez les boucles infinies ? (oui, il y a des timeouts, mais tout de même).

La règle est toujours aussi simple : si vous devez utiliser des données provenant de votre base pour bâtir d'autres requêtes, utilisez des paramètres / procédures stockées (correctement appelées). Et de toute façon, comme dit plus haut, vous n'êtes toujours pas à l'abri d'un apostrophe légitime, donc pourquoi prendre ce risque d'obtenir un ordre SQL invalide même si les données stockées sont dignes de confiance (si ça arrive réellement...) ? Et repensez aussi au coup de l'OCR...

 

 

Et dans le code des procédures stockées ? (ou le restant du batch d'une requête paramétrée)

Voilà un dernier point auquel on ne pense pas forcément, et pourtant le risque est bien là : vous ne devez pas faire n'importe quoi non plus dans le code SQL utilisant les paramètres, que ce soit un simple batch ou une procédure stockée, fonction, ...
La simple utilisation de procédures stockées (et des paramètres en général) ne vous garanti pas que votre donnée est définitivement saine, ça vous garanti juste que la donnée sera transmise en tant que tel.

Pour illustrer, prenons l'exemple d'une procédure stockée permettant de faire une recherche des personnes dont le nom commence par celui d'une autre, et que pour une raison valable (dans l'exemple courant il n'y en a pas réellement) vous effectuez cette recherche au moyen d'une requête dynamique définie dans le corps de la procédure :

-- NE PAS UTILISER CECI ! / DON'T USE THAT 
CREATE PROCEDURE [MonSchema].[FindPersonBAD] 
( 
   
@LastName  nvarchar(256) 
) 
AS 
BEGIN 
    
   
-- NE PAS UTILISER CECI ! / DON'T USE THAT 
    DECLARE @sql nvarchar(4000);
    
   
SET @sql = N'SELECT [FirstName], [LastName] 
        FROM [MonSchema].[MaTable] 
        WHERE [LastName] LIKE '''
+ @LastName + N'%'''; 
    
   
EXECUTE (@sql); 
   
-- NE PAS UTILISER CECI ! / DON'T USE THAT 

END 

Si jamais un agresseur a prévu ce genre de cas, et que son nom est "Dupont%'; WHILE 1=1 DECLARE @nb int; --", vous venez une nouvelle fois de revivre le coup de la boucle infinie (certes vos DBA, si DBA il y a, ont probablement limités les effets de ce code précis en limitant la durée maximum d'exécution des requêtes mais quand même...).
Si ça ne vous suffit pas, imaginez un remplacement de la boucle par un code plus "sympathique", comme un ordre UPDATE : corruption d'informations et impact sur les performances en cas de table très volumineuse.

Si vous devez vraiment utiliser du SQL dynamique dans votre code SQL, ayez au moins le réflexe de passer par des paramètres : la procédure sp_executesql vous permet d'y arriver très simplement :

CREATE PROCEDURE [MonSchema].[FindPerson] 
( 
   
@LastName  nvarchar(256) 
) 
AS 
BEGIN 
    
   
-- TODO : valider les entrées
    
   
DECLARE @sql nvarchar(4000);
    
   
SET @sql = N'SELECT [FirstName], [LastName] 
        FROM [MonSchema].[MaTable] 
        WHERE [LastName] LIKE @Name+''%'''
; 
    
   
EXECUTE sp_executesql 
       
@stmt = @sql, 
       
@params = N'@Name nvarchar(256)', 
       
@Name = @LastName; 

END

Bien sûr, dans l'hypothèse que le SQL dynamique soit réellement nécessaire : dans le cas contraire, passez vous en.

 

 

Et là où on ne peut vraiment pas utiliser de paramètres ?

Il peut se présenter des cas pour lesquels utiliser un paramètre directement dans la requête n'est réellement pas possible, comme par exemple avec une clause TOP avec des versions de SQL Server inférieures à SQL Server 2005.

Dans ce cas vous devrez vous même assurer la sécurité, et donc prendre les mesures qui s'imposent : validation des types, validation des longueurs, ...
Dans le cas présent, il y a de fortes chances que votre valeur aie été passée à la procédure stockée sous forme d'un paramètre type int/bigint/float, mais n'oubliez pas de valider la plage de valeurs possible : si dans votre esprit la taille des pages affichées par votre application peut aller de 10 à 100 lignes, un attaquant aura peut être l'envie d'en demander quelques millions...

Si c'est du SQL dynamique généré côté client, n'insérez pas directement la valeur de filtrage à partir d'une chaîne : passez par Int32/Int64/Double (via TryParse si disponible), ça vous permettra de valider le type et la plage assez facilement.

Si la donnée est typée texte, ne cédez pas pour autant à la fatalité : par exemple s'il s'agit de manipuler des identifiants d'objets, vérifiez que la valeur qui vous a été spécifiée est bien celle d'un objet existant (voir OBJECT_ID, OBJECT_NAME, OBJECT_SCHEMA_NAME, etc)

 

Bonne revue de code.

Sandcastle et CodePlex : le verdict

Je vous en parlais la dernière fois, le projet Sandcastle avait été mis en état non publié pour cause de non respect des termes d'utilisation de CodePlex.

Les choix envisagés par l'équipe du projet était alors :

Et c'est donc la première solution qui a été retenue : Sandcastle Source Code published in Codeplex

Les "Tracepoint" ? C'est sympa ! (et ce n'est pas nouveau)

Ces temps ci je vois certains s'extasier sur une "nouvelle" fonctionnalité de VS2008 : les Tracepoint (points de trace).

Eh bien ce n'est pas nouveau, je vous en avais parler en mai 2006, pour Visual Studio 2005 donc : Les Tracepoint ? C'est sympa !
Ce post ayant relativement mal vécu le changement de skin du blog (les images sont tronquées), je vais le représenter ci dessous :-)

 

Il s'agit, en gros, de l'équivalent d'un point d'arrêt sur lequel vous allez pouvoir notamment choisir d'envoyer un message vers la sortie du debugger, et, partie la plus intéressante, de continuer ou non l'exécution sans marquer d'arrêt.
Dans ce cas, on peut comparer le fonctionnement à l'insertion d'un appel à System.Diagnostics.Debug.WriteLine/System.Diagnostics.Trace.WriteLine, mis à par :

  • vous n'avez pas besoin de modifier le code
  • l'exécution ne se fait que si le debugger est attaché
  • la suppression des constantes DEBUG/TRACE ne supprime pas l'affichage du message si le debugger est attaché (il ne s'agit pas d'une compilation conditionnelle, mais bien d'une fonction propre à Visual Studio)
  • vous avez accès aux possibilités de réglages sur les breakpoint (test de condition, nombre d'accès, etc etc)

Au lieu de modifier votre code comme ceci :
Présentation des points de trace (Tracepoints) - Exemple de code

Vous pouvez maintenant ajouter un Tracepoint : 
Présentation des points de trace (Tracepoints) - Exemple de code avec Tracepoint

Soit en partant de zéro en passant par "Insérer un point de trace" :
Présentation des points de trace (Tracepoints) - Insérer un Tracepoint

Soit en transformant un point d'arrêt existant via "Lorsqu'il est atteint..." (Aaah, le bon vieux F9 ;-) ) : 
Présentation des points de trace (Tracepoints)

Il vous suffit de renseigner les champs comme ceci :
Présentation des points de trace (Tracepoints)

Vous aurez ainsi en sortie : 
Présentation des points de trace (Tracepoints)

Prenons maintenant un cas "plus poussé", c'est à dire celui du travail dans une méthode dont le passage en arrière plan, y compris sur un break donc, provoque un nouveau passage, qui provoque un nouveau passage, qui provoque un nouveau passage, qui [...] (Paint, Focus etc).

Soit un code de dessin de ce genre (très poussé, lui aussi) :
Présentation des points de trace (Tracepoints) - Exemple de code avec OnPaint

Vous voulez afficher sur votre sortie les coordonnées du point de dessin, mais seulement si une CheckBox est cochée.

Avant, vous pouviez écrire ce genre de chose :
Présentation des points de trace (Tracepoints) - Exemple de code avec OnPaint - utilisation de TRACE

Maintenant, il vous suffit de définir votre action comme ceci :
Présentation des points de trace (Tracepoints) - Exemple de code avec OnPaint - paramètre de tracepoint pour remplacer TRACE

Couplée avec la condition suivante pour le point d'arrêt :
Présentation des points de trace (Tracepoints) - Exemple de code avec OnPaint - condition de point d'arrêt

Et le code n'a pas changé :
Présentation des points de trace (Tracepoints) - Exemple de code avec OnPaint - avec Tracepoint

Sympa, non ?

FxCop et Code Analysis : écrire ses propres règles

Voici une documentation qui devrait faire plaisir à ceux qui veulent écrire des règles pour FxCop ou le Code Analysis de Visual Studio : Jason Kresowaty nous offre son "FxCop and Code Analysis: Writing Your Own Custom Rules" (ce n'est pas nouveau, mais ça fait partie des liens qu'on ne retrouve pas facilement quand on en a besoin).
Cette documentation est orientée vers FxCop 1.36 Beta 2 et Visual Studio 2008, mais je rappelle que FxCop 1.36 permet l'analyse d'assemblies .NET 1.x, 2.0 et 3.x.

La version actuelle du document (1.4 datée du 07/05/2008) est consultable soit en ligne, soit sous forme d'un pdf d'une bonne trentaine de pages.

Naturellement, il ne s'agit pas d'une documentation officielle, vous l'utilisez donc bien évidemment en l'état.

FxCop and Code Analysis: Writing Your Own Custom Rules

PowerShell : provider Windows Mobile et management Hyper-V

Voici deux projets autour de PowerShell qui pourrait en intéresser certains :

Le premier est un provider pour travailler avec des appareils Windows Mobile sur un panel assez large (PocketPC/SmartPhone 2002, 2003, 2003SE, Windows Mobile 5, 6 et 6.1), notamment au niveau des manipulations de fichiers.
Je n'ai pas encore eu le temps de tester, mais le post de présentation par Oisin Grehan est assez parlant.
Rien que pour les fichiers c'est intéressant : vous aimez vraiment les copies de fichiers via l'explorer vous ?
PowerShell Windows Mobile Provider

Le second devrait intéresser les utilisateurs d'Hyper-V, vu qu'il s'agit d'un projet (encore en phase beta lui aussi) qui offre à l'heure actuelle plus de 50 fonctions permettant de jouer avec Hyper-V depuis PowerShell.
Avis aux amateurs, il me semble qu'il y en a quelques uns qui trainent dans le coin.
PowerShell management Library for Hyper-V

Liste de changements brisants pour ASP.NET si utilisé avec le mode intégré de IIS 7.0

Dans le genre post qu'on ne retrouve jamais quand on en a besoin, celui-ci bien sympathique de Mike Volodarsky : une liste de 25 problèmes, accompagnés de l'explication qui va avec, qui peuvent survenir lors de la migration d'une application ASP.NET vers IIS 7.0 en mode intégré.

Breaking Changes for ASP.NET 2.0 applications running in Integrated mode on IIS 7.0

Sondage autour de la documentation disponible pour Visual Studio/.NET

Un post sur le blog du team BCL nous invite à répondre à un court sondage (en anglais) portant sur la documentation disponible autour de .NET : comment vous l'utilisez actuellement, la façon dont vous y accédez/faites des recherches, l'intérêt de l'avoir disponible hors ligne (c'est cool), etc

BCL Team Blog : .NET Framework Developer Documentation Survey [Matthew Connelly]

Mais où est passé Sandcastle ?

Si vous avez tenter d'obtenir les binaires de Sandcastle ces derniers temps, vous aurez sans doute remarqué que son projet sur CodePlex est actuellement marqué comme non publié.

Cette situation est tout à fait "normale", cette décision a été prise début juin en raison du fait que ce projet ne respectait pas vraiment les termes de sa licence et aussi les termes d'utilisation de l'hébergement sur CodePlex : nous n'avons en effet jamais eu les sources.
Voir entre autres les posts suivants : Port 25 : Sandcastle Removed from Codeplex et CodePlex Weblog : Removal of "Sandcastle" Project

Ainsi, les différentes solutions envisagées par l'équipe de ce projet sont :

En attendant la décision sur ce point, vous pouvez comme annoncé hier retrouver les binaires de Sandcastle sur le Download Center : Sandcastle - Version 2.4.10520
La version de SHFB qui va bien est elle aussi disponible : Sandcastle Help File Builder 1.7.0.0

CodeProject : page d'explication sur les licences

CodeProject: Licenses

Une page offrant un aperçu de différentes licences, ça peut être (très, très, ...) pratique.
Si vous connaissez d'autres pages du même genre (et si c'est en français c'est encore mieux :p), n'hésitez pas à laisser un commentaire.

VHD : images Windows Server 2008 Evaluation pour Virtual Server 2005 et Hyper-V

De nouvelles images sont disponibles sur le Download Center.
Pour rappel ces disques virtuels permettent d'avoir rapidement un produit en état de fonctionnement (pour une période d'évaluation, les OS installés expirent) sans passer par la phase de déploiement, ce qui est toujours appréciable.

Ces nouvelles images devraient intéresser du monde, vu qu'il s'agit de Windows Server 2008.

Ici nous avons le Windows Server 2008 seul, disponible à la fois pour Virtual Server 2005 mais aussi pour Hyper-V :

Ces images contiennent une installation de la version d'évaluation de Windows Server 2008 Enterprise Edition et offrent une période d'évaluation de 60 jours, pouvant être au besoin étendue par la procédure de réinitialisation habituelle, permettant au final d'aller jusqu'à 240 jours.
Chaque page de téléchargement donnent accès à 2 images : une installation complète et une installation Core. Chacune de ces installations est disponible soit en téléchargement fractionné (rar multipart), soit en un seul fichier (zip monopart). (Au passage la taille de WS08_ServerCorex86_Enterprise.part2.rar est ... intéressante ;-))

Outil : Windows Updates Downloader

Voilà un outil qui peut se révéler pratique. Je viens de le découvrir via un post de David Sebban : comme son nom l'indique, il permet de télécharger les patchs qui sont censés se trouver sur Windows Update.
Il fait ceci grace à des listes de mises à jour, vous aurez donc typiquement la liste des patchs sortis depuis le dernier service pack du produit cible.

image

Toujours bon à connaitre, en complément du site Microsoft Update Catalog qui permet déjà d'obtenir les setups de mises à jour.

Windows Updates Downloader

Les outils Sysinternals (Process Explorer, Process Monitor, PsTools, ...) en "live"

Les indispensables outils Sysinternals sont maintenant accessibles directement en ligne via un répertoire en UNC sur \\live.sysinternals.com :

\\live.sysinternals.com\Tools : les outils directement executables (pas dans des zips)
\\live.sysinternals.com\Files : les zips, y compris la Sysinternals Suite (donc attention si vous faites de la synchro sur ce répertoire)

Au besoin, le listing du partage Tools est aussi accessible via http ici : http://live.sysinternals.com/

 

Donc plus d'excuses pour ne pas avoir la dernière version de ces outils, car accès via UNC ça veut dire quoi :

  • utilisation facile depuis un simple prompt PowerShell par exemple, comme avec n'importe quel autre répertoire :
    • La liste des fichiers ? :
      PS> dir \\live.sysinternals.com\Tools | where { !$_.PSIsContainer } | sort -Property LastWriteTimeUtc -Descending
    • La liste des fichiers modifiés depuis 15 jours ? :
      PS> dir \\live.sysinternals.com\Tools | where { !$_.PSIsContainer -and $_.LastWriteTimeUtc -gt [datetime]::UtcNow.AddDays(-15) } | sort -Property LastWriteTimeUtc -Descending
  • vous pouvez mapper en lecteur réseau, donc c'est aussi utilisable depuis cmd
  • vous pouvez utiliser Robocopy dessus, donc pour la synchronisation ça ne va pas être trop dur

Il existait déjà d'autres outils, comme notamment un script PowerShell, mais maintenant c'est vraiment simple :-)

Windows Sysinternals

Posted: samedi 7 juin 2008 11:34 par coq | 0 commentaire(s)
Classé sous :
Microsoft Source Analysis for C# (aka StyleCop), un camarade pour FxCop

Un nouvel outil est disponible pour les développeurs C#. Comme son nom l'indique il s'agit d'un analyseur de code C#, qui contrairement à ce bon vieux FxCop agit sur les sources et non sur les binaires.
En gros on peut dire que StyleCop (heu oui, je préfère le nom court) agit plus sur la forme et FxCop sur le fond, les 2 outils sont donc complémentaires.

StyleCop s'intègre à Visual Studio 2005 et Visual Studio 2008, et peut être utilisé avec MSBuild.
A première vue, très intéressant, plus qu'à utiliser sur la longueur :-)

Microsoft Source Analysis for C#
Blog dédié à StyleCop
Documentation des rules

 

Microsoft Source Analysis for C# dans VS2008

Microsoft Source Analysis for C# dans VS2008

Microsoft Source Analysis for C# dans VS2008 - Settings

Microsoft Source Analysis for C# dans VS2008 - Liste des rules