近年來的Developer人數越來越多,可是在資料傳輸大多數人都忽略了加密的重要性。
因有SSL憑證的關係,很多人在處理資料後都是明碼就給了SSL層級來做加密的動作,那如果沒有了SSL憑證,資料要怎麼做比較安全。
以登入畫面為例,採用RSA非對稱式加密的方法來實作,對資料送出加密,以及後端SERVER接收後的解密。
前端會以JS來做加密動作,後端以C# 來做解密的處理。
非對稱式加密,也就是需要一把公開金鑰(Public Key),以及私有基金鑰(Private Key)。
會需要到的架構大概如下(隨意畫畫別太介意):
我們的Controller底下有一個Action來做畫面的顯示,以及POST帳號登入處理。
然後我們要先準備兩個兩把鑰匙的文件。一個為PEM檔案格式一個為XML檔案格式。
PEM檔案格式是給予前端做使用的公鑰,XML是給予C#作解密的私鑰,而為何不統一使用PEM格式,因為C#看不懂PEM的格式。
公開金鑰格式
-----BEGIN PUBLIC KEY-----
MIGeMA0GCSqGSIb3DQEBAQUAA4GMADCBiAKBgHGTSuKoFrGAblY0ftcXqEw4/BdX
gXyR/uNJPm1TZC9NGCLooIDy4QwYhoOlTUj9c5ucxE5IYWtYS/ssvnjki/YTreYc
R30L9O26FC1jLn/wr7VHp6LINbw6e1eTQnrjnnaJdifDO08vLimjnwefGuvzKDym
OiM2KQVCiRSf1JFdAgMBAAE=
-----END PUBLIC KEY-----
私有金鑰格式
<RSAKeyValue>
<Modulus>cZNK4qgWsYBuVjR+1xeoTDj8F1eBfJH+40k+bVNkL00YIuiggPLhDBiGg6VNSP1zm5zETkhha1hL+yy+eOSL9hOt5hxHfQv07boULWMuf/CvtUenosg1vDp7V5NCeuOedol2J8M7Ty8uKaOfB58a6/MoPKY6IzYpBUKJFJ/UkV0=</Modulus>
<Exponent>AQAB</Exponent>
<P>tpc/1vLLJXg2Agz1wqsSQdVbgZw/Rb1e4ABurKZOBMwmeUdzipnwzJv+Gd1cB9FBR/jmBD2MJoycJfyNeEbwFw==</P>
<Q>nzzIMRwp9Mb3rFBE3IB3y9PupCheKDXRS4U6UXK1ar/xMecIqfefOtCsz2mtz00fIB17FkI7g7rtbIeJiFyeqw==</Q>
<DP>RuqrwuJ+AEmWQGmkMj2bU7J4Xfi/omiQptPEKI5XEwnvj38u4xAzNGUJ5iXRjr+5aSjEvbTh8D8Ajshucd6rdQ==</DP>
<DQ>eXFjxICURwiPz60QN5MKyjsB39Shqs0QqCYdigyP67AjhUmMRASEPdj0UuNoGZfZyyZwv1MYDKk9de4QqBzrLQ==</DQ>
<InverseQ>HjiApzfA1DhEodRlv9NI92XUNN2intTbz9XMXKBOl/+GLRNtMccIukft9z5XbmXkHWLfLOm7RE0SWvzF2AxQjg==</InverseQ>
<D>MHFDopNRQppl9WzkoPedOA2iMI6JU0muLuGBt/22oJpAbjtMolN1+8PGNAZghX5dPgVKkZ07uB5sIhD+mO/aZiRH9fon9ov5GpWkjb1fCeOwTCei/hh2g+ipj7Jdgm7GmyIx7ZGnAzqAxH3UpBEVvasujbb2YK+0GB6Gsmqg690=</D>
</RSAKeyValue>
準備好兩份文件後我們就可以編寫Controller和View
首先進到登入畫面要將公鑰給前端網頁取得。
//顯示登入頁面
public ActionResult Login()
{
var Data = new LogOn();
Data.PublicKey = RSAService.GetPulicKey(); //將公開金鑰放置前端的頁面
return View(Data);
}
這裡解釋一下,RSAService只是去讀取我的公鑰的檔案,然後存成字串的模式,然後放在ViewModel給予前端使用。
@using (Html.BeginForm("Login", "Account", FormMethod.Post))
{
@Html.AntiForgeryToken()
<div class="form-bottom">
<form role="form" action="" method="post" class="login-form">
<div class="form-group">
<label class="sr-only" for="form-username">VENDORNO</label>
<input type="text" name="Account" class="form-username form-control" id="Account">
</div>
<div class="form-group">
<label class="sr-only" for="form-password">PWD</label>
<input type="password" name="PWD" class="form-password form-control" id="PWD">
</div>
<div id="PublicKey" class="hidden" data-val="@Model.PublicKey"></div>
<button type="submit" id="LoginBT" class="btn btn-Login">Singin</button>
</form>
</div>
}
這裡作法是將Public Key存在DIV裡面,當然也可以使用COOKIES的方式來放置PublicKey,就看實作的時候要採取什麼方式。
下一步就是前端的加密JS如下:
<script src="~/Scripts/RSA/jsencrypt.js"></script>
<script>
$('#LoginBT').click(function ()
{
$.blockUI({
message: "<i class='fa fa-spinner fa-pulse orange' style='font-size:600%'></i>",
//borderWidth:'0px' 和透明背景
css: { borderWidth: '0px', backgroundColor: 'transparent' },
});
var publicKey = $('#PublicKey').data("val");
var encryptedPassword;
var pwd = $('#PWD').val();
if (pwd !== null && pwd !== "") {
var crypt = new JSEncrypt();
crypt.setPublicKey(publicKey);
encryptedPassword = crypt.encrypt(pwd);
console.log(encryptedPassword);
$('#PWD').val(encryptedPassword);
}
})
</script>
這段會引用到JSEncryp來做加密的動作,此外還用了BLOCKUI來做遮罩的事件。
加密完再將資料放回TEXTBOX,採用原生的ASP.NET MVC @using (Html.BeginForm("Login", "Account", FormMethod.Post))將資料傳送至後端的Action。
後端接收到資料的時候密碼會是加密過的資料,然後用SERVER端的私有鑰匙進行解密,如下:
Controller
[HttpPost]
[ValidateAntiForgeryToken]
[AllowAnonymous]
public ActionResult Login(LogOn LogOnModel)
{
if (!ModelState.IsValid)
{
return View();
}
LogOnModel.PWD = RSAService.GetPlainText(LogOnModel.PWD); //解密取得明碼
}
Service解密實作:
public static string RSADecrypt(string xmlPrivateKey, string m_strDecryptString)
{
byte[] PlainTextBArray;
byte[] DypherTextBArray;
string Result;
var rsa = new RSACryptoServiceProvider();
rsa.FromXmlString(xmlPrivateKey);
PlainTextBArray = Convert.FromBase64String(m_strDecryptString);
DypherTextBArray = rsa.Decrypt(PlainTextBArray, false);
Result = (new ASCIIEncoding()).GetString(DypherTextBArray);
return Result;
}
這裡採用.Net所提供的RSACryptoServiceProvider來做解密動作,需要將加密後的資料打成Byte[]的資料型態,取得私有鑰匙進行解密,在編碼回去看得懂的資料型態。
加解密大致上就到這邊,後續的應用就靠自己延伸出更多的想法吧,不僅僅是字串加密,資料檔案傳輸也都能加密。
前端的Public Key
在網路傳輸時候加密過的資料:(在此還保留了MVC的@Html.AntiForgeryToken()防偽機制)
後端解密前:
後端解密後:
新手發文,有誤麻煩用力鞭策,謝謝。
本篇參考: