7
votes

Pourquoi je reçois un résultat différent de deux expressions presque égales pour obtenir des données de la base de données à l'aide d'un cadre de cadre d'entité

Je validons le nom d'utilisateur (insensible à la casse-insensible) et le mot de passe (sensible à la casse) de la base de données

J'utilise l'entité Framework 5.0 pour interagir avec la base de données

dans le mot de passe de la base de données est

"0x11A46971FFFE1A2CA228CF592CA37DC77E7CCF759602D53629C22B693AEEE96CCD9F889D8E9A92C19391E9A92C19391E9A92C939E391ACDC939E391ACDC939B993C9D7F5D"

Je m'attends à NULL en retour pour mon bloc de code suivant lorsque je change de cas de mot de passe pour abaisser I.E.

"0x11A46971FFFE1A2CA228CF592CA37DC77E7CCF759602D53629C22B693AEEE96CCD9F889D8E9A92C19391E9A92C19391E9A92C939E391ACDC939E391ACDC939B993C9D7F5D"

mais cela ne échoue pas et renvoie une entité utilisateur appropriée. xxx

null xxx

c'est étrange? Pourquoi ça se passe? Comment rédiger une requête sensible à la casse à SQL de Linq?


5 commentaires

Que se passe-t-il lorsque vous courez le SQL manuellement?


X.Authentification Secret.equals (mot de passe) vscode> x.password.equaux (mot de passe)


N'utilisez pas non plus context.utilisateur.tolist (); , il itière sur tout le tableau.


@Ahmedkraiem qui était de type, édité la question s'il vous plaît voir.


@ Daniela.White Les deux requêtes reviennent true (j'ai eu que SQL est insensible à l'affaire)


6 Réponses :


7
votes

Lorsque vous utilisez

var users = context.Users.ToList();


0 commentaires

12
votes

SQL n'est pas sensible à la casse. Si vous avez examiné le SQL généré, cela ressemblerait à ceci comme suit:

EXISTS(SELECT * FROM Users WHERE userName = 'foo' AND Password = '0x11a46971eff1e1a2ca228cf592ca37dc77e7ccf759602d53629c22b693aeee96ccd9f889d8e9a92c19391e6bd2dd07e741e9b7aa07e391acdc939b993c9d7f5d')


3 commentaires

Je crois que vous pouvez rendre la casse SMSQL sensible en spécifiant une assiette sensible à la casse pour cette colonne.


Vous pouvez oui, vous modifiez la méthode de cette colonne de cette colonne. Ce n'est pas quelque chose que je recommanderais car si vous n'êtes pas au courant du changement, vous pouvez obtenir des résultats inattendus. blog.sqlauthority.com/2007/04/30 / ...


En outre, le mot de passe est en fait codé de manière à ne pas considérer la sensibilité au cas. 0xaa et 0xaa sont fonctionnellement équivalents.



2
votes

La recherche SQL est insensible à la casse et lorsque vous faites le tolist code> vous finissez par faire une comparaison sensible à la casse. Mais le tolist code> retournera tout de la DB. Au lieu de faire le où code> sur la base de données db, puis une autre comparaison pour vous assurer que le mot de passe est le cas correct.

using (var context = new MyDbContext(ConnectionString))
{
  var users = context.Users.Where(x => x.Name == userName && x.Password == password).ToList();
  return users.FirstOrDefault(x =>  x.Password.Equals(password)));
}


2 commentaires

Sauf si vous ne le jetez pas pour la liste, cela comparera de manière insensible à la casse. J'ai édité votre réponse en ajoutant .tolist (); à la fin du premier linq à SQL


Cela n'est pas possible dans mon scénario que deux utilisateurs ont le même nom d'utilisateur, il convient donc à la base de la base de données de requête avec le nom d'utilisateur et le mot de passe insensible à casse et vérifiez plus tard uniquement pour le mot de passe sensible à la casse.



1
votes

Il y a une réponse plus détaillée à cela ici:

https://stackoverflow.com/a/3843382/933416

Si vous en avez besoin, vous pouvez configurer la colonne pour être sensible à la casse du côté serveur. Mais dans votre cas, je ne vois pas pourquoi vous avez même besoin d'interroger le mot de passe. Il n'y a sûrement qu'un mot de passe pour chaque nom d'utilisateur et un nom d'utilisateur est censé être insensible à la casse - alors pourquoi pas seulement interroger le nom d'utilisateur, puis vérifier le mot de passe sur le résultat?


1 commentaires

Ne laissez pas les détails de l'utilisateur de la boîte SQL sans vulnérabilité de sécurité authentifiée.



2
votes

Comme @nmClean mentionné, c'est parce que votre base de données est configurée pour effectuer des comparaisons insensibles de cas. Le petit programme suivant montre comment EF ignore complètement les valeurs code> StringComParison code> transmettes à string.equals code>. Il montre également comment changer la collation de la colonne de base de données permet de réaliser ce dont vous avez besoin.

Il s'agit d'un concept impossible lorsque vous travaillez avec EF (et d'autres fournisseurs LINQ également). Votre requête tel qu'il est écrit looks em> comme le code .NET normal. Cependant, ce n'est pas! De nombreux fournisseurs traduisent le code à quelque chose de complètement différent, dans ce cas SQL (pour SQL Server, Transact-SQL). Seul un sous-ensemble des méthodes .NET disponibles fonctionnera du tout (c'est pourquoi, par exemple, vous ne pouvez pas utiliser regex code> dans une requête EF), et ceux qui travaillent peuvent présenter un comportement subtilement différent. comparé à ce que vous attendez. p>

où vous utilisez tolist () code> sur une requête, puis em> Appliquez votre filtre, vous utilisez réellement LINQ vers des objets , pas ef, pour appliquer le filtre. Linq aux objets est em> "réel" .NET, vous disposez donc de la gamme complète de fonctionnalités .NET à votre disposition. Bien sûr, vous perdez l'avantage d'avoir votre code exécuté sur le serveur SQL, ce n'est donc généralement pas une option. P>

using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity;
using System.Linq;

namespace ConsoleApplication2
{
    public class Initializer<T> : DropCreateDatabaseAlways<T> where T : DbContext
    {
        protected override void Seed(T context)
        {
            base.Seed(context);

            // Comment out this line and note how the count changes.
            context.Database.ExecuteSqlCommand("ALTER TABLE MyEntity ALTER COLUMN MyString nvarchar(MAX) COLLATE Latin1_General_CS_AS");
        }
    }

    [Table("MyEntity")]
    public class MyEntity
    {
        [Key]
        public virtual int MyEntityId { get; set; }

        [Required]
        public virtual string MyString { get; set; }
    }

    public class MyContext : DbContext
    {
        public DbSet<MyEntity> Entities
        {
            get { return this.Set<MyEntity>(); }
        }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);

            var e = modelBuilder.Entity<MyEntity>();
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Database.SetInitializer(new Initializer<MyContext>());

            using (MyContext context = new MyContext())
            {
                context.Entities.Add(new MyEntity { MyString = "aaa" });
                context.Entities.Add(new MyEntity { MyString = "AAA" });

                context.SaveChanges();
            }

            using (MyContext context = new MyContext())
            {
                var caseSensitiveQuery = from e in context.Entities
                                         where e.MyString.Equals("aaa", StringComparison.Ordinal)
                                         select e;

                var caseInsensitiveQuery = from e in context.Entities
                                           where e.MyString.Equals("aaa", StringComparison.OrdinalIgnoreCase)
                                           select e;

                // Note how the StringComparison parameter is completely ignored.  Both EF queries are identical.
                Console.WriteLine("Case sensitive query (count = {0}):\r\n{1}", caseSensitiveQuery.Count(), caseSensitiveQuery);
                Console.WriteLine();

                Console.WriteLine("Case insensitive query (count = {0}):\r\n{1}", caseInsensitiveQuery.Count(), caseInsensitiveQuery);
            }

            Console.ReadLine();
        }
    }
}


2 commentaires

Vous pouvez oui, vous modifiez la méthode de cette colonne de cette colonne. Ce n'est pas quelque chose que je recommanderais car si vous n'êtes pas au courant du changement, vous pouvez obtenir des résultats inattendus. blog.sqlauthority.com/2007


@Imranrizvi - Je ne suis pas sûr d'être d'accord avec ça. Il est vrai que les collations sont souvent une source de confusion, mais elles existent pour une raison. La classement d'une colonne doit être sélectionnée en fonction du comportement de tri et de comparaison souhaité. Ususally une collation est appropriée pour une base de données ou serveur entière, mais ici il y a une bonne raison de s'écarter de cela. En ce qui concerne l'observation, "Vous pouvez obtenir des résultats inattendus", pourrait affirmer que vous obtenez déjà des résultats inattendus! Le changement de collation vous donnerait ce que vous espérez tout le long!



-1
votes

Comme tout le monde l'a déjà mentionné, la cause du problème est que SQL Server par défaut de non sensible à la casse et c # par défaut à la case sensible à la casse.

Vous pouvez modifier le champ de mot de passe de varchar à varbinaire pour contourner ce problème.


Pourquoi les votes anonymes en bas? En utilisant une chaîne pour stocker et comparer ce qui semble être une valeur de hachage de 64 octets n'est pas la meilleure approche. Il n'est pas nécessaire de fonder 64 encoder un hachage à stocker (sauf si l'entité framework ne peut pas le gérer?).

http://support.microsoft.com/kb/307020 - Comment calculer et comparer les valeurs de hachage En utilisant Visual C # comparer les mots de passe de hachage


1 commentaires

En effet! Et ef prend en charge varbinary ; Il correspond à un .NET octet [] .