信息安全第三周

作者因为估计选不到老师的课,第三周就针对性的进行学习和实操,作者认为还是实操最重要。

数据库与Web技术加密模式

在数据库和Web技术中,加密是一个常用来保护数据和通讯的手段。以下是在这两个领域中可能使用到的加密模式:

  1. 密文分组链接模式 (CBC: Cipher Block Chaining Mode)

    • 由于其增加了难以预测性,CBC模式通常用于数据库加密和某些Web应用程序中的数据加密。
    • 在SSL/TLS(安全套接字层/传输层安全性)中,CBC模式曾经是推荐的加密模式,但由于存在某些攻击(如BEAST攻击),现在通常建议使用其他模式。
  2. 计数器模式 (CTR: Counter Mode)

    • 由于其可以并行处理的特性,CTR模式在某些Web技术和大型数据库中是首选的加密模式。本文重点研究计数器模式。
    • 在SSL/TLS中,有一个称为GCM(伽罗华计数模式)的变种,它结合了CTR模式和消息认证码,提供了加密和完整性保护。
  3. 电码本模式 (ECB: Electronic Codebook Mode)

    • 由于其固有的安全性问题,ECB模式通常不建议在Web技术或数据库中使用。当使用相同的密钥加密时,相同的输入块会生成相同的输出块,这使得它容易受到分析攻击。
  4. 输出反馈模式 (OFB: Output Feedback Mode) 和 密文反馈模式 (CFB: Cipher Feedback Mode)

    • 这两种模式在Web和数据库应用中较少使用,但在特定的应用场景中它们可能会出现。
  5. 流模式

    • 当我们谈论流模式时,我们通常指的是像RC4这样的算法,它原生就是为流模式设计的。RC4曾经是Web加密(特别是在早期的SSL/TLS版本中)的主要算法,但由于已知的安全性问题,现在已经不再建议使用。

在选择加密模式时,总是建议使用现代、经过广泛审核和验证的模式和实现,避免使用已知有安全问题或已被弃用的模式。所以作者不学旧东西了,直接学习和作者工作稍微接轨的知识。


CBC&CTR

基础概念

在开始之前,我们需要明白以下几个点:

  • 块密码: 这是一种对固定大小的明文块(例如128位)进行加密的方法。最著名的块密码算法是AES。

  • 初始化向量 (IV): 这是一个与明文一起使用的随机值,用于加密的起始阶段。IV不需要保密,但通常每次加密都会更改。

密文分组链接模式 (CBC)

  1. 如何工作:

    • 在开始加密第一个块之前,先将明文的第一个块与一个随机的初始化向量(IV)进行异或操作。
    • 对结果使用块密码进行加密
    • 结果(即第一个加密块)用于与明文的下一个块进行异或操作,然后再次使用块密码进行加密。
    • 这个过程重复,直到加密所有的明文块。

  1. 使用场景:例如,当你需要存储加密的敏感数据(如信用卡信息)时,CBC是一个可靠的选择,因为它提供了良好的安全性。

  2. 优点:相同的明文块和相同的密钥,由于IV的存在,在不同的加密过程中会产生不同的密文。

  3. 缺点:串行化: 由于每个块的加密都依赖于前一个块,所以CBC不太适合并行化处理

计数器模式 (CTR)

  1. 如何工作:

    • 给定计数器值。
    • 使用AES-128和密钥K加密上一步的结果,但不与明文进行任何操作。
    • 得到的输出与"HELLO"明文进行异或操作。
    • 得到的结果即为密文,这就是该字符串在数据库中的加密版本。
    • 对于下一个块(如果存在),增加计数器值,并重复上述步骤。

  1. 使用场景:在需要快速并行读/写的情境下,CTR模式是一个不错的选择,因为你可以独立地加密或解密任何块。

  2. 优点:

    • 并行性: CTR模式支持并行加密/解密,因为每个块的处理不依赖于其他块
    • 随机访问: 适合于需要随机访问数据块的应用,例如数据库。
  3. 缺点:计数器的值必须为每个块保持独特,否则安全性会受到威胁。如果重新使用计数器和密钥的组合,攻击者可能会找出明文。

结合数据库

假设你有一个数据库,其中存储了用户的敏感信息。为了保护这些数据,你决定使用加密。

  1. 如果你使用CBC,每次加密一个数据行时,你都会生成一个新的IV。由于CBC的串行性,写入大量数据时可能会略显缓慢。

  2. 另一方面,如果你使用CTR,你可以同时加密多个数据行,因为每个数据块的加密是独立的。但要确保计数器值对于每个块都是唯一的。

无论选择哪种模式,都需要确保密钥的安全性,并定期更换密钥。

为何CTR模式与数据库结合良好

由于CTR模式的加密操作是独立的,假如你想读取数据库中一个特定的加密块(例如,一个加密的记录或字段),你不需要解密前面的所有块。你只需使用相应的计数器值进行解密即可


CTR实操

Python

为了给大家一个具体的操作示例,我们首先会使用Python的cryptography库来完成这个操作。但首先,需要确保你已经安装了这个库:

pip install cryptography

接下来,我们来看看CTR模式下如何使用AES加密"HELLO"这个字符串:

import random
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import ciphers
from cryptography.hazmat.primitives.ciphers import Cipher

# 1. 选择一个密钥
# AES-128位密钥 (16 bytes)
key = b'abcdefghijklmnop'

# 2. 初始化一个计数器 (这只是一个简单的例子, 在实际应用中通常使用更复杂的方法)
nonce = int.to_bytes(random.getrandbits(128), 16, 'big')

# 3. 创建AES Cipher实例并设置为CTR模式
cipher = Cipher(ciphers.algorithms.AES(key), ciphers.modes.CTR(nonce), backend=default_backend())

# 4. 创建一个加密器对象
encryptor = cipher.encryptor()

# 5. 加密"HELLO"字符串
ciphertext = encryptor.update(b'HELLO') + encryptor.finalize()

print("Ciphertext:", ciphertext)

首先,代码从cryptography库中导入了所需的模块和函数,这个库是一个提供加密和解密功能的Python包。

在代码中,首先选择了一个固定的128位AES密钥,即key = b'abcdefghijklmnop'。AES支持多种密钥长度,如128位、192位和256位。在这个示例中,选择了128位的密钥,这意味着密钥长度为16字节。

接下来,为了使用CTR模式,我们需要一个名为nonce的计数器。在这个例子中,随机生成了一个128位的数字,并将其转换为一个16字节的字节串作为nonce。请注意,在实际应用中,计数器的使用和管理通常会更加复杂,确保每次加密时使用的nonce都是唯一的。

然后,使用指定的AES密钥和CTR模式的nonce创建了一个Cipher实例ciphers.algorithms.AES(key)定义了使用AES算法,而ciphers.modes.CTR(nonce)则设定了CTR模式并提供了计数器。这个Cipher对象将作为加密和解密操作的基础。

随后,使用这个Cipher实例创建了一个加密器对象,称为encryptor。这个加密器对象将被用于执行实际的加密操作。

最后,使用这个加密器对字符串"HELLO"进行了加密,并打印出加密后的密文。在CTR模式下,加密操作通常分为两步:先调用update方法进行加密,然后调用finalize方法来结束加密过程并获取任何剩余的加密数据。这两步通常一起使用,以确保所有数据都已被正确加密。每一次运行,nonce值不同,所以密文结果是不同的:

这段代码为我们提供了一个简洁的方式,使用AES的CTR模式加密数据。它涵盖了选择密钥、生成计数器、设置加密算法和模式、创建加密器,以及实际进行加密的整个过程。


Python结合数据库

在数据库的上下文中,加密通常发生在以下几个级别:

  1. 透明数据加密(TDE): 这是最简单的方式。整个数据库或特定的数据文件被加密。当数据库服务启动时,它会解密数据以进行读取,并在写入时再次加密。用户和应用程序与数据库的交互就好像它未被加密一样,但实际上一直处于加密状态。

  2. 列级加密: 只对特定的列进行加密,如信用卡号、身份证号等敏感信息。应用程序在写入或读取这些列时需要执行加密或解密操作。

  3. 应用级加密: 在应用程序内部,数据在被写入数据库之前先被加密,然后在被读取被解密。数据库读数据的时候只看到加密的数据。

现在,假设我们想在列级加密的上下文中使用上面的CTR示例,我们可以这样做:

场景

我们有一个数据库表,它存储用户信息,其中ssn (社会安全号) 是一个敏感列,需要被加密。

CREATE TABLE users (
    id INT PRIMARY KEY,
    name VARCHAR(100),
    ssn BLOB  -- We'll store encrypted data here
);

插入数据时的加密

当插入新的用户数据时,我们不直接插入社会安全号。首先,我们使用上面的Python代码对其进行加密,然后再插入加密后的值。

注意是使用Python,这就涉及到后端,并不是在数据库中进行的操作哦!对于数据库本身,它仅存储和检索加密数据,不知道解密方法或密钥。

# ... the AES CTR encryption code ...

user_name = "John Doe"
user_ssn = "123-45-6789"  # This is what we want to encrypt

encrypted_ssn = encryptor.update(user_ssn.encode()) + encryptor.finalize()

# Now, use the encrypted_ssn in your SQL INSERT statement

读取数据时的解密

当从数据库中读取用户数据时,ssn列的值是加密的。因此,需要使用解密器对象来解密它,以便在应用程序中使用。

# ... the AES CTR decryption code ...

# Assume 'encrypted_data_from_db' is the value we fetched from the 'ssn' column for a user
decryptor = cipher.decryptor()
decrypted_ssn = decryptor.update(encrypted_data_from_db) + decryptor.finalize()

print("Decrypted SSN:", decrypted_ssn.decode())

完整的加密解密过程如下:

import random
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import ciphers
from cryptography.hazmat.primitives.ciphers import Cipher

# 1. 选择一个密钥
# AES-128位密钥 (16 bytes)
key = b'abcdefghijklmnop'

# 2. 初始化一个计数器 (这只是一个简单的例子, 在实际应用中通常使用更复杂的方法)
nonce = int.to_bytes(random.getrandbits(128), 16, 'big')

# 3. 创建AES Cipher实例并设置为CTR模式
cipher = Cipher(ciphers.algorithms.AES(key), ciphers.modes.CTR(nonce), backend=default_backend())

# 4. 创建一个加密器对象
encryptor = cipher.encryptor()

# 5. 加密"HELLO"字符串
ciphertext = encryptor.update(b'HELLO') + encryptor.finalize()

print("Ciphertext:", ciphertext)

decryptor = cipher.decryptor()

decrypted_ssn = decryptor.update(ciphertext) + decryptor.finalize()

print("Decrypted_ssn:",decrypted_ssn)

输出:


Springboot

各层代码

作者最终毕设还是Springboot,所以继续学一下,这个挺有趣的!

为了简化,我们将使用固定的加密密钥,但在真实应用中,你应该使用一个安全的方式来生成和存储这个密钥。

首先,需要在你的pom.xml中添加以下依赖以使用Java加密扩展(JCE):

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>

这一步不是必须的,添加依赖之后的所有访问之前都需要使用用户名user和Springboot控制台提供的密码登录,这其实是一种安全性检查(在后文中有介绍)。作者一开始添加了依赖,但是在下一篇改进优化部分中死活不返回值,就把这个依赖删了,等以后询问老师再解决吧!

然后,创建服务层,以下是一个简单的加密/解密服务:

import org.springframework.stereotype.Service;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.Base64;

@Service
public class EncryptionService {

    // 请注意:此示例使用固定的密钥和IV。在实际应用中,你应该使用安全的方式生成这些值。
    private static final String KEY = "0123456789ABCDEF"; // 16字节
    private static final String IV = "1234567890ABCDEF"; // 16字节
    private static final String ALGORITHM = "AES";
    private static final String MODE = "AES/CTR/NoPadding";

    public String encrypt(String plainText) throws Exception {
        Cipher cipher = Cipher.getInstance(MODE);
        SecretKey secretKey = new SecretKeySpec(KEY.getBytes(StandardCharsets.UTF_8), ALGORITHM);
        IvParameterSpec iv = new IvParameterSpec(IV.getBytes(StandardCharsets.UTF_8));

        cipher.init(Cipher.ENCRYPT_MODE, secretKey, iv);
        byte[] encryptedBytes = cipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8));

        return Base64.getEncoder().encodeToString(encryptedBytes);
    }

    public String decrypt(String encryptedText) throws Exception {
        Cipher cipher = Cipher.getInstance(MODE);
        SecretKey secretKey = new SecretKeySpec(KEY.getBytes(StandardCharsets.UTF_8), ALGORITHM);
        IvParameterSpec iv = new IvParameterSpec(IV.getBytes(StandardCharsets.UTF_8));

        cipher.init(Cipher.DECRYPT_MODE, secretKey, iv);
        byte[] decryptedBytes = cipher.doFinal(Base64.getDecoder().decode(encryptedText));

        return new String(decryptedBytes, StandardCharsets.UTF_8);
    }
}

然后定义Controller控制器,用于展示如何使用上述服务:

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class EncryptionController {

    private final EncryptionService encryptionService;

    public EncryptionController(EncryptionService encryptionService) {
        this.encryptionService = encryptionService;
    }

    @GetMapping("/encrypt")
    public String encrypt(@RequestParam String text) {
        try {
            return encryptionService.encrypt(text);
        } catch (Exception e) {
            return "Error during encryption: " + e.getMessage();
        }
    }

    @GetMapping("/decrypt")
    public String decrypt(@RequestParam String encryptedText) {
        try {
            return encryptionService.decrypt(encryptedText);
        } catch (Exception e) {
            return "Error during decryption: " + e.getMessage();
        }
    }
}

这只是一个基本的示例,并且其中的固定密钥和IV并不安全。在生产环境中,你应该使用更为安全的方式来管理你的密钥和IV,例如使用Java的KeyStore或第三方工具。


具体流程

另外,考虑到有些人(作者)稍微有点忘记Springboot操作,现查询基础操作流程:

1. 创建新的Spring Boot项目

最简单的方法是使用Spring Initializr

  • 选择Maven和Java版本。
  • 添加依赖:"Spring Web" 和 "Spring Security",但作者这次没加后者。

2. 添加代码

将先前提供的EncryptionService类和EncryptionController类添加到项目中。

3. 配置应用

如果你想运行应用在一个特定的端口,你可以在src/main/resources/application.properties文件中添加以下内容(例如,我们设置为8085端口):

server.port=8085

4. 启动应用

在你的IDE中,查找@SpringBootApplication注解的主类(它是Spring Initializr为你创建的)。这个类应该有一个public static void main(String[] args)方法。直接运行这个类。

5. 查看结果

当应用启动后,打开浏览器并访问:

注意:替换YOUR_ENCRYPTED_STRING_HERE为实际的加密字符串。


注意,当我们在Spring Boot应用中引入spring-boot-starter-security依赖时,Spring Boot会默认为你的应用启用安全配置。我们会看到登录界面:

这个默认的安全配置包括一些基础的身份验证和授权设置。

有常见的两种方法,一种是设置Configuration配置类,有点难,作者不是这样解决的。还有一种方案是,需要一个用户名密码才能访问应用。Spring Boot通常会在控制台上输出一个默认的用户名(user)和一个随机生成的密码,每次启动应用时密码都会变:

登陆后,服务返回值展示在页面上:

这样就实现了Springboot程序上的CTR!做到这里,是不是很有成就感呢?作者认为在课上所有内容都学,早已不用的方法原理也要学,这可能会打基础,但当前是一定没用的。因为我们需要实操!请大家相信自己,有自己的思考、想法,做最适合自己的事!

当然,这样基础的代码是不够的,作者对于密钥生成和数据完整性检查对于Python和Springboot都做出了改进,并在Springboot中使用post请求,详情见文章《信息安全第三周+》。


密钥分配

密钥分配是许多加密协议和系统中的关键部分。一个系统中的实体(例如用户或设备)需要一个安全的方式来交换或接收密钥,以便进行安全通信。这就引入了两种主要的密钥分配机制:集中式分配和分布式分配。下面是关于这两种机制和密钥分配中心(KDC)的简介:

  1. 集中式分配方案(Centralized Key Distribution):

    • 在这种机制中,有一个中央实体(通常称为密钥分配中心或KDC)负责密钥的生成、存储和分配。
    • 当两个实体需要通信时,它们都会联系KDC来获取会话密钥。KDC知道每个实体的长期密钥,并使用这些密钥来安全地传输会话密钥。
    • 优势:简单,容易管理,因为所有的密钥管理都集中在一个地方。
    • 劣势:单点故障。如果KDC受到攻击或失效,整个系统可能会受到威胁。

    Kerberos就是一个广泛使用的基于KDC的身份验证协议。

  2. 分布式分配方案(Distributed Key Distribution):

    • 在分布式系统中,密钥管理是分散的,没有单一的中心实体负责密钥的分配。
    • 这通常涉及到复杂的协议,使实体可以直接(或通过少数几个中间实体)安全地交换密钥。
    • 优势:没有单点故障,可扩展性好。
    • 劣势:可能会比集中式系统更复杂,并需要更多的初始设置和维护。
  3. 密钥分配中心(KDC):

    • KDC是集中式密钥分配方案的核心部分。
    • KDC通常包含两个主要组件:一个身份验证服务器(AS)和一个票据授权服务器(TGS)。
      • 身份验证服务器(AS):当用户首次登录系统时,他们与AS通信,向其证明自己的身份,并获取一个“票据授权票”(TGT)。
      • 票据授权服务器(TGS):当用户需要访问特定服务时,他们使用TGT与TGS通信,请求特定服务的会话密钥。
    • KDC使用预共享的秘密密钥或证书与每个用户或服务进行身份验证。

为了使密钥分配更为安全和高效,需要结合多种策略和技术,确保密钥在其生命周期中始终保持安全。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Joy T

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值