亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > C# > 正文

使用數字簽名實現數據庫記錄防篡改(Java實現)

2019-10-29 21:15:10
字體:
來源:轉載
供稿:網友

本文大綱

一、提出問題

二、數字簽名

三、實現步驟

四、參考代碼

五、后記

六、參考資料

一、提出問題

最近在做一個項目,需要對一個現成的產品的數據庫進行操作,增加額外的功能。為此,需要對該產品對數據庫有什么操作進行研究(至于怎么監控一個產品的操作會引發什么數據庫操作,以后會詳細解說)。本來已經對數據庫的操作了如指掌的,無意中發現數據庫表里的每條記錄都會有這樣一個字段:

數據庫防篡改

這感覺不妙了,字段名叫signature,顧名思義,就是簽名的意思呀。難道數據庫表中的每條記錄都會有簽名?也就是說如果我不能正確生成簽名,而直接改記錄中的字段,會被程序認為非法篡改了數據?那以后我的產品設計,是否也可采用這種方式來對每條記錄做簽名,防止數據被非法篡改,例如日志表中的數據?抱著這一發現以及這一連串的問題,我進行了以下的研究。在這里我將研究整理了一下,分享給大家。

二、數字簽名

要解決上面的問題,首先就要對最基礎的知識進行了解。這里最基礎的知識,無疑就是什么是數字簽名了。很多同學可能對這個名詞并不陌生,但估計大多數人都是對其一知半解,會把散列、非對稱加密、數字簽名、數字證書的幾個概念混為一談,造成混亂。所以我先對相關概念進行解釋,再往下講。如果很熟悉這方面的同學可以跳過此部分,但對于絕大多數同學來說,不建議這樣做。基礎沒搭好,直接看怎么實現,換了個說法又不知道怎么去做了。要想提高個人能力,做到舉一反三很重要。

言歸正傳,先對跟數字簽名有關的密碼學知識簡單說一下。加密方法分兩大類,分別是單鑰加密和雙鑰加密,數字簽名涉及到雙鑰加密。關于雙鑰加密,主要涉及到以下幾個要點[1]:

  • 雙鑰加密的密鑰有兩把,一把是公開的公鑰,一把是不公開的私鑰
  • 公鑰和私鑰是一一對應的關系,有一把公鑰就必然有一把與之對應的、獨一無二的私鑰,反之亦成立。
  • 所有的(公鑰, 私鑰)對都是不同的。
  • 用公鑰可以解開私鑰加密的信息,反之亦成立。
  • 同時生成公鑰和私鑰應該相對比較容易,但是從公鑰推算出私鑰,應該是很困難或者是不可能的。
  • 在雙鑰體系中,公鑰用來加密信息,私鑰用來數字簽名。
  • 還有一點關于數字證書的。因為任何人都可以生成自己的公鑰私鑰對,所以為了防止有人散布偽造的騙取信任,就需要一個可靠的第三方機構來生成經過認證的公鑰、私鑰對。簡單來說,數字證書是權威的第三方機構頒發的,用來認證某對公鑰私鑰的證書,經過這個數字證書認證的公鑰私鑰,就可以明確屬于某人或者某機構,是合法的,可信任的。就如同身份證,是證明你身份的一個證件。所以數字證書跟數字簽名是兩回事,要分清楚。

數字簽名,顧名思義,就類似于一種寫在紙上的普通的物理簽名,不同的是,數字簽名是電子信息化的,采用雙鑰加密的技術實現,是一種用于鑒別數字信息的方法。處理的過程,簡單說就是將文件內容進行hash散列,信息發送者對散列后的字符串使用私鑰加密,得到的最終字符串就是簽名。然后將得到的簽名字符串添加到文件信息的后面一同發送出去。接收者獲取到文件信息和簽名后,使用公鑰對簽名進行解密,就得到文件內容加密后的hash散列。此時,他可以對獲取到的文件內容做hash散列,與簽名中的hash散列進行匹對,從而鑒別出最終獲取信息的真偽。主要過程如這四幅圖所示[2]:

數據庫防篡改

對文件內容進行hash散列,生成摘要

數據庫防篡改

對生成的摘要,使用私鑰進行加密,形成簽名

數據庫防篡改

將得到的簽名,附到文件內容后部,就想到與簽名簽到文件尾部那樣子

數據庫防篡改

使用公鑰對簽名進行解密,得到摘要,并與獲取到的文件內容生成的摘要做對比,以確定是否被篡改

想了解更詳細的數字證書相關內容,可以訪問此地址:http://www.youdzone.com/signature.html。里面解釋得很形象,應該一看就明白的了。

三、實現步驟

看到這里,開篇提出的問題也就呼之欲出了。沒錯,就是使用數字簽名技術,將數據庫中的重要字段進行簽名,將簽名結果作為記錄的一列存在記錄中。這樣當有人入侵數據庫,惡意修改字段,程序讀數據時拿簽名校驗一下,就知道數據是否有被修改過了。

在java.security包中,有很多有用的類,用以進行安全機制的開發。對于要創建數字簽名,我們主要用到以下的接口或類:

 

接口名

描述

PrivateKey

A private key

PublicKey

A public key

 

接口

 

 類名

描述

Signature

The Signature class is used to provide applications the functionality of a digital signature algorithm.

KeyPair

This class is a simple holder for a key pair (a public key and a private key)

KeyPairGenerator

The KeyPairGenerator class is used to generate pairs of public and private keys.

 

對于接口和類的描述,我直接引用了Oracle上的J2SE 7的API描述[3],就不翻譯成中文了,以防詞不達意。大家看英文應該能更精確的明白其意思。

利用上述的接口和類,就可以進行數字簽名和驗證了,下面分三部分進行基本步驟的描述。

第一部分:生成密鑰并存儲

  • 生成KeyPairGenerator實例,并調用其genKeyPair()方法生成KeyPair對象。
  • 利用ObjectOutputStream實例,將KeyPair對象寫到文件中,從而把密鑰保存到文件中。

第二部分:進行數字簽名

  • 從密鑰文件中讀取KeyPair對象。
  • 調用KeyPair對象的getPrivate()和getPublic()方法,分別獲取PrivateKey和PublicKey。
  • 利用密鑰的指定算法生成Signature實例,然后利用PrivateKey和文件內容,分別調用其initSign()和update()方法,最后調用sign()方法生成數字簽名。

第三部分:進行簽名驗證

  • 從密鑰文件中讀取KeyPair對象。
  • 調用KeyPair對象的getPrivate()和getPublic()方法,分別獲取PrivateKey和PublicKey。
  • 利用密鑰的指定算法生成Signature實例,然后利用PublicKey和文件內容,分別調用其initSign()和update()方法,最后利用數字簽名調用verify()方法驗證簽名。

四、參考代碼

根據上面的步驟描述,基本可以寫出程序來了。下面是參考代碼,未必盡善盡美,但是基本功能都體現到了,供你參考。

工程結構:

數據庫防篡改

DataSecurity類:

package com.hzj.security;import java.io.UnsupportedEncodingException;import java.nio.charset.CharsetEncoder;import java.security.KeyPair;import com.hzj.util.StringHelper;public class DataSecurity { private KeyPair keyPair; private static final String KEY_FILE = "/ca.key"; private DataSignaturer dataSignaturer; public DataSecurity() { try { this.keyPair = KeyPairUtil.loadKeyPair(getClass().getResourceAsStream("/ca.key")); this.dataSignaturer = new DataSignaturer(this.keyPair.getPublic(), this.keyPair.getPrivate()); } catch (RuntimeException e) { System.out.println("沒有找到KeyPair文件[/ca.key]!"); } } /** * 驗證數字簽名 * @param data * @param signs * @return */ public boolean verifySign(String data, String signs) { if ((data == null) || (signs == null)) { System.out.println("參數為Null"); } boolean verifyOk = false; try { verifyOk = this.dataSignaturer.verifySign(data.getBytes("UTF-8"), StringHelper.decryptBASE64(signs)); } catch (RuntimeException e) { System.out.println("fail!data=" + data + ", sign=" + signs + ", exception:" + e.getMessage()); } catch (UnsupportedEncodingException e) { System.out.println("不支持UTF-8字符集"); } catch (Exception e) { System.out.println("Exception:" + e.getMessage()); } if (!verifyOk) { System.out.println("fail!data=" + data + ", sign=" + signs + ", verifyOk=false!"); } return verifyOk; } /** * 生成數字簽名 * @param data * @return */ public String sign(String data) { if (data == null) { System.out.println("參數為Null"); } String sign = null; try { sign = StringHelper.encryptBASE64(this.dataSignaturer.sign(data.getBytes("UTF-8"))); } catch (UnsupportedEncodingException e) { System.out.println("不支持UTF-8字符集"); } catch (Exception e) { System.out.println(e.getMessage()); } return sign; } }

DataSignaturer類:

package com.hzj.security;import java.security.InvalidKeyException;import java.security.NoSuchAlgorithmException;import java.security.PrivateKey;import java.security.PublicKey;import java.security.Signature;import java.security.SignatureException;public class DataSignaturer { private PrivateKey privateKey; private PublicKey publicKey; public DataSignaturer(PublicKey publicKey, PrivateKey privateKey){ this.privateKey = privateKey; this.publicKey = publicKey; } /** * 進行數字簽名 * @param data * @return */ public byte[] sign(byte[] data) { if (this.privateKey == null) { System.out.println("privateKey is null"); return null; } Signature signer = null; try { signer = Signature.getInstance(this.privateKey.getAlgorithm()); } catch (NoSuchAlgorithmException e) { System.out.println(e.getMessage()); } try { signer.initSign(this.privateKey); } catch (InvalidKeyException e) { System.out.println(e.getMessage()); } try { signer.update(data); return signer.sign(); } catch (SignatureException e) { System.out.println(e.getMessage()); return null; } catch (NullPointerException e) { System.out.println(e.getMessage()); return null; } } /** * 驗證數字簽名 * @param data * @param signature * @return */ public boolean verifySign(byte[] data, byte[] signature) { if (this.publicKey == null) { System.out.println("publicKey is null"); return false; } Signature signer = null; try { signer = Signature.getInstance(this.publicKey.getAlgorithm()); } catch (NoSuchAlgorithmException e) { System.out.println(e.getMessage()); return false; } try { signer.initVerify(this.publicKey); } catch (InvalidKeyException e) { System.out.println(e.getMessage()); return false; } try { signer.update(data); return signer.verify(signature); } catch (SignatureException e) { System.out.println(e.getMessage()); return false; } }}

KeyPair類:

package com.hzj.security;import java.io.FileNotFoundException;import java.io.IOException;import java.io.InputStream;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import java.io.OutputStream;import java.security.KeyPair;import java.security.KeyPairGenerator;import java.security.NoSuchAlgorithmException;public class KeyPairUtil { // 采用的雙鑰加密算法,既可以用DSA,也可以用RSA public static final String KEY_ALGORITHM = "DSA"; /** * 從輸入流中獲取KeyPair對象 * @param keyPairStream * @return */ public static KeyPair loadKeyPair(InputStream keyPairStream) { if (keyPairStream == null) { System.out.println("指定的輸入流=null!因此無法讀取KeyPair!"); return null; } try { ObjectInputStream ois = new ObjectInputStream(keyPairStream); KeyPair keyPair = (KeyPair) ois.readObject(); ois.close(); return keyPair; } catch (Exception e) { System.out.println(e.getMessage()); } return null; } /** * 將整個KeyPair以對象形式存儲在OutputStream流中, 當然也可以將PublicKey和PrivateKey作為兩個對象分別存到兩個OutputStream流中, * 從而私鑰公鑰分開,看需求而定。 * @param keyPair 公鑰私鑰對對象 * @param out 輸出流 * @return */ public static boolean storeKeyPair(KeyPair keyPair, OutputStream out) { if ((keyPair == null) || (out == null)) { System.out.println("keyPair=" + keyPair + ", out=" + out); return false; } try { ObjectOutputStream oos = new ObjectOutputStream(out); oos.writeObject(keyPair); oos.close(); return true; } catch (FileNotFoundException e) { System.out.println(e.getMessage()); } catch (IOException e) { System.out.println(e.getMessage()); } return false; } /** * 生成KeyPair公鑰私鑰對 *  * @return */ public static KeyPair initKeyPair() throws NoSuchAlgorithmException{ KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM); keyPairGen.initialize(1024); return keyPairGen.genKeyPair(); } /** * 生成密鑰,并存儲 * @param out * @return * @throws NoSuchAlgorithmException */ public static boolean initAndStoreKeyPair(OutputStream out) throws NoSuchAlgorithmException { return storeKeyPair(initKeyPair(), out); }}

StringHelper類:

package com.hzj.util;import sun.misc.BASE64Encoder;import sun.misc.BASE64Decoder;public class StringHelper { /**  * BASE64Encoder 加密  * @param data 要加密的數據  * @return 加密后的字符串  */  public static String encryptBASE64(byte[] data) {  BASE64Encoder encoder = new BASE64Encoder();  String encode = encoder.encode(data);  return encode;  }  /**  * BASE64Decoder 解密  * @param data 要解密的字符串  * @return 解密后的byte[]  * @throws Exception  */  public static byte[] decryptBASE64(String data) throws Exception {  BASE64Decoder decoder = new BASE64Decoder();  byte[] buffer = decoder.decodeBuffer(data);  return buffer;  } }

Program類:

package com.hzj.main;import java.io.File;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.security.NoSuchAlgorithmException;import com.hzj.security.DataSecurity;import com.hzj.security.KeyPairUtil;public class Program { public static void main(String[] args) { // 1.生成證書// File file = new File("ca.key");// try {// FileOutputStream fileOutputStream = new FileOutputStream(file);// KeyPairUtil.initAndStoreKeyPair(fileOutputStream);// } catch (FileNotFoundException | NoSuchAlgorithmException e) {// e.printStackTrace();// } // 2.生成數字簽名// DataSecurity dataSecurity = new DataSecurity();// String sign = dataSecurity.sign("大家好");// System.out.println("sign:" + sign); //3.驗證數字簽名 DataSecurity dataSecurity = new DataSecurity(); boolean result = dataSecurity.verifySign("大家好", "MCwCFCDs3sBw/fXK9flndl0M5lAUiPYFAhR9vyNNc91UiUBxFwK3GzLLjWgTkQ=="); System.out.println("result:" + result); }}

這里需要注意的是,為什么要對數字簽名進行進行Base64編碼呢?這是因為生成的數字簽名是byte[]型的,無論對應哪一種字符集來轉化成String,都會有亂碼出現。所以,采用Base64進行編碼,就可以得到一串可見的字符串,方便存儲和重新調用。

五、后記

寫到這里,本文的內容就基本上完結了。有人看到這里就會問,這不是說數據庫記錄防篡改嘛,一直都在講數字簽名,究竟怎么個防篡改?前文已經對數字簽名的一些基本原理,使用的場景,開發的步驟、代碼等進行了描述,開篇是也描述了項目中遇到的數據庫中的問題。將這些信息綜合起來,應該就知道怎么將數字簽名應用到數據庫記錄中來作為數據庫防篡改的工具了。知道工具怎么用是基礎,會用工具來完成自己想做的事情,就是進階了。祝你步步高升!

以上就是本文的全部內容,希望本文的內容對大家的學習或者工作能帶來一定的幫助,同時也希望多多支持VEVB武林網!


注:相關教程知識閱讀請移步到c#教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
欧美日韩中文字幕日韩欧美| 欧美激情欧美激情在线五月| 欧洲成人午夜免费大片| 美女视频久久黄| 精品国产拍在线观看| 亚洲国产高清高潮精品美女| 日韩精品欧美激情| 午夜精品国产精品大乳美女| 国产免费一区二区三区在线能观看| 日韩成人小视频| 国产精品福利小视频| 国产精品亚洲精品| 亚洲天堂男人的天堂| 综合网中文字幕| 国产色视频一区| 久久影院免费观看| 在线激情影院一区| 日韩视频一区在线| 久久人人看视频| 成人在线中文字幕| 91香蕉嫩草影院入口| 欧美洲成人男女午夜视频| 国产日本欧美一区二区三区在线| 国产精品直播网红| 91精品国产91久久久久久不卡| 国产香蕉97碰碰久久人人| 亚洲人免费视频| 亚洲精品一二区| 在线看片第一页欧美| 成人国产亚洲精品a区天堂华泰| 国产精品一区二区av影院萌芽| 精品日韩中文字幕| 91精品国产高清久久久久久| 亚洲缚视频在线观看| 国产精品夜色7777狼人| 97免费在线视频| 久久久国产一区二区| 国产精品扒开腿做| 久久综合久久八八| 欧美亚洲国产日韩2020| 欧美高跟鞋交xxxxxhd| 波霸ol色综合久久| 日韩电影免费观看在线观看| 国产视频久久久久| 中文字幕亚洲二区| 国外成人在线视频| 国产a∨精品一区二区三区不卡| 欧美视频裸体精品| 亚洲男人天堂九九视频| 国产成人自拍视频在线观看| 欧美午夜片在线免费观看| 亚洲人成网站777色婷婷| 欧美在线免费看| 欧美日韩性生活视频| 色偷偷av一区二区三区乱| www.午夜精品| 精品自拍视频在线观看| 国产精品久久久久久亚洲调教| 国产精品午夜一区二区欲梦| 国产精品美女久久久久久免费| 久久婷婷国产麻豆91天堂| 自拍偷拍亚洲区| 精品福利在线观看| 日韩精品一二三四区| 精品国产乱码久久久久久天美| 亚洲精品成人网| 欧美精品久久久久久久免费观看| 两个人的视频www国产精品| 欧美第一页在线| 国产精品久久久久久久久久三级| 亚洲v日韩v综合v精品v| 日本一欧美一欧美一亚洲视频| 日韩在线免费观看视频| 久久深夜福利免费观看| 久久影视电视剧免费网站清宫辞电视| 色偷偷av亚洲男人的天堂| 国产精品video| 久久偷看各类女兵18女厕嘘嘘| 欧美日韩免费一区| 亚洲最大在线视频| 综合网中文字幕| 亚洲社区在线观看| 国产91在线播放精品91| 欧美性生交xxxxxdddd| 日韩在线视频观看| 久久久久久久久久久网站| 亚洲国产成人91精品| 欧美亚洲成人免费| 欧美放荡办公室videos4k| 日本国产欧美一区二区三区| 97国产一区二区精品久久呦| 少妇高潮久久77777| 91精品国产高清久久久久久| 成人激情视频在线| 亚洲精品美女在线观看播放| 91av视频在线免费观看| 久久久久久久色| 欧美日韩激情小视频| 久久精品一本久久99精品| 日韩亚洲第一页| 国内精品视频在线| 亚洲福利小视频| 亚洲免费电影在线观看| 亚洲理论片在线观看| 亚洲激情成人网| 国产精品国产三级国产专播精品人| 国产欧美最新羞羞视频在线观看| 亚洲国产欧美一区二区三区同亚洲| 午夜精品久久17c| 国产一区二区三区精品久久久| 亚洲香蕉在线观看| 国产精品揄拍一区二区| 亚洲午夜未满十八勿入免费观看全集| 国产精品久久av| 原创国产精品91| 亚洲第一区中文字幕| 中文字幕无线精品亚洲乱码一区| 欧美成人免费大片| 国产在线精品一区免费香蕉| 国产不卡av在线免费观看| 欧美大尺度激情区在线播放| 欧美午夜片欧美片在线观看| 欧美有码在线观看| 色哟哟亚洲精品一区二区| 91精品国产自产在线观看永久| 成人妇女免费播放久久久| 久久久天堂国产精品女人| 欧美成人免费在线视频| 欧美专区在线观看| 国产精品视频白浆免费视频| 亚洲最大福利网站| 国产精品久久久久久久一区探花| 亚洲精品女av网站| 亚洲综合大片69999| 91精品国产91久久久久久| 九九九久久国产免费| 欧美性猛交xxxx久久久| 911国产网站尤物在线观看| 81精品国产乱码久久久久久| 欧美中文在线视频| 亚洲男人的天堂在线播放| 伊人久久综合97精品| 欧美多人爱爱视频网站| 久久久久久com| 色先锋久久影院av| 成人福利在线观看| 国产精品毛片a∨一区二区三区|国| 亚州av一区二区| 日韩成人av一区| 国产精品久久国产精品99gif| 久久久精品国产网站| 亚洲最新视频在线| 97久久精品在线| 日本三级韩国三级久久| 77777亚洲午夜久久多人| 国外成人免费在线播放| 国产精品自产拍在线观看中文| 精品偷拍一区二区三区在线看| 九色成人免费视频| 日韩在线观看免费全集电视剧网站| 91九色蝌蚪国产| 国产午夜精品全部视频播放| 欧美wwwxxxx| 久久精品成人一区二区三区|