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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM