当前位置: 首页 > 科技观察

敏感数据加密方案及实现

时间:2023-03-16 12:19:24 科技观察

前言现在是大数据时代,需要收集大量的个人信息进行统计。一方面给我们带来了便利,另一方面,一些个人信息数据在无意中被泄露,被不法分子用于促销和黑色产业。2018年5月25日,欧盟实施了《通用数据保护条例》(通用数据保护条例,简称GDPR)。该法规是欧盟法律关于所有欧盟个人数据保护和隐私的规范。这意味着必须使用假名化或匿名化来存储个人数据,并且默认情况下使用尽可能高的隐私设置以避免数据泄露。相信大家都不想在外面“裸奔”。因此,作为前端开发者,也应该尽量避免用户个人数据的明文传输,尽可能降低信息泄露的风险。看到这里,可能有人会说,现在用的是HTTPS,数据在传输的时候是加密的,所以前端不需要加密。其实我可以在你发送HTTPS请求之前,通过Google插件在HTTPS请求中抓取个人信息,下面我会演示一下。因此,前端数据加密还是很有必要的。数据泄露方式1.中间人攻击中间人攻击是一种常见的攻击方式。详细过程可以看这里:https://zh.wikipedia.org/wiki/%E4%B8%AD%E9%97%B4%E4%BA%BA%E6%94%BB%E5%87%BB.大致过程是中间人通过DNS欺骗等手段劫持客户端与服务器之间的会话。客户端和服务器之间的信息会经过中介,中介可以获取和转发双方的信息。HTTP下,前端数据加密还是不能避免数据泄露,因为中间人可以伪造密钥。为了避免中间人攻击,我们一般使用HTTPS进行传输。2.GooglepluginHTTPS虽然可以防止数据在网络传输过程中被劫持,但是在发送HTTPS之前Googleplugin还是有可能泄露数据的。由于Google插件可以捕获Network中的所有请求,如果某些插件中存在恶意代码,仍然可以获取到用户信息,如下图。因此,如果只使用HTTPS,一些敏感信息如果仍然以明文传输是不安全的。如果数据在HTTPS的基础上加密就更好了。加密算法介绍1.对称加密对称加密算法,又称共享密钥加密算法。在对称加密算法中,只使用一个密钥,发送方和接收方都使用这个密钥来加密和解密数据。这就需要加解密双方事先知道加密密钥。其优点是算法开放,计算量小,加密速度快,加密效率高;缺点是密钥泄露后,数据会被破解。一般不建议单独使用。根据不同的实现机制,常见的算法主要有:AES(https://zh.wikipedia.org/wiki/%E9%AB%98%E7%BA%A7%E5%8A%A0%E5%AF%86%E6%A0%87%E5%87%86)ChaCha20(https://zh.wikipedia.org/wiki/Salsa20#ChaCha20)、3DES(https://zh.wikipedia.org/wiki/3DES)等2.非对称加密非对称加密算法,又称公钥加密算法。它需要两把钥匙,一把叫做公钥(publickey),即公钥;另一个称为私钥(privatekey),即私钥。它们是通过配对产生的,就像钥匙和锁的关系。由于加密和解密使用两个不同的密钥,所以这种算法称为非对称加密算法。其优点是算法强度复杂,安全性高;缺点是加密和解密的速度没有对称加密算法快。常见的算法主要有:RSA(https://zh.wikipedia.org/wiki/RSA%E5%8A%A0%E5%AF%86%E6%BC%94%E7%AE%97%E6%B3%95)Elgamal(https://zh.wikipedia.org/wiki/ElGamal%E5%8A%A0%E5%AF%86%E7%AE%97%E6%B3%95)等3.HashAlgorithm哈希算法也称为哈希函数或哈希函数,将消息或数据压缩成摘要,使数据量变小,并将数据的格式固定为特定长度的值。一般用于检查数据的完整性。通常我们在下载文件的时候可以通过校验MD5来判断下载的数据是否完整。常见的算法主要有:MD4(https://zh.wikipedia.org/wiki/MD4)MD5(https://zh.wikipedia.org/wiki/MD5)SHA(https://zh.wikipedia.org/wiki/SHA%E5%AE%B6%E6%97%8F)等解决方案一:如果采用对称加密,则服务端和客户端都必须知道密钥。服务器必须将密钥发送给客户端。这个过程是不安全的,所以单靠对称加密是行不通的。方案二:如果采用非对称加密,客户端的数据用公钥加密,服务端用私钥解密。客户端发送数据实现加密是没有问题的。当客户端接受数据时,服务器需要用公钥加密,然后客户端用私钥解密。因此,该方案需要两套公钥和私钥,并且需要在客户端和服务端生成各自的密钥。方案三:如果结合对称加密和非对称加密。客户端需要生成一个对称加密密钥1,传输内容用密钥1加密后传输给??服务器,密钥1和公钥进行非对称加密后传输给??服务器。服务端通过私钥解密对称加密密钥1,再通过密钥1解密内容。以上就是客户端到服务端的过程。如果服务端要向客户端发送数据,需要用对称加密密钥1对响应数据进行加密,然后客户端收到密文,通过客户端的密钥1进行解密,完成加密传输。总结:以上只是列出了常见的加密方案。一般来说,第二种方案比较简单,但是需要维护两套公钥和私钥。当公钥发生变化时,必须通知对方,灵活性较差。与方案二相比,密钥1可以随时更改,无需通知服务器,相对更加灵活和安全,方案三对内容进行了对称加密。当数据量很大时,对称加密的速度会比非对称加密快。因此,本文采用方案三给出代码实现。代码实现下面是具体的代码实现(以登录界面为例),主要目的是将个人信息明文转换为密文进行传输。对称加密库使用AES,非对称加密库使用RSA。客户端:AES库(aes-js):https://github.com/ricmoo/aes-jsRSA库(jsencrypt):https://github.com/travist/jsencrypt具体实现登录界面的代码(一)客户端终端需要随机生成一个aesKey,在页面加载时需要请求publicKeyletaesKey=[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15fromtheserver,16];//随机生成letpublicKey="";//公钥会从服务器获取//页面加载完成后,去获取公钥window.onload=()=>{axios({method:"GET",headers:{"content-type":"application/x-www-form-urlencoded"},url:"http://localhost:3000/getPub",}).then(function(result){publicKey=result.data.data;//获取公钥}).catch(function(error){console.log(error);});};2.aes加密解密方式/***aes加密方式*@param{string}待加密的文本字符串*@param{array}key加密密钥*/functionaesEncrypt(text,key){consttextBytes=aesjs.utils.utf8.toBytes(text);//将字符串转为二进制数据//这里使用CTR-Counter加密模式,还有其他模式可以选择,具体参考aes加密库constaesCtr=newaesjs.ModeOfOperation.ctr(key,newaesjs.Counter(5));constencryptedBytes=aesCtr.encrypt(textBytes);//encryptconstencryptedHex=aesjs.utils.hex.fromBytes(encryptedBytes);//放两个将二进制数据转成十六进制returnencryptedHex;}/***aes解密方法*@param{string}encryptedHex加密字符串*@param{array}key加密密钥*/functionaesDecrypt(encryptedHex,key){constencryptedBytes=aesjs.utils.hex。toBytes(encryptedHex);//将十六进制数据转换为二进制constaesCtr=newaesjs.ModeOfOperation.ctr(key,newaesjs.Counter(5));constdecryptedBytes=aesCtr.decrypt(encryptedBytes);//解密constdecryptedText=aesjs.utils.utf8.fromBytes(decryptedBytes);//将二进制数据转为utf-8字符串returndecryptedText;}3.请求登录/***登录界面*/functionsubmitFn(){constuserName=document.querySelector("#userName").value;constpassword=document.querySelector("#password").value;constdata={userName,password,};consttext=JSON.stringify(data);constsendData=aesEncrypt(text,aesKey);//将要发送的数据转换成字符串用于加密console.log("senddata",text);constencrypt=newJSEncrypt();encrypt.setPublicKey(publicKey);constencryptencrypted=encrypt.encrypt(aesKey.toString());//非对称加密aesKeyconsturl="http://localhost:3000/login";constparams={id:0,data:{param1:sendData,param2:encrypted}};axios({method:"POST",headers:{"content-type":"application/x-www-form-urlencoded"},url:url,data:JSON.stringify(params),}).then(function(result){constreciveData=aesDecrypt(result.data.data,aesKey);//用aesKey解密console.log("receivedata",reciveData);}).catch(function(error){console.log("error",error);});}服务器(节点):AES库(aes-js):https://github.com/ricmoo/aes-jsRSA库(node-rsa):https://github.com/rzcoder/node-rsa具体代码实现登录接口(1)引用加密库consthttp=require("http");constaesjs=require("aes-js");constNodeRSA=require("node-rsa");constrsaKey=newNodeRSA({b:1024});//密钥大小为1024位letaesKey=null;//用于保存aesKeyletprivateKey="";//用于保存server'spublickeyrsaKey.setOptions({encryptionScheme:"pkcs1"});//设置加密方式(2)实现登录接口http.createServer((request,response)=>{response.setHeader("Access-Control-允许来源","*");response.setHheader("Access-Control-Allow-Headers","Content-Type");response.setHeader("Content-Type","application/json");switch(request.method){case"GET":if(request.url==="/getPub"){constpublicKey=rsaKey.exportKey("public");privateKey=rsaKey.exportKey("private");response.writeHead(200);response.end(JSON.stringify({result:true,data:publicKey}));//发送公钥给客户端return;}break;case"POST":if(request.url==="/login"){letstr="";request.on("data",function(chunk){str+=chunk;});request.on("end",function(){constparams=JSON.parse(str);constreciveData=decrypt(params.data);控制台.log("reciveData",reciveData);//一系列处理后response.writeHead(200);response.end(JSON.stringify({result:true,data:aesEncrypt(JSON.stringify({userId:123,address:"Hangzhou"}),//此数据将被aesKey加密),}));});return;}break;default:break;}response.writeHead(404);response.end();}).listen(3000);3。加解密方法functiondecrypt({param1,param2}){constdecrypted=rsaKey.decrypt(param2,"utf8");//解密得到aesKeyaesKey=decrypted.split(",").map((item)=>{return+item;});returnaesDecrypt(param1,aesKey);}/***aes解密方式*@param{string}encryptedHex加密字符串*@param{array}key加密密钥*/functionaesDecrypt(encryptedHex,key){constencryptedBytes=aesjs.utils.hex.toBytes(encryptedHex);//将十六进制数据转换为二进制数据consstaesCtr=newaesjs.ModeOfOperation.ctr(key,newaesjs.Counter(5));//这里使用CTR-Counter加密方式,也可以选择其他方式。具体可以参考aes加密库//将二进制数据转成字符串returndecryptedText;}/***aes加密方式*@param{string}待加密的text字符串*@param{array}key加密密钥*/functionaesEncrypt(text,key){consttextBytes=aesjs.utils.utf8.toBytes(text);//将字符串转为二进制数据constaesCtr=newaesjs.ModeOfOperation.ctr(key,newaesjs.Counter(5));constencryptedBytes=aesCtr.encrypt(textBytes);//加密constencryptedHex=aesjs.utils.hex.fromBytes(encryptedBytes);//将二进制数据转换为十六进制returnencryptedHex;}完整示例代码:https://github.com/Pulset/FrontDataEncrypt演示总结本文主要介绍一些前端安全方面的内容,以保护客户的隐私数据,无论是HTTP还是HTTPS,建议采用密文传输信息,这样破解者可以增加攻击难度。当然,数据加解密也会带来一定的性能消耗,这需要每个开发者衡量。