zoukankan      html  css  js  c++  java
  • API安全(二)-SQL注入与防范

    1、什么是注入攻击

      使用了用户输入的但是我们没有校验过的数据,来拼装一个可以行的指令,交给系统去执行,结果导致执行了我们不希望发生的命令。注入攻击用很多种,最常见的是SQL注入。

    2、SQL注入攻击

      Java程序员知道,使用Statement进行查询时会造成SQL注入攻击,从而使用PreparedStatement来进行SQL预编译,从而有效的防止SQL注入攻击。但是日常开发中,我们一般多使用框架来进行数据库操作,如JdbcTemplate、Spring-Data-Jpa、Mybatis等,但是使用起来,我们也要注意,避免写出可注入程序。

    3、JdbcTemplate注入代码示例

      3.1、UserDO实体类与UserDTO

    /**
     * @author caofanqi
     * @date 2020/1/20 13:08
     */
    @Data
    @Entity
    @Table(name = "user")
    public class UserDO {
    
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long id;
    
        @Column(nullable = false)
        private String name;
    
    
        public UserDTO buildUserDTO(){
            UserDTO userDTO = new UserDTO();
            BeanUtils.copyProperties(this,userDTO);
            return userDTO;
        }
    
    }
    
    
    /**
     * @author caofanqi
     * @date 2020/1/20 13:08
     */
    @Data
    public class UserDTO {
    
    
        private Long id;
    
        private String name;
    
    }

      3.2、UserController,提供一个根据用户名称进行查询用户的API接口

    /**
     * 用户控制层
     *
     * @author caofanqi
     * @date 2020/1/20 13:05
     */
    @RestController
    @RequestMapping("/users")
    public class UserController {
    
        @Resource
        private UserService userService;
    
    
        @GetMapping
        public List<UserDTO> query(String name) {
            return userService.query(name);
        }
    
        
    }

      3.3、UserService实现类,使用JdbcTemplate进行条件拼接查询,会产生SQL注入问题

    /**
     * 用户业务层实现类
     *
     * @author caofanqi
     * @date 2020/1/20 13:52
     */
    @Slf4j
    @Service
    public class UserServiceImpl implements UserService {
    
    
        @Resource
        private JdbcTemplate jdbcTemplate;
    
    
        @Override
        public List<UserDTO> query(String name) {
    
            String sql = "SELECT * FROM user WHERE name = '" + name + "'";
            log.info("执行的SQL为:{}",sql);
            List<UserDO> queryResult = jdbcTemplate.query(sql, BeanPropertyRowMapper.newInstance(UserDO.class));
    
            List<UserDTO> result = queryResult.stream().map(UserDO::buildUserDTO).collect(Collectors.toList());
    
            return result;
        }
    
    }

      3.4、启动项目,向数据库中插入3条数据,如下:

      

      3.5、访问http://127.0.0.1:9090/users?name=zhangsan 可以正常查询到结果

      

      3.6、但是执行http://127.0.0.1:9090/users?name=' or '1'='1 时,就会把数据库中所有的用户都查询出来,这样就会导致信息泄漏。

      

      控制台打印日志如下

    2020-01-20 21:48:07.263  INFO 18540 --- [nio-9090-exec-3] c.c.s.service.impl.UserServiceImpl       : 执行的SQL为:SELECT * FROM user WHERE name = '' or '1'='1'

      往下追溯源码可以发现,该query方法,底层使用的是Statement

      

      3.7、解决这个问题,我们修改query代码如下,使用了预编译SQL。

        @Override
        public List<UserDTO> query(String name) {
    
            String sql = "SELECT * FROM user WHERE name = ? ";
            List<UserDO> queryResult = jdbcTemplate.query(sql, new Object[]{name}, BeanPropertyRowMapper.newInstance(UserDO.class));
            List<UserDTO> result = queryResult.stream().map(UserDO::buildUserDTO).collect(Collectors.toList());
    
            return result;
        }

      3.8、http://127.0.0.1:9090/users?name=' or '1'='1 时,查询不到结果,预防了SQL注入攻击

      

       往下追溯源码可以发现,该query方法,底层使用的是PreparedStatement

      

    4、EntityManager注入代码示例

      在使用JPA的EntityManager执行拼接SQL时,将参数拼接到SQL中,一样会有SQL注入问题

    @Slf4j
    @Service
    public class UserServiceImpl implements UserService {
    
        @PersistenceContext
        private EntityManager entityManager;
    
        @Override
        public List<UserDTO> query(String name) {
    
            String sql = "SELECT * FROM user WHERE name = '" + name + "'";
    
            Query nativeQuery = entityManager.createNativeQuery(sql, UserDO.class);
            List<UserDO> queryResult = nativeQuery.getResultList();
    
            List<UserDTO> result = queryResult.stream().map(UserDO::buildUserDTO).collect(Collectors.toList());
    
            return result;
        }
    
    }

      需要修改成如下:

            String sql = "SELECT * FROM user WHERE name = ? ";
            Query nativeQuery = entityManager.createNativeQuery(sql, UserDO.class);
            nativeQuery.setParameter(1, name);
            List<UserDO> queryResult = nativeQuery.getResultList();

    5、如何防止SQL注入

      上面的情况只是针对与查询,多查出来数据,更危险的攻击可能会修改或删除数据,甚至调用存储过程,删表等。我们如何防止SQL注入呢?

      5.1、控制数据库用户权限(对分配给应用程序的用户权限进行限定,一般只有对数据的CRUD权限)

      5.2、对传入的参数进行校验

      5.3、使用一些高级的框架进行数据库操作,对于一些复杂的情况,需要进行SQL拼接时,不要将参数拼接到SQL中,要使用预编译SQL。

    项目源码:https://github.com/caofanqi/study-security/tree/dev-SQL-injection

  • 相关阅读:
    [译]WCF RIA Services中的集合(2)
    Silverlight中服务通信方式的选择(WCF、Data Service、Ria Service)
    记录来敦煌一周的情况
    Silverlight通过MVVM实现多语言实时切换(含源代码)
    [译]WCF RIA Services中的集合(1)
    Silverlight Client←→Server数据同步备忘代码
    Siverlight5新功能/改进总结
    Expression Blend 5 Preview For Silverlight5 RC已发布
    你应该知道的,那些未在Silverlight5Beta中出现的特性
    .NET数据库编程求索之路1.引子
  • 原文地址:https://www.cnblogs.com/caofanqi/p/12219669.html
Copyright © 2011-2022 走看看