简单登录
    为了演示sql注入问题,我们使用jdbc来实现一个简单的登录功能,用户从控制台输入用户名和密码,然后从数据库中查找是否有匹配的数据,如果存在则登录成功,否则登录失败。

    创建一个UserService类,该来主要是做用户相关的操作。

    1. /*
    2. 用户服务
    3. */
    4. public class UserService {
    5. public User selectByNameAndPassword(String username,String password) {
    6. String sql = "select id,name,password,email,birthday from t_user where name='" + username + "' and password='" + password + "'";
    7. System.out.println(sql);
    8. User u = null;
    9. try (
    10. //获取Connection对象
    11. Connection conn = DBUtil.getConnection();
    12. //获取Statement对象
    13. Statement stmt = conn.createStatement();
    14. //获取ResultSet对象
    15. ResultSet rs = stmt.executeQuery(sql);
    16. ) {
    17. //处理结果
    18. while (rs.next()) {
    19. u = new User();
    20. u.setId(rs.getInt("id"));
    21. u.setName(rs.getString("name"));
    22. u.setPassword(rs.getString("password"));
    23. u.setEmail(rs.getString("email"));
    24. u.setBirthday(rs.getDate("birthday"));
    25. }
    26. } catch (SQLException e) {
    27. e.printStackTrace();
    28. }
    29. return u;
    30. }
    31. }
    32. 创建登录类
    33. package com.company.sql;
    34. import com.company.User;
    35. import java.util.Scanner;
    36. public class Login {
    37. public static void main(String[] args) {
    38. Scanner sc = new Scanner(System.in);
    39. System.out.println("请输入用户名:");
    40. String username = sc.nextLine();
    41. System.out.println("请输入密码:");
    42. String password = sc.nextLine();
    43. //创建UserService对象判断当前用户是否可以登录成功
    44. //UserService us = new UserService();
    45. // User user = us.selectByNameAndPassword(username, password);
    46. LoginServiceNew ls = new LoginServiceNew();
    47. User user = ls.selectByNameAndPassword(username,password);
    48. if (user == null) {
    49. System.out.println("用户名或密码不正确");
    50. }else {
    51. System.out.println("登录成功");
    52. }
    53. }
    54. }

    之后从控制台输入用户名和密码进行测试

    sql注入问题
    在之前写的登录功能中,随便输入一个用户名,在密码部分输入下面内容:

    1. 123' or 1='1

    这个密码肯定是不正确的,但是依然能够登录成功,这个就是sql注入问题,也就是说之前写的登录功能有安全问题。为什么会导致这样的问题?我们将最终执行的sql打印可以看到是这样的:

    1. 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修改登录功能的代码:

    1. package com.company.sql;
    2. import com.company.DBUtil;
    3. import com.company.User;
    4. import java.sql.*;
    5. public class LoginServiceNew {
    6. public User selectByNameAndPassword(String username, String password) {
    7. User u = null;
    8. String sql = "select id,name,password,email,birthday from t_user where name=? and password=?";
    9. System.out.println(sql);
    10. try( Connection con = DBUtil.getConnection();
    11. PreparedStatement stmt = con.prepareStatement(sql);
    12. ) {
    13. stmt.setString(1,username);
    14. stmt.setString(2,password);
    15. //执行结果,并返回
    16. ResultSet rs = stmt.executeQuery();
    17. while (rs.next()){
    18. u.setId(rs.getInt("id"));
    19. u.setName(rs.getString("name"));
    20. u.setPassword(rs.getString("password"));
    21. u.setEmail(rs.getString("email"));
    22. u.setBirthday(rs.getDate("birthday"));
    23. }
    24. } catch (SQLException e) {
    25. e.printStackTrace();
    26. }
    27. return u;
    28. }
    29. }

    在sql语句中,使用?作为占位符来替代要传入的内容,通过调用PreparedStatement的setString等方法将要传入的内容作为参数传递过去。