前后端調(diào)用接口旅薄,防止他人竊取辅髓,用什么方式

在Java中,如果你希望保護(hù)接口調(diào)用時(shí)的參數(shù)不被輕易獲取少梁,你可以通過加密參數(shù)的方式來(lái)增加安全性洛口。以下是幾種常見的做法:

  • 對(duì)稱加密:
    使用像AES(Advanced Encryption Standard)這樣的對(duì)稱加密算法,可以對(duì)參數(shù)進(jìn)行加密凯沪〉谘妫客戶端和服務(wù)器共享同一個(gè)密鑰,發(fā)送時(shí)加密妨马,接收時(shí)解密挺举。
    示例代碼片段:
     import javax.crypto.Cipher;
     import javax.crypto.spec.SecretKeySpec;
     import java.util.Base64;

     // 加密
     byte[] encrypt(String key, String plainText) {
         SecretKeySpec secretKey = new SecretKeySpec(key.getBytes(), "AES");
         Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
         cipher.init(Cipher.ENCRYPT_MODE, secretKey);
         return Base64.getEncoder().encode(cipher.doFinal(plainText.getBytes()));
     }

     // 解密
     String decrypt(String key, byte[] encryptedBytes) {
         SecretKeySpec secretKey = new SecretKeySpec(key.getBytes(), "AES");
         Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
         cipher.init(Cipher.DECRYPT_MODE, secretKey);
         return new String(cipher.doFinal(Base64.getDecoder().decode(encryptedBytes)));
     }
  • 非對(duì)稱加密:
    RSA或DSA等非對(duì)稱加密算法,使用一對(duì)公鑰和私鑰烘跺∠孀荩客戶端使用服務(wù)器的公鑰加密參數(shù),服務(wù)器使用私鑰解密滤淳。
    這種方法更適合在不安全的網(wǎng)絡(luò)環(huán)境中梧喷,因?yàn)榧词构€被截獲,也無(wú)法解密數(shù)據(jù),因?yàn)橹挥兴借€才能解密铺敌。
    在Java中汇歹,常用的非對(duì)稱加密算法主要是RSA和ECC。以下是使用這兩種算法的基本步驟:
    RSA(Rivest-Shamir-Adleman)
    導(dǎo)入必要的庫(kù):
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.RSAPublicKeySpec;
import java.security.spec.RSAPrivateKeySpec;
import javax.crypto.Cipher;
import java.io.*;

生成公鑰和私鑰:

KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize(2048); // 指定密鑰長(zhǎng)度偿凭,例如2048位
KeyPair keyPair = keyGen.generateKeyPair();
PublicKey publicKey = keyPair.getPublic();
PrivateKey privateKey = keyPair.getPrivate();

加密數(shù)據(jù):

Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); // 選擇填充模式
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] encryptedData = cipher.doFinal(data.getBytes()); // data是待加密的字符串

解密數(shù)據(jù):

cipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] decryptedData = cipher.doFinal(encryptedData);
String originalData = new String(decryptedData);

ECC(Elliptic Curve Cryptography)
導(dǎo)入必要的庫(kù)(可能需要Bouncy Castle庫(kù)产弹,因?yàn)樗贘ava標(biāo)準(zhǔn)庫(kù)中不是默認(rèn)支持的):

import org.bouncycastle.jce.provider.BouncyCastleProvider;
import java.security.Security;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.ECGenParameterSpec;
import javax.crypto.Cipher;
import java.io.*;

添加Bouncy Castle Provider:

if (Security.getProvider("BC") == null) {
    Security.addProvider(new BouncyCastleProvider());
}

生成公鑰和私鑰:

KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC", "BC");
keyGen.initialize(new ECGenParameterSpec("secp256r1")); // 選擇橢圓曲線
KeyPair keyPair = keyGen.generateKeyPair();
PublicKey publicKey = keyPair.getPublic();
PrivateKey privateKey = keyPair.getPrivate();

加密數(shù)據(jù):

Cipher cipher = Cipher.getInstance("ECIES", "BC"); // 選擇合適的橢圓曲線加密算法
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] encryptedData = cipher.doFinal(data.getBytes());

解密數(shù)據(jù):

cipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] decryptedData = cipher.doFinal(encryptedData);
String originalData = new String(decryptedData);

請(qǐng)注意,實(shí)際應(yīng)用中還需要考慮密鑰的存儲(chǔ)笔喉、傳輸和生命周期管理等問題取视,以及可能需要處理的異常。同時(shí)常挚,非對(duì)稱加密通常用于建立對(duì)稱加密的密鑰作谭,因?yàn)榉菍?duì)稱加密速度較慢,不適合大量數(shù)據(jù)的加密

  • 數(shù)字簽名:
    使用哈希函數(shù)(如SHA-1或SHA-256)和私鑰創(chuàng)建簽名奄毡,然后將簽名與原始參數(shù)一起發(fā)送折欠。服務(wù)器使用公鑰驗(yàn)證簽名的有效性,確保數(shù)據(jù)未被篡改吼过。
    在Java中锐秦,使用鹽(Salt)加密密碼的常見步驟如下,這里以BCrypt強(qiáng)散列函數(shù)為例盗忱,因?yàn)樗菍iT為密碼存儲(chǔ)設(shè)計(jì)的酱床,提供了自動(dòng)鹽值生成和較強(qiáng)的加密強(qiáng)度。BCrypt是由OpenBSD團(tuán)隊(duì)開發(fā)的一種加密算法趟佃,現(xiàn)在廣泛應(yīng)用于Web應(yīng)用程序中扇谣。
    使用BCrypt進(jìn)行加鹽加密
    首先,你需要添加BCrypt庫(kù)到你的項(xiàng)目中闲昭。如果你使用Maven罐寨,可以在pom.xml文件中添加依賴:
<dependency>
    <groupId>org.mindrot</groupId>
    <artifactId>jbcrypt</artifactId>
    <version>0.4</version>
</dependency>

接下來(lái),使用BCrypt進(jìn)行加鹽加密的示例代碼:

import org.mindrot.jbcrypt.BCrypt;

public class PasswordEncryptionExample {

    // 生成一個(gè)加密后的密碼(自動(dòng)包含鹽值)
    public static String encryptPassword(String plainTextPassword) {
        return BCrypt.hashpw(plainTextPassword, BCrypt.gensalt());
    }

    // 驗(yàn)證密碼
    public static boolean verifyPassword(String plainTextPassword, String storedHash) {
        return BCrypt.checkpw(plainTextPassword, storedHash);
    }

    public static void main(String[] args) {
        String passwordToEncrypt = "mySecurePassword";
        
        // 加密密碼
        String hashedPassword = encryptPassword(passwordToEncrypt);
        System.out.println("Encrypted Password: " + hashedPassword);
        
        // 模擬驗(yàn)證密碼
        boolean isMatch = verifyPassword(passwordToEncrypt, hashedPassword);
        System.out.println("Does the password match? " + isMatch);
    }
}

使用其他哈希函數(shù)手動(dòng)加鹽
如果不使用BCrypt序矩,而是使用如SHA-256等哈希函數(shù)手動(dòng)加鹽鸯绿,步驟如下:
生成鹽值:通常使用一個(gè)安全的隨機(jī)數(shù)生成器(如SecureRandom)來(lái)生成一個(gè)隨機(jī)的鹽值。
拼接密碼和鹽值:將原始密碼字符串與鹽值拼接簸淀。
哈希拼接后的字符串:使用哈希函數(shù)(如SHA-256)對(duì)拼接后的字符串進(jìn)行哈希瓶蝴。
存儲(chǔ)鹽值和哈希值:將鹽值和哈希后的值一并存儲(chǔ)在數(shù)據(jù)庫(kù)中。
示例代碼(使用SHA-256和手動(dòng)鹽值):使用其他哈希函數(shù)手動(dòng)加鹽
如果不使用BCrypt租幕,而是使用如SHA-256等哈希函數(shù)手動(dòng)加鹽舷手,步驟如下:
生成鹽值:通常使用一個(gè)安全的隨機(jī)數(shù)生成器(如SecureRandom)來(lái)生成一個(gè)隨機(jī)的鹽值。
拼接密碼和鹽值:將原始密碼字符串與鹽值拼接令蛉。
哈希拼接后的字符串:使用哈希函數(shù)(如SHA-256)對(duì)拼接后的字符串進(jìn)行哈希。
存儲(chǔ)鹽值和哈希值:將鹽值和哈希后的值一并存儲(chǔ)在數(shù)據(jù)庫(kù)中。
示例代碼(使用SHA-256和手動(dòng)鹽值):

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;

public class SHA256WithSaltExample {

    public static void main(String[] args) throws NoSuchAlgorithmException {
        String password = "mySecurePassword";
        SecureRandom random = new SecureRandom();
        byte[] salt = new byte[16]; // 16 bytes salt
        random.nextBytes(salt); // Generate a random salt
        
        String hashed = hashWithSalt(password, salt);
        System.out.println("Hashed Password: " + hashed);
        // 實(shí)際應(yīng)用中珠叔,應(yīng)將salt和hashedPassword一起存儲(chǔ)
    }
    
    public static String hashWithSalt(String password, byte[] salt) throws NoSuchAlgorithmException {
        MessageDigest md = MessageDigest.getInstance("SHA-256");
        md.update(salt);
        byte[] hashedPassword = md.digest(password.getBytes());
        // 可選:進(jìn)一步處理hash蝎宇,如Base64編碼,使其可打印和存儲(chǔ)
        return bytesToHex(hashedPassword);
    }
    
    private static String bytesToHex(byte[] bytes) {
        StringBuilder result = new StringBuilder();
        for (byte b : bytes) {
            result.append(String.format("%02x", b));
        }
        return result.toString();
    }
}

請(qǐng)注意祷安,手動(dòng)管理鹽和哈希過程雖然提供了靈活性姥芥,但也增加了實(shí)現(xiàn)錯(cuò)誤的風(fēng)險(xiǎn)。因此汇鞭,推薦使用成熟的庫(kù)和算法凉唐,如BCrypt,它們已經(jīng)考慮到了安全性最佳實(shí)踐霍骄。

  • HTTPS/TLS:
    在網(wǎng)絡(luò)層使用HTTPS(HTTP over TLS/SSL)協(xié)議台囱,可以對(duì)整個(gè)HTTP請(qǐng)求進(jìn)行加密,包括URL读整、頭信息和正文簿训,防止中間人攻擊。
  • 使用框架集成:
    如果你在Spring框架中工作米间,可以利用Spring Security來(lái)實(shí)現(xiàn)加密和解密强品,包括自定義攔截器來(lái)處理加密邏輯。
    Spring Security 提供了內(nèi)置的密碼編碼器來(lái)處理密碼的加密和驗(yàn)證屈糊,其中最常用的是 BCryptPasswordEncoder的榛。下面是如何使用 Spring Security 的 BCryptPasswordEncoder 來(lái)處理密碼的加密和解密(實(shí)際上在密碼驗(yàn)證場(chǎng)景中,我們并不需要解密逻锐,而是對(duì)比加密后的密碼):
    1.密碼加密: 添加 BCryptPasswordEncoder 到你的 Spring Boot 應(yīng)用中夫晌,并使用它來(lái)加密密碼。以下是一個(gè)簡(jiǎn)單的例子:
   import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

   @Configuration
   public class SecurityConfig {

       @Bean
       public BCryptPasswordEncoder passwordEncoder() {
           return new BCryptPasswordEncoder();
       }
   }

在用戶注冊(cè)或密碼修改時(shí)谦去,你可以使用這個(gè)密碼編碼器來(lái)加密密碼:

   @Autowired
   private BCryptPasswordEncoder bCryptPasswordEncoder;

   public String encodePassword(String plainPassword) {
       return bCryptPasswordEncoder.encode(plainPassword);
   }

2.密碼驗(yàn)證: 當(dāng)用戶嘗試登錄時(shí)慷丽,Spring Security 會(huì)自動(dòng)處理密碼的驗(yàn)證。你需要確保在 UserDetailsService 實(shí)現(xiàn)中使用了正確的加密密碼:

   @Service
   public class CustomUserDetailsService implements UserDetailsService {

       @Autowired
       private UserRepository userRepository;

       @Override
       public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
           User user = userRepository.findByUsername(username)
                   .orElseThrow(() -> new UsernameNotFoundException("User not found"));

           return new User(user.getUsername(), user.getPassword(), user.getAuthorities());
       }
   }

在上述代碼中鳄哭,user.getPassword() 應(yīng)該返回的是數(shù)據(jù)庫(kù)中存儲(chǔ)的 BCrypt 加密后的密碼要糊。Spring Security 的 AuthenticationManager 將使用 BCryptPasswordEncoder 自動(dòng)驗(yàn)證用戶輸入的密碼與數(shù)據(jù)庫(kù)中存儲(chǔ)的密碼是否匹配。
3.配置 Spring Security: 在你的安全配置類中妆丘,設(shè)置 BCryptPasswordEncoder 作為默認(rèn)的密碼編碼器:

   @Override
   protected void configure(AuthenticationManagerBuilder auth) throws Exception {
       auth.userDetailsService(customUserDetailsService())
               .passwordEncoder(passwordEncoder());
   }

其中锄俄,passwordEncoder() 是從 SecurityConfig 類中注入的 BCryptPasswordEncoder 實(shí)例。
請(qǐng)注意勺拣,密碼編碼器并不負(fù)責(zé)解密密碼奶赠,因?yàn)槊艽a是單向哈希,不可逆药有。在處理密碼時(shí)毅戈,我們通常只關(guān)心密碼的驗(yàn)證苹丸,即檢查用戶輸入的密碼與存儲(chǔ)的哈希值是否匹配。

  • Token-based認(rèn)證:
    使用JWT(JSON Web Tokens)或OAuth2等機(jī)制苇经,生成加密的令牌赘理,令牌中包含用戶信息和權(quán)限,而不是直接傳遞敏感參數(shù)扇单。
    參數(shù)混淆:
    除了加密商模,還可以通過參數(shù)混淆或者編碼轉(zhuǎn)換來(lái)增加破解的難度,但這種方式不如加密安全蜘澜。
    請(qǐng)根據(jù)你的具體需求和安全級(jí)別選擇合適的方法施流。通常,結(jié)合多種策略(比如HTTPS + 加密參數(shù))可以提供更好的安全性鄙信。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末瞪醋,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子扮碧,更是在濱河造成了極大的恐慌趟章,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,194評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件慎王,死亡現(xiàn)場(chǎng)離奇詭異蚓土,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)赖淤,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門蜀漆,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人咱旱,你說(shuō)我怎么就攤上這事确丢。” “怎么了吐限?”我有些...
    開封第一講書人閱讀 156,780評(píng)論 0 346
  • 文/不壞的土叔 我叫張陵鲜侥,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我诸典,道長(zhǎng)描函,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,388評(píng)論 1 283
  • 正文 為了忘掉前任狐粱,我火速辦了婚禮舀寓,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘肌蜻。我一直安慰自己互墓,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,430評(píng)論 5 384
  • 文/花漫 我一把揭開白布蒋搜。 她就那樣靜靜地躺著篡撵,像睡著了一般判莉。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上育谬,一...
    開封第一講書人閱讀 49,764評(píng)論 1 290
  • 那天骂租,我揣著相機(jī)與錄音,去河邊找鬼斑司。 笑死,一個(gè)胖子當(dāng)著我的面吹牛但汞,可吹牛的內(nèi)容都是我干的宿刮。 我是一名探鬼主播,決...
    沈念sama閱讀 38,907評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼私蕾,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼僵缺!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起踩叭,我...
    開封第一講書人閱讀 37,679評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤磕潮,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后容贝,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體自脯,經(jīng)...
    沈念sama閱讀 44,122評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,459評(píng)論 2 325
  • 正文 我和宋清朗相戀三年斤富,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了膏潮。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,605評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡满力,死狀恐怖焕参,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情油额,我是刑警寧澤叠纷,帶...
    沈念sama閱讀 34,270評(píng)論 4 329
  • 正文 年R本政府宣布,位于F島的核電站潦嘶,受9級(jí)特大地震影響涩嚣,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜衬以,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,867評(píng)論 3 312
  • 文/蒙蒙 一缓艳、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧看峻,春花似錦阶淘、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,734評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)坤塞。三九已至,卻和暖如春澈蚌,著一層夾襖步出監(jiān)牢的瞬間摹芙,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,961評(píng)論 1 265
  • 我被黑心中介騙來(lái)泰國(guó)打工宛瞄, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留浮禾,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,297評(píng)論 2 360
  • 正文 我出身青樓份汗,卻偏偏與公主長(zhǎng)得像盈电,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子杯活,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,472評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容