简单登录
为了演示sql注入问题,我们使用jdbc来实现一个简单的登录功能,用户从控制台输入用户名和密码,然后从数据库中查找是否有匹配的数据,如果存在则登录成功,否则登录失败。
创建一个UserService类,该来主要是做用户相关的操作。
/*用户服务*/public class UserService {public User selectByNameAndPassword(String username,String password) {String sql = "select id,name,password,email,birthday from t_user where name='" + username + "' and password='" + password + "'";System.out.println(sql);User u = null;try (//获取Connection对象Connection conn = DBUtil.getConnection();//获取Statement对象Statement stmt = conn.createStatement();//获取ResultSet对象ResultSet rs = stmt.executeQuery(sql);) {//处理结果while (rs.next()) {u = new User();u.setId(rs.getInt("id"));u.setName(rs.getString("name"));u.setPassword(rs.getString("password"));u.setEmail(rs.getString("email"));u.setBirthday(rs.getDate("birthday"));}} catch (SQLException e) {e.printStackTrace();}return u;}}创建登录类package com.company.sql;import com.company.User;import java.util.Scanner;public class Login {public static void main(String[] args) {Scanner sc = new Scanner(System.in);System.out.println("请输入用户名:");String username = sc.nextLine();System.out.println("请输入密码:");String password = sc.nextLine();//创建UserService对象判断当前用户是否可以登录成功//UserService us = new UserService();// User user = us.selectByNameAndPassword(username, password);LoginServiceNew ls = new LoginServiceNew();User user = ls.selectByNameAndPassword(username,password);if (user == null) {System.out.println("用户名或密码不正确");}else {System.out.println("登录成功");}}}
之后从控制台输入用户名和密码进行测试
sql注入问题
在之前写的登录功能中,随便输入一个用户名,在密码部分输入下面内容:
123' or 1='1
这个密码肯定是不正确的,但是依然能够登录成功,这个就是sql注入问题,也就是说之前写的登录功能有安全问题。为什么会导致这样的问题?我们将最终执行的sql打印可以看到是这样的:
select id,name,password,email,birthday from t_user where name='tb' and password='123' or 1='1';
出现问题的部分是 or 1=’1’这部分,因为无论如何这部分的运算结果都是true,所以在输错用户名和密码的情况下依然登录成功了。要想解决这个问题,可以使用jdbc提供的PreparedStatement。
PreparedStatement
PreparedStatement是一个接口,它继承了Statement,该接口有以下几个优点:
性能比Statement高,会把sql预编译
可以解决sql注入问题
使用PreparedStatement修改登录功能的代码:
package com.company.sql;import com.company.DBUtil;import com.company.User;import java.sql.*;public class LoginServiceNew {public User selectByNameAndPassword(String username, String password) {User u = null;String sql = "select id,name,password,email,birthday from t_user where name=? and password=?";System.out.println(sql);try( Connection con = DBUtil.getConnection();PreparedStatement stmt = con.prepareStatement(sql);) {stmt.setString(1,username);stmt.setString(2,password);//执行结果,并返回ResultSet rs = stmt.executeQuery();while (rs.next()){u.setId(rs.getInt("id"));u.setName(rs.getString("name"));u.setPassword(rs.getString("password"));u.setEmail(rs.getString("email"));u.setBirthday(rs.getDate("birthday"));}} catch (SQLException e) {e.printStackTrace();}return u;}}
在sql语句中,使用?作为占位符来替代要传入的内容,通过调用PreparedStatement的setString等方法将要传入的内容作为参数传递过去。
