Spring Boot + Vue 基于 RSA 的用戶身份認證加密機制實現過程
Spring Boot + Vue 基于 RSA 的用戶身份認證加密機制實現
什么是RSA?
RSA算法是一種非對稱加密算法,與對稱加密算法不同的是,RSA算法有兩個不同的密鑰,一個是公鑰,一個是私鑰
RSA公開密鑰密碼體制是一種使用不同的加密密鑰與解密密鑰,“由已知加密密鑰推導出解密密鑰在計算上是不可行的”
密碼體制
在公開密鑰密碼體制中,加密密鑰(即公開密鑰)PK是公開信息,而解密密鑰(即秘密密鑰)SK是需要保密的。加密算法E和解密算法D也都是公開的。雖然解密密鑰SK是由公開密鑰PK決定的,但卻不能根據PK計算出SK
正是基于這種理論,1978年出現了著名的RSA算法,它通常是先生成一對RSA密鑰,其中之一是保密密鑰,由用戶保存;另一個為公開密鑰,可對外公開,甚至可在網絡服務器中注冊。為提高保密強度,RSA密鑰至少為500位長。這就使加密的計算量很大。為減少計算量,在傳送信息時,常采用傳統加密方法與公開密鑰加密方法相結合的方式,即信息采用改進的DES或IDEA對話密鑰加密,然后使用RSA密鑰加密對話密鑰和信息摘要。對方收到信息后,用不同的密鑰解密并可核對信息摘要
安全需求介紹
背景:在安全掃描過程中,系統被檢測到存在中危漏洞,影響了用戶登錄環(huán)節(jié)的信息安全性
漏洞描述
Web程序在處理用戶登錄過程中,針對用戶名和口令在傳輸前未采用加密。用戶名和口令一旦被惡意攻擊者嗅探或暴力破解得到后,可以直接利用它去登錄系統。
解決方案:建議對用戶名、口令等參數值采用強加密算法,如SHA512、RSA、AES、國密算法等,避免使用MD5、Base64、DES、3DES等弱算法。
問題分析:未加密的敏感信息在傳輸過程中易被攔截,尤其是在公共網絡環(huán)境下。這使得系統的認證機制成為攻擊目標,存在較高的安全隱患
需求實現:
- 在前端使用安全加密算法對用戶名和密碼進行加密,防止信息裸露傳輸
- 后端解密用戶信息并進行驗證,同時保障傳輸數據的完整性與安全性
前后端交互流程
基于RSA加密的登錄流程,Web端和服務端的交互過程詳細步驟:
- 用戶發(fā)起登錄請求:
- 用戶在Web端輸入登錄操作,Web端開始處理登錄流程
- Web端向服務端發(fā)送一個請求,要求獲取RSA加密所需的公鑰
- 服務端返回公鑰:
- 服務端接收到公鑰請求后,從系統中讀取公鑰信息,并將公鑰發(fā)送回Web端。這個步驟的響應無需校驗
- Web端加密用戶憑據:
- Web端使用獲取到的公鑰,對用戶的用戶名和密碼進行加密。加密后的數據用于安全傳輸,避免敏感信息在網絡中被截獲
- Web端將加密后的用戶名和密碼通過HTTPS協議發(fā)送給服務端。HTTPS協議提供了額外的安全層,防止中間人攻擊
- 服務端解密并驗證:
- 服務端接收到加密的數據后,使用私鑰對加密內容進行解密。私鑰是嚴格保密的,只在服務端保存和使用服務端對解密后的用戶名和密碼進行驗證,檢查憑據是否正確并符合登錄要求
- 返回登錄結果:
- 服務端驗證完成后,將登錄驗證的結果返回給Web端。結果可以是登錄成功或失敗的信息
- Web端處理響應:
- Web端接收并處理服務端返回的登錄結果,并顯示相應的提示或進行后續(xù)操作
前端使用 RSA 加密密碼
在前端 Vue.js 中,使用 jsencrypt
庫對用戶名密碼進行加密,并將加密后的用戶名密碼發(fā)送給后端
安裝 jsencrypt庫
在Vue.js 項目中運行以下命令來安裝 jsencrypt
:
npm install jsencrypt --save
實現敏感信息加密
在 Vue.js 登錄頁面中,對敏感信息進行加密,然后發(fā)送給后端:
// 引入 jsencrypt 和 Base64 編碼庫 import JSEncrypt from 'jsencrypt'; // 需要安裝 js-base64 庫 import { Base64 } from 'js-base64'; export default { data() { return { username: '', // 用戶輸入的用戶名 password: '' // 用戶輸入的密碼 }; }, methods: { /** * 使用 RSA 公鑰加密字符串 * @param {string} str - 需要加密的字符串 * @returns {string|null} - 加密后的字符串,若失敗返回 null */ encryptString(str) { // 初始化 JSEncrypt const encrypt = new JSEncrypt(); // 設置公鑰 const publicKey = ` -----BEGIN PUBLIC KEY----- ...公鑰內容... -----END PUBLIC KEY----- `; encrypt.setPublicKey(publicKey); // 加密字符串并返回加密結果 return encrypt.encrypt(str); }, /** * 用戶登錄邏輯 */ login() { // 獲取用戶輸入的用戶名和密碼 const username = this.username.trim(); // 去除多余空格 const password = this.password.trim(); // 驗證用戶名和密碼是否為空 if (!username || !password) { this.$message.error('用戶名或密碼不能為空'); // 提示用戶 return; } // 加密用戶名和密碼 const encryptedUsername = this.encryptString(username); const encryptedPassword = this.encryptString(password); // 驗證加密是否成功 if (!encryptedUsername || !encryptedPassword) { this.$message.error('加密失敗,請檢查公鑰配置'); return; } // Base64 編碼的主要作用是將加密后的數據轉換成由可見 ASCII 字符組成的字符串,以便在網絡傳輸或存儲時避免因特殊字符引發(fā)的兼容性問題 const base64EncodedUsername = Base64.encode(encryptedUsername); const base64EncodedPassword = Base64.encode(encryptedPassword); // 發(fā)送登錄請求到后端 this.$axios.post('/api/login', { username: base64EncodedUsername, // 加密后的用戶名 password: base64EncodedPassword // 加密后的密碼 }).then(response => { // 登錄成功后的處理邏輯 if (response.data.success) { this.$message.success('登錄成功'); // 跳轉到主頁面或其他邏輯 } else { this.$message.error(response.data.message || '登錄失敗'); } }).catch(error => { // 請求失敗的處理邏輯 console.error('登錄請求失敗:', error); this.$message.error('登錄失敗,請稍后重試'); }); } } };
服務器端生成RSA的公私鑰文件
Windows環(huán)境 生成rsa的公私鑰文件
安裝 OpenSSL:下載并安裝 OpenSSL for Windows,可以從 OpenSSL 官網 下載適合的版本。
生成 RSA 私鑰:
- 在安裝目錄的bin目錄下面,打開命令提示符(
cmd
) - 運行以下命令生成一個2048位的私鑰文件
private_key.pem
:
openssl genpkey -algorithm RSA -out private_key.pem -pkeyopt rsa_keygen_bits:2048
- 生成 RSA 公鑰:
- 使用生成的私鑰來提取公鑰,運行以下命令:
openssl rsa -pubout -in private_key.pem -out public_key.pem
?
Linux環(huán)境 生成rsa的公私鑰文件
使用RSA算法生成pem格式的私鑰文件,指定密鑰長度2048
openssl genpkey -algorithm RSA -out private_key.pem -pkeyopt rsa_keygen_bits:2048
使用RSA算法在上述私鑰文件基礎上生成pem格式的公鑰文件
openssl rsa -pubout -in private_key.pem -out public_key.pem
執(zhí)行完成后,會看到輸出兩份文件 private_key.pem, public_key.pem。
后端代碼實現
返回給前端的公鑰接口
將生成的兩份密鑰文件放入指定的目錄中,然后在配置文件中配置公私鑰文件所屬路徑
/** * 獲取公鑰 */ @GetMapping("/getPublicKey") public AjaxResult getPublicKey() { // 加載資源 File file = new File("公鑰的文件所屬路徑"); if (!file.exists()) { throw new BusinessException("未獲取到指定公鑰文件"); } String publicKey; try (InputStream inputStream = Files.newInputStream(file.toPath())) { publicKey = IOUtils.toString(inputStream, StandardCharsets.UTF_8); } catch (IOException e) { log.error("讀取公鑰文件失敗", e); // 返回錯誤信息 return AjaxResultGenerator.error("讀取公鑰文件失敗"); } // 檢查 publicKey 是否為 null 或空字符串 if (publicKey == null || publicKey.isEmpty()) { return AjaxResultGenerator.error("公鑰內容為空"); } // 刪除PEM格式的頭部和尾部以及所有空格、換行符 publicKey = publicKey.replace("-----BEGIN PUBLIC KEY-----", "") .replace("-----END PUBLIC KEY-----", "") .replaceAll("\\s+", ""); return AjaxResultGenerator.success(publicKey); }
解密前端傳入的加密字符串
前端的賬戶和密碼進行rsa加密并且base64編碼后,調用正常登錄接口login()
,readPrivateKeyAndDecode()
方法將 RSA 加密并 Base64 編碼的字符串解碼后,再用 RSA 私鑰對解碼后的數據進行解密,最終返回解密后的原始數據
pom.xml
<dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.8.26</version> </dependency>
登錄和解密方法
/** * 用戶名密碼登錄 * * @param loginBody 登錄信息 * @return 結果 */ @PostMapping("/v1/login") public AjaxResult login(@RequestBody LoginBody loginBody) { // 使用 RSA 私鑰解密 String username = readPrivateKeyAndDecode(loginBody.getUsername()); String password = readPrivateKeyAndDecode(loginBody.getPassword()); loginBody.setUsername(username); loginBody.setPassword(password); // 執(zhí)行正常的登錄邏輯... return AjaxResultGenerator.success(); } /** * 讀取私鑰并解密 * * @param rsaEncoded64Str 已rsa加密并且base64編碼后的字符串 * @return */ public String readPrivateKeyAndDecode(String rsaEncoded64Str) { // 加載資源 File file= new File("私鑰的文件所屬路徑"); if (!file.exists()) { throw new BusinessException("未獲取到指定私鑰文件"); } String privateKey; try (InputStream inputStream = Files.newInputStream(file.toPath())) { privateKey = IOUtils.toString(inputStream, StandardCharsets.UTF_8); } catch (IOException e) { log.error("讀取私鑰文件失敗", e); throw new BusinessException("讀取私鑰文件失敗:" + e.getMessage()); } if (StringUtils.isBlank(privateKey)) { throw new BusinessException("私鑰內容為空"); } // 刪除PEM格式的頭部和尾部以及所有空格、換行符 privateKey = privateKey.replace("-----BEGIN PRIVATE KEY-----", "") .replace("-----END PRIVATE KEY-----", "") .replaceAll("\\s+", ""); // 進行base64解密 String decodedUsername = new String(Base64.getDecoder().decode(rsaEncoded64Str)); // 使用 RSA 私鑰解密,用到了hutool-all中的類 return new RSA(privateKey, null) .decryptStr(decodedUsername, KeyType.PrivateKey); }
實現效果
到此這篇關于Spring Boot + Vue 基于 RSA 的用戶身份認證加密機制實現的文章就介紹到這了,更多相關Spring Boot Vue 身份認證加密內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
hibernate通過session實現增刪改查操作實例解析
這篇文章主要介紹了hibernate通過session實現增刪改查操作實例解析,具有一定借鑒價值,需要的朋友可以參考下。2017-12-12Spring boot 在idea中添加熱部署插件的圖文教程
這篇文章主要介紹了Spring boot 在idea中添加熱部署插件的圖文教程,本文通過圖文并茂的形式給大家展示具體步驟,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-10-10springboot 整合fluent mybatis的過程,看這篇夠了
這篇文章主要介紹了springboot 整合fluent mybatis的過程,配置數據庫連接創(chuàng)建數據庫的詳細代碼,本文給大家介紹的非常詳細,需要的朋友可以參考下2021-08-08詳解SpringMVC加載配置Properties文件的幾種方式
這篇文章主要介紹了詳解SpringMVC加載配置Properties文件的幾種方式,具有一定的參考價值,感興趣的小伙伴們可以參考一下。2017-02-02