最近项目上出现了明文密码,被检测出来漏洞了,那也就是说,我们的密码要加密,这本身就是一件非常平常的事情。
这里大家或是有经验的开发人员,可能觉得再普通不过了,直接md5加密,跟数据库的字段做匹配,一致的就可以登录成功了。
要是这么简单的话,就不用特意来记录这个安全了,我们项目是这样的,这个项目用上了AD域登录,不知道大家对这个有没有什么概念。
接下来是AD域的概念:
“域帐号登录”属于“交互式登录”(即用户通过相应的用户帐号(UserAccount)和密码进行登录)的一种(另外一种为“本地登录”)。采用域用户帐号登录计算机,系统通过存储在域控制器的活动目录中的数据进行验证。如果该用户帐号有效,则登录后可以访问到整个域中具有访问权限的资源。
其实大概就是这么个意思,就是客户不想用户每个系统一个密码,这样用户太麻烦了,所以都统一使用AD域的密码账户来登录各个业务系统。
那介绍了AD的概念之后,究竟跟我们的密码加密有什么有关系呢?主要是AD域这里使用的是明文密码,所以我们不能用MD5加密,否则肯定验证不成功的。
为此,我们这里就引进了一种AES对称式加密,对密码进行解密,最后再传到AD域那边去验证,让业务系统整个流程可以跑通起来。
那接下来,我们就要介绍下,我们的AES算法了
接下来用的是C#的代码
//加密
publicstaticstringEncrypt(stringstr,stringstrkey,stringstrvalue)
{
//byte[]IV={57,87,122,110,97,109,111,53,65,95,114,101,120,73,72,84};
//stringkey="MKE7612Y4ADF8JD1";
byte[]clearBytes=Encoding。UTF8。GetBytes(str);
byte[]keyBytes=Encoding。UTF8。GetBytes(strkey);
byte[]ivBytes=Encoding。UTF8。GetBytes(strvalue);
//byte[]clearBytes=Convert。FromBase64String(str);
using(Aesencryptor=Aes。Create())
{
encryptor。Key=keyBytes;
encryptor。IV=ivBytes;
using(MemoryStreamms=newMemoryStream())
{
using(CryptoStreamcs=newCryptoStream(ms,encryptor。CreateEncryptor(),CryptoStreamMode。Write))
{
cs。Write(clearBytes,0,clearBytes。Length);
cs。Close();
}
str=Convert。ToBase64String(ms。ToArray());
}
}
returnstr;
}
publicstaticstringDecryptStringAES(stringencryptedValue,stringstrkey,stringstrvalue)
{
try
{
varkeybytes=Encoding。UTF8。GetBytes(strkey);
variv=Encoding。UTF8。GetBytes(strvalue);
//DECRYPTFROMCRIPTOJS
varencrypted=Convert。FromBase64String(encryptedValue);
vardecriptedFromJavascript=DecryptStringFromBytes(encrypted,keybytes,iv);
returndecriptedFromJavascript;
}
catch(Exceptionex)
{
return"";
}
}
//解密
privatestaticstringDecryptStringFromBytes(byte[]cipherText,byte[]key,byte[]iv)
{
//Checkarguments。
if(cipherText==null||cipherText。Length<=0)
{
thrownewArgumentNullException("cipherText");
}
if(key==null||key。Length<=0)
{
thrownewArgumentNullException("key");
}
if(iv==null||iv。Length<=0)
{
thrownewArgumentNullException("key");
}
//Declarethestringusedtohold
//thedecryptedtext。
stringplaintext=null;
//CreateanRijndaelManagedobject
//withthespecifiedkeyandIV。
using(varrijAlg=newRijndaelManaged())
{
//Settings
rijAlg。Mode=CipherMode。CBC;
rijAlg。Padding=PaddingMode。PKCS7;
rijAlg。FeedbackSize=128;
rijAlg。Key=key;
rijAlg。IV=iv;
//Createadecrytortoperformthestreamtransform。
vardecryptor=rijAlg。CreateDecryptor(rijAlg。Key,rijAlg。IV);
//Createthestreamsusedfordecryption。
using(varmsDecrypt=newMemoryStream(cipherText))
{
using(varcsDecrypt=newCryptoStream(msDecrypt,decryptor,CryptoStreamMode。Read))
{
using(varsrDecrypt=newStreamReader(csDecrypt))
{
//Readthedecryptedbytesfromthedecryptingstream
//andplacetheminastring。
plaintext=srDecrypt。ReadToEnd();
}
}
}
}
returnplaintext;
}
调用语句加密
stringaa=aesenHelper。Encrypt("123","2023080514454401","2023080514454401");
通过代码,大家以为到这里就完了,其实不然,那假如,我们在数据库里边要进行加密解密怎么办?
这里研究了很久,反正我没找到可以直接用sql把C#的代码还原到sqlserver数据库里边。试过很多种方法,都没办法加密出一样的密文,为此,我们使用了 clr这种功能。
以下是sqlserver代码
--开启CLR支持,并且指定某个数据库支持unsafe模式
EXECsp_configure'clrenabled',1;
RECONFIGURE;
GO
ALTERDATABASEv3_kd_newSETTRUSTWORTHYON;
GO
Sp_changedbowner'sa',true--sa
--为了能够调到C#的Encrypt方法,需要SQLSERVER先导入这个程序集,然后再以Function映射其中方法即可
--dropASSEMBLYclr_Bussiness
CREATEASSEMBLYclr_Bussiness
FROM'E:\database\aesencryption。dll'
WITHPERMISSION_SET=UNSAFE;
GO
--dropfunction clr_Encrypt
CREATEFUNCTIONdbo。clr_Encrypt
(
@strASNVARCHAR(100),
@strkeyASNVARCHAR(100),
@strvalueASNVARCHAR(100)
)
RETURNSNVARCHAR(100)
AS
EXTERNALNAMEclr_Bussiness。[aesencryption。aesenHelper]。Encrypt;
GO
--创建完了之后,可以观察assembly开头的几个系统视图
SELECT*FROMsys。assemblieswherename='clr_Bussiness'
SELECT*FROMsys。assembly_files;
SELECT*FROMsys。assembly_modules;
--接下来调用一下刚才创建的clr_UserLogin函数。
selectdbo。clr_Encrypt(N'123',N'2023080514454401',N'2023080514454401')AS'aa'
以上是自己的做为资深开发的一些个人经历,把这些经验分享给大家,希望以后大家在从事开发中,可以避免不必要的麻烦,跟浪费时间精力。
要是大家喜欢我的文章的话,可以在文章下留言或是联系我,共同进步,共同探讨开发的一些案例,促进彼此间的交流,分享一些日常的开发趣事。
共有 0 条评论