Maison > Article > base de données > Comment utiliser Hibernate pour empêcher l'injection SQL
Avant d'écrire du code, transmettez une instruction Hql ou Sql de type String organisée en arrière-plan pour exécution.
C'est en fait une approche très stupide ! ! ! !
Imitons le scénario de connexion de l'utilisateur :
Une approche courante consiste à amener l'utilisateur à la réception Le nom et le mot de passe sont fusionnés dynamiquement dans l'instruction de requête sous forme de chaînes, puis la requête de base de données est appelée. Si le résultat de la requête n'est pas nul, cela signifie que l'utilisateur existe et que la connexion est réussie, sinon la connexion échoue !
Normalement, le numéro de compte saisi par l'utilisateur est 123456 et le mot de passe 123 (en supposant qu'il s'agit d'un mot de passe erroné ou que l'utilisateur n'existe pas du tout)
usernameString//前台输入的用户名passwordString//前台输入的密码//hql语句String queryString = "from User t where t.username= " + usernameString + " and t.password="+ passwordString;//执行查询List result = session.createQuery(queryString).list();
Pour une saisie utilisateur normale, l'instruction SQL est divisée en : de l'utilisateur t où t.username=123456 et t .password=123;
Il s'agit d'une instruction SQL normale. Vous pouvez interroger la base de données pour vérifier si ces données utilisateur existent.
Mais !
Si l'utilisateur saisit : 123 ou 1=1 dans la zone de saisie du mot de passe, il est passé en arrière-plan sous forme de chaîne
L'instruction sql est épissé dans : de l'utilisateur t où t.username=123456 et t.password=123 ou 1=1;
Une fois Add ou 1=1, alors ce sql sera toujours vrai ! ! ! Les cas plus graves incluent la suppression de tables dans la base de données et la falsification d'informations, ce qui est extrêmement grave ! ! !
La raison de l'injection SQL est superficiellement parce que les chaînes sont épissées pour former des instructions SQL, et les instructions SQL ne sont pas précompilées ou des variables liées ne sont pas utilisées.
Mais la raison la plus profonde est que la chaîne saisie par l'utilisateur est exécutée comme une "instruction SQL".
Par exemple, la chaîne ci-dessus queryString = "from User t où t.username= " + usernameString + " et t.password="+ passwordString;
Nous espérons que les valeurs du nom d'utilisateur et du mot de passe saisies par l'utilisateur seront transmises à la base de données pour exécution uniquement sous forme de valeur littérale de chaîne.
Mais lors de la saisie : 123 ou 1=1, ou 1=1 n'est pas utilisé comme valeur littérale de Where id=, mais comme l'instruction SQL est exécuté. Son essence est donc d’exécuter les données saisies par l’utilisateur sous forme de commande.
En gros, tout le monde sait que adopte la précompilation Les instructions SQL et les variables de liaison sont les meilleurs moyens de se défendre contre l'injection SQL. Pour éviter l'injection SQL, évitez de reconstituer les instructions SQL ! ! !
Dans les projets réels, nous utilisons généralement divers frameworks, tels que ibatis, hibernate, mybatis, etc. Ils sont généralement précompilés par défaut en SQL. Pour ibatis/mybatis, si vous utilisez le formulaire #{name}, alors c'est SQL précompilé. Si vous utilisez ${name}, ce n'est pas SQL précompilé.
hibernate prend en charge le paramètre positionnel de style JDBC (utilisé dans la chaîne de requête ?), qui a le même effet que l'utilisation du paramètre nommé (utilisé dans la chaîne de requête :).
Utiliser le paramètre nommé
usernameString//前台输入的用户名passwordString//前台输入的密码//hql语句String queryString = "from User t where t.username:usernameString and t.password: passwordString";//执行查询List result = session.createQuery(queryString) .setString("usernameString ", usernameString ) .setString("passwordString", passwordString) .list();
Utiliser le paramètre positionnel
usernameString//前台输入的用户名passwordString//前台输入的密码//hql语句String queryString = "from User t where t.username=? and t.password=?";//执行查询List result = session.createQuery(queryString) .setString(0, usernameString ) .setString(1, passwordString) .list();
两者比较:positional parameter可读性强不如named parameter的强,而且可维护性差,如果我们的查询稍微改变一点,将第一个参数和第二个参数改变一下位置,
这样我们的代码中涉及到位置的地方都要修改,所以我们强烈建议使用named parameter方式进行参数绑定。
在举个栗子~~
我们模仿一下用户登录的场景:这次业务变换,有的网站,手机号可以作为用户名来登录,也能作为手机号本身登录。
常见的做法是将前台获取到的用户名or手机号和密码,作为字符串动态拼接到查询语句中,然后去调用数据库查询~查询的结果不为null就代表用户存在,则登陆成功,否则登录失败!
正常情况下用户输入账号是13812345678和密码123
这里usernameString作为手机号又作为用户名出现了两次,怎么办呢?
大家请看下面代码:
usernameString//前台输入的用户名passwordString//前台输入的密码//hql语句String queryString = "from User t where t.username:usernameString and t.phone:usernameString and t.password: passwordString";//执行查询List result = session.createQuery(queryString) .setString("usernameString ", usernameString ) .setString("passwordString", passwordString) .list();
在Hibernate+spring中getHibernateTemplate()返回的对象可以调用find(String queryString, Object value...Object value)来实现named parameter。比如:
usernameString//前台输入的用户名passwordString//前台输入的密码//hql语句String queryString = "from User t where t.username:usernameString and t.password: passwordString";//执行查询return getHibernateTemplate().find(queryString, usernameString, passwordString);
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!