数据库数据使用md5加密
Background
背景
Personally-identifying information (PII) is personal information that customers tell the service provider (e-commerce, financial service, etc…). As a service provider, it’s their responsibility to safekeeping the information. The attack vector can be from outside or inside the organization.
个人识别信息(PII)是客户告诉服务提供商的个人信息(电子商务,金融服务等)。 作为服务提供商,他们有责任保护信息。 攻击媒介可以来自组织外部或内部。
Objective
目的
Encrypt PII stored in the Database so information cannot be read by an employee within the organization, and the external attacker cannot read the information when they manage to steal the Database.
对存储在数据库中的PII进行加密,以使组织内的员工无法读取信息,并且外部攻击者在设法窃取数据库时也无法读取信息。
Strategy
战略
Data Writing
数据写入
- Read input (plaintext) 读取输入(纯文本)
- Encrypt plaintext to ciphertext 将纯文本加密为密文
- Write ciphertext to DB 将密文写入数据库
Data Reading
资料读取
- Read ciphertext from DB 从数据库读取密文
- Decrypt ciphertext to plaintext 将密文解密为纯文本
- Send plaintext 发送纯文本
Example
例
kingsman ==> sLR9ctALjY0rtAi8IvosScCtBE21gyMOBl3xHzi52Hbo+H3O
金斯曼==> sLR9ctALjY0rtAi8IvosScCtBE21gyMOBl3xHzi52Hbo + H3O
Encryption Algorithm
加密演算法
Symmetric-key is an appropriate algorithm in this scenario because:
在这种情况下,对称密钥是一种合适的算法,因为:
- Encryption process happens in one party (the same service to be precise). So no need to concerning key exchange with another party. 加密过程发生在一方(确切地说是同一服务)中。 因此,无需考虑与另一方进行密钥交换。
- Symmetric encryption is faster compare to asymmetric encryption. Extra speed in data interaction service is always welcomed. 与非对称加密相比,对称加密更快。 始终欢迎在数据交互服务中提高速度。
- Content size in each field of data can be huge. Symmetric encryption has a better capability for encrypting big sized data. 每个数据字段中的内容量可能很大。 对称加密具有更好的加密大型数据的能力。
Sample Case
样品盒
Financial Service Provider: Registration Module
金融服务提供商:注册模块
Create New User Function
创建新的用户功能
func createData(id, name, nationalID, createTimeUnix string) (err error) {
_, err = DB.Exec(`
INSERT INTO
user (id, name, national_id, create_time_unix)
VALUES
("?", "?", "?", "?")
`, id, name, nationalID, createTimeUnix)
return
}
The function above is the minimum function to write data into the Database in Go.
上面的功能是在Go中将数据写入数据库的最小功能。
To limit the scope in the example case, every request contains 4 info:
为了限制示例中的范围,每个请求都包含4个信息:
- id ID
- name 名称
- nationalID (in USA this known as SSN, in Indonesia known by KTP) nationalID(在美国,这被称为SSN,在印度尼西亚,被KTP称为)
- createTimeUnix createTimeUnix
We will come back to this function to integrate encryption function.
我们将回到此功能以集成加密功能。
Read User Data Function
读取用户数据功能
type User struct {
ID string
Name string
NationalID string
CreateTimeUnix string
}func readData(id string) (user User, err error) {
row := DB.QueryRow(`
SELECT
id, name, national_id, create_time_unix
FROM
user
WHERE
id = "?"`, id)
err = row.Scan(
&user.ID,
&user.Name,
&user.NationalID,
&user.CreateTimeUnix)
return
}
The code above explains two things, struct of User and function to read data from the Database. The function is the minimum code to read data and parse into an object without any data handling. The function will work fine given the provided with the correct table in the Database. We will come back to this function again to decrypt data from the Database.
上面的代码解释了两件事,用户结构和从数据库读取数据的功能。 该函数是无需任何数据处理即可读取数据并解析为对象的最少代码。 鉴于数据库中提供了正确的表,该功能将正常运行。 我们将再次回到此功能以解密数据库中的数据。
Data Encryption Function
数据加密功能
func encrypt(plaintext, passphrase string) (chipertext string, err error) {
block, _ := aes.NewCipher([]byte(passphrase))
gcm, err := cipher.NewGCM(block)
if err != nil {
return
}nonce := make([]byte, gcm.NonceSize())
if _, err = io.ReadFull(rand.Reader, nonce); err != nil {
return
}ciphertextByte := gcm.Seal(
nonce,
nonce,
[]byte(plaintext),
nil)
chipertext = base64.StdEncoding.EncodeToString(ciphertextByte)return
}
The function above (encrypt
) is a function to encrypt plain text. AES algorithm is used as a symmetrical key algorithm. Most of the modern language (Go, Node JS, Python, PHP) already have a library for AES. In essence, what’s written in code above are;
上面的函数( encrypt
)是对纯文本进行加密的函数。 AES算法用作对称密钥算法。 大多数现代语言(Go,Node JS,Python,PHP)已经具有用于AES的库。 本质上,上面的代码写的是:
Create AES Cipher (encryptor) using
NewCipher
function. Creating an AES Cipher required a passphrase. The passphrase is the human-readable format of the key.使用
NewCipher
函数创建AES密码(加密器)。 创建AES密码需要密码。 密码短语是密钥的人类可读格式。Ciphering plain text using
Seal
function. The output ofSeal
function is ciphertext in byte-formated which not a human-readable format. It is required to encode the ciphertext intobase64
so it can be stored in the Database.使用
Seal
功能对纯文本进行加密。Seal
函数的输出是字节格式的密文,而不是人类可读的格式。 需要将密文编码为base64
以便可以将其存储在数据库中。
We will use encrypt
function to encrypt nationalID
. The process will happen at createData
function.
我们将使用encrypt
功能对nationalID
进行加密。 该过程将在createData
函数处发生。
Data Decryption Function
数据解密功能
We need to create function to decrypt data stored in the Database. Decryption using the same key used during encryption.
我们需要创建函数来解密存储在数据库中的数据。 使用加密期间使用的相同密钥进行解密。
func decrypt(cipherText, key string) (plainText string, err error) {
// prepare cipher
keyByte := []byte(key)
block, err := aes.NewCipher(keyByte)
if err != nil {
return
}
gcm, err := cipher.NewGCM(block)
if err != nil {
return
}
nonceSize := gcm.NonceSize()
process ciphertext
ciphertextByte, _ := base64.StdEncoding.DecodeString(cipherText)
nonce, ciphertextByteClean := ciphertextByte[:nonceSize], ciphertextByte[nonceSize:]
plaintextByte, err := gcm.Open(
nil,
nonce,
ciphertextByteClean,
nil)
if err != nil {
log.Println(err)
return
}
plainText = string(plaintextByte)
//
return
}
The function above (decrypt
) is processing ciphertext and key into plaintext. There are 2 parts in the decrypt
function.
上面的功能( decrypt
)是将密文和密钥处理成明文。 decrypt
功能分为两部分。
The first part is preparing the cipher using
AES
andcipher
library from Go. It required a key used during encryption.第一部分是使用
AES
和Go中的cipher
库准备密码。 它需要加密期间使用的密钥。The second part is processing decryption. Data from the Database is string-type in base64 format. We need to format it into byte-type before running
Open
function. The output ofOpen
is byte type so we need to format it into string-type to make it human-readable.第二部分是处理解密。 来自数据库的数据是base64格式的字符串类型。 在运行
Open
函数之前,我们需要将其格式化为字节类型。Open
的输出为字节类型,因此我们需要将其格式化为字符串类型以使其易于阅读。
Unit Test
单元测试
Before we integrate encrypt
and decrypt
function into CRUD DB function. we must create the unit test to verify the output of decrypt
function is the same as plaintext.
在将encrypt
和decrypt
功能集成到CRUD DB功能之前。 我们必须创建单元测试以验证decrypt
函数的输出与纯文本相同。
func Test_encrypt(t *testing.T) {
type args struct {
plaintext string
key string
}
tests := []struct {
name string
args args
}{
{
name: "happy test",
args: args{
plaintext: "kingsman",
key: "04076d64bdb6fcf31706eea85ec98431"},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// encrypt the plaintext
ciphertext, err := encrypt(tt.args.plaintext, tt.args.key)
if err != nil {
t.Errorf("encrypt() error = %v", err)
return
}
t.Logf("ciphertext = %s", ciphertext)
decrypt the ciphertext from previous encrypt function
plaintext, err := decrypt(ciphertext, tt.args.key)
if err != nil {
t.Errorf("encrypt() error = %v", err)
return
}
t.Logf("plaintext = %s", plaintext)
compare the initial plaintext with output of previous decrypt function
if plaintext != tt.args.plaintext {
t.Errorf("plaintext = %v, want %v", plaintext, tt.args.plaintext)
}
//
})
}
}
We are running encrypt
function to encrypt plaintext (“kingsman”). The output is ciphertext which we will pass into decrypt
function. The expected output is the string-type value equal to the plaintext. Lastly, we compare the output with plaintext as verification. The test result is the following;
我们正在运行encrypt
功能来加密纯文本(“ kingsman”)。 输出为密文,我们将其传递给decrypt
函数。 预期的输出是等于明文的字符串类型值。 最后,我们将输出与纯文本进行比较以进行验证。 测试结果如下:
db-encryption go test -v -timeout 30s
=== RUN Test_encrypt
=== RUN Test_encrypt/happy_test
--- PASS: Test_encrypt (0.00s)
--- PASS: Test_encrypt/happy_test (0.00s)
main_test.go:78: ciphertext = sLR9ctALjY0rtAi8IvosScCtBE21gyMOBl3xHzi52Hbo+H3O
main_test.go:87: plaintext = kingsman
PASS
ok github.com/purnaresa/secureme/db-encryption 0.005s
Integration
积分
It is time to integrate to CRUD DB Function once we are confident that both encrypt
and decrypt
function working as expected. Basically we must encrypt the data right before we insert it into the Database.
一旦我们确信encrypt
和decrypt
功能均能按预期工作,就可以将其集成到CRUD DB Function了。 基本上,我们必须在将数据插入数据库之前对数据进行加密。
func createData(id, name, nationalID, createTimeUnix string) (err error) {
// encryption
nationalID, _ = encrypt(nationalID, masterKey)
//_, err = DB.Exec(`
INSERT INTO
user (id, name, national_id, create_time_unix)
VALUES
("?", "?", "?", "?")
`, id, name, nationalID, createTimeUnix)return
}
In the above code, we are running encryption for nationalID.
To simplify the example we are ignoring the error output.
在上面的代码中,我们正在为nationalID.
运行加密nationalID.
为了简化示例,我们忽略了错误输出。
And for decryption, we must run decrypt
function right after we read data from the Database.
对于解密,我们必须在从数据库读取数据后立即运行decrypt
功能。
func readData(id string) (user User, err error) {
row := DB.QueryRow(`
SELECT
id, name, national_id, create_time_unix
FROM
user
WHERE
id = "?"`, id)err = row.Scan(
&user.ID,
&user.Name,
&user.NationalID,
&user.CreateTimeUnix)// decryption
user.NationalID, _ = decrypt(user.NationalID, masterKey)
//
return
}
Summary
摘要
The sample provided in this project is the encryption of a single value. But it can be used to encrypt several values. AES mechanism is safe to use as long as the key is well guarded. This project is considered as a minimum requirement for Securing Information in Database because there are only two factors implemented (algorithm and key).
该项目中提供的示例是单个值的加密。 但是它可以用于加密多个值。 只要密钥受到良好的保护,AES机制就可以安全使用。 由于仅实现了两个因素(算法和密钥),因此该项目被认为是保护数据库中信息的最低要求。
Full code can be downloaded from Github: https://github.com/purnaresa/secureme/blob/master/db-encryption/main.go
完整的代码可以从Github下载: https : //github.com/purnaresa/secureme/blob/master/db-encryption/main.go
We can improve more security factors such as salt
so even if the key is stolen, an attacker couldn’t utilize the key to decrypt the ciphertext.What else do you think we can add to the next post?
我们可以改善salt
等安全性因素,因此即使密钥被盗,攻击者也无法利用该密钥解密密文。您认为我们还能在下一篇文章中添加什么?
If you found this article helpful for you, don’t forget to follow my account.Xoxo
如果您发现本文对您有所帮助,请不要忘记关注我的帐户。
数据库数据使用md5加密