问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

防止SQL注入攻击:高效网络安全编码指南

创作时间:
作者:
@小白创作中心

防止SQL注入攻击:高效网络安全编码指南

引用
CSDN
12
来源
1.
https://blog.csdn.net/2301_79448933/article/details/137653352
2.
https://cloud.baidu.com/article/3283333
3.
https://blog.csdn.net/weixin_43178927/article/details/136687238
4.
https://blog.csdn.net/m0_68948067/article/details/137045643
5.
https://blog.csdn.net/acmman/article/details/139377496
6.
https://blog.csdn.net/weixin_39746740/article/details/80818339
7.
https://blog.csdn.net/weixin_41039677/article/details/138419461
8.
https://learn.microsoft.com/zh-cn/sql/relational-databases/security/sql-injection?view=sql-server-ver16
9.
https://www.cnblogs.com/szk123456/p/18408144
10.
https://www.aqniu.com/homenews/107661.html
11.
https://www.cnblogs.com/Magiclala/p/18230469
12.
https://developer.mozilla.org/zh-CN/docs/Learn_web_development/Extensions/Server-side/First_steps/Website_security

SQL注入攻击是Web应用中最常见的安全威胁之一,它不仅可能导致敏感数据泄露,还可能造成数据库被恶意篡改或删除。据统计,超过一半的Web应用都存在SQL注入风险。本文将详细介绍SQL注入的原理,并提供一系列有效的防护措施,帮助开发者构建更加安全的应用程序。

01

SQL注入攻击原理

SQL注入是一种攻击方式,通过在字符串中插入恶意代码,然后将该字符串传递到数据库引擎进行分析和执行。任何构成SQL语句的过程都应进行注入漏洞检查,因为数据库引擎将执行其接收到的所有语法有效的查询。一个有经验的、坚定的攻击者甚至可以操作参数化数据。

注入过程的工作方式是提前终止文本字符串,然后追加一个新的命令。由于插入的命令可能在执行前追加额外字符串,因此攻击者将用批注标记 -- 来标记终止注入的字符串。执行时,此后的文本将被忽略。

02

防止SQL注入的最佳实践

使用参数化查询和预编译语句

最有效的防止SQL注入的方法是使用预编译语句(PreparedStatement),它将SQL语句与数据分离,避免了恶意数据被执行为SQL代码。

package cn.juwatech.security;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;

public class SqlInjectionPrevention {

    public static void main(String[] args) {
        String userId = "123"; // 假设这是用户提供的输入
        String query = "SELECT * FROM users WHERE id = ?";
        
        try (Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb", "user", "password");
             PreparedStatement statement = connection.prepareStatement(query)) {
            
            // 设置参数
            statement.setString(1, userId);
            
            try (ResultSet resultSet = statement.executeQuery()) {
                while (resultSet.next()) {
                    System.out.println("User ID: " + resultSet.getString("id"));
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

在这个示例中,使用 PreparedStatement 将SQL查询与输入参数分开,避免了SQL注入风险。

严格的输入验证

始终通过测试类型、长度、格式和范围来验证用户输入。预防恶意输入时,请注意应用程序的体系结构和部署方案。请注意,设计为在安全环境中运行的程序可能会被复制到不安全的环境中。以下建议应被视为最佳做法:

  • 对应用程序接收的数据不做任何有关大小、类型或内容的假设。例如,您应该进行以下评估:
    • 如果一个用户在需要邮政编码的位置无意中或恶意地输入了一个 2 GB 的视频文件,应用程序会做出什么反应?
    • 如果在文本字段中嵌入了一个 DROP TABLE 语句,应用程序会做出什么反应?
  • 测试输入的大小和数据类型,强制执行适当的限制。这有助于防止有意造成的缓冲区溢出。
  • 测试字符串变量的内容,只接受所需的值。拒绝包含二进制数据、转义序列和注释字符的输入内容。这有助于防止脚本注入,防止某些缓冲区溢出攻击。
  • 使用 XML 文档时,根据数据的架构对输入的所有数据进行验证。
  • 绝不直接使用用户输入内容来生成 Transact-SQL 语句。
  • 使用存储过程来验证用户输入。
  • 在多层环境中,所有数据都应该在验证之后才允许进入可信区域。未通过验证过程的数据应被拒绝,并向前一层返回一个错误。
  • 实现多层验证。对无目的的恶意用户采取的预防措施对坚定的攻击者可能无效。更好的做法是在用户界面和所有跨信任边界的后续点上验证输入。
  • 绝不串联未验证的用户输入。字符串串联是脚本注入的主要输入点。
  • 不接受以下来自可构造文件名的字段中的字符串:AUX 、 CLOCK$ 、 COM1 到 COM8 、 CON 、 CONFIG$ 、 LPT1 到 LPT8 , NUL 和 PRN 。
  • 如果可能,拒绝包含以下字符的输入。
    • 输入字符 在 Transact-SQL 中的含义
    • ; 查询分隔符。
    • ' 字符数据字符串分隔符。
    • -- 单行注释分隔符。服务器不计算在--之后直到该行结束的文本。
    • /.../ 注释分隔符。服务器不计位于//之间的文本。
    • xp_ 用于目录扩展存储过程的名称的开头,如xp_cmdshell。

使用ORM框架

使用对象关系映射(ORM)框架,如Hibernate或JPA,也能有效防止SQL注入,因为这些框架内部使用了安全的查询构造方法。

package cn.juwatech.orm;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
import javax.persistence.TypedQuery;
import java.util.List;

public class OrmExample {

    public static void main(String[] args) {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("my-persistence-unit");
        EntityManager em = emf.createEntityManager();
        EntityTransaction tx = em.getTransaction();
        
        try {
            tx.begin();
            String userId = "123"; // 假设这是用户提供的输入
            
            TypedQuery<User> query = em.createQuery("SELECT u FROM User u WHERE u.id = :id", User.class);
            query.setParameter("id", userId);
            
            List<User> users = query.getResultList();
            for (User user : users) {
                System.out.println("User ID: " + user.getId());
            }
            
            tx.commit();
        } catch (Exception e) {
            if (tx.isActive()) {
                tx.rollback();
            }
            e.printStackTrace();
        } finally {
            em.close();
            emf.close();
        }
    }
}

在这个示例中,使用JPA的 TypedQuery 安全地构造和执行查询,从而避免了SQL注入问题。

03

实际案例分析

以靶场pikachu为例。假设输入vince,你会发现vince在这个数据库里面,并且有id 和邮箱,这些数据可能都是某个表中的某列数据。当你输入个xx时,会发现username不存在,即不在数据库里面。当你在xx后面加上' or 1=1#时候,能查询到数据库所有信息。

这是怎么回事呢?#为注释符号。本来输入的vince,将&sname都替换了。后来输入的xx' or 1=1#,过程:username='&name' xx' or 1=1# 红色部分指被黑色部分替换了,正好引号将xx注释掉了,or 两边条件成立一个,就都成立。因为1=1为永真式,所以就能够查询到全部的数据。总结:引号闭合了前面的数据,#注释了后面的数据,拼接了一个sql语句。

04

总结与建议

防止SQL注入攻击的关键在于:

  1. 使用参数化查询和预编译语句
  2. 严格验证所有用户输入
  3. 使用ORM框架简化安全编码
  4. 避免直接拼接SQL语句
  5. 定期更新和维护安全防护措施

随着Web应用的不断发展,SQL注入攻击手段也在不断进化。开发者和安全人员需要时刻保持警惕,持续学习最新的安全知识,以应对日益复杂的网络威胁。

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号