1.1フロントエンドjs暗号化の概要
システムのセキュリティ要件は比較的高いため、データを送信するにはhttpsプロトコルを選択する必要があります。もちろん、多くの場合、一般的なWebサイトでは、セキュリティ要件がそれほど高くない場合は、httpプロトコルを使用できます。この場合、パスワードのプレーンテキスト送信は明らかに不適切です。送信中にリクエストが傍受された場合、プレーンテキストパスワードを使用してWebサイトに直接ログインできるためです。
HTTPS(443)は、SSL(Secure Sockets Layer)プロトコルをHTTP(80)に追加します。SSLは、証明書に依存してサーバーのIDを検証し、ブラウザーとサーバー間の通信を暗号化します。送信する前に、公開鍵を使用して暗号化し、サーバー側は秘密鍵を使用して復号化します。
httpプロトコルを使用するWebフロントエンドの暗号化では、紳士を防ぐことはできますが、悪役を防ぐことはできません。フロントエンドは、暗号化アルゴリズムを含めて完全に公開されています。
暗号化アルゴリズムを知っていると、パスワードが解読される可能性があります。それは時間の問題です。知乎の記事をご覧ください:ドラッグライブラリとの戦い
したがって、暗号化はクラッキングの時間コストを増加させることです。クラッキングに必要な時間が許容できない場合、これは目標を達成します。
データベースに保存されているパスワードの安全性を高めるには、暗号化されたストレージのバックエンドでさまざまな一方向(非対称)暗号化方式を組み合わせる必要があります。
フロントエンド暗号化バックエンドは復号化する必要があるため、対称暗号化アルゴリズムが必要です。つまり、フロントエンドはencrypted = crypto(password + key)を使用し、バックエンドはpassword = decode(encrypted +キー)。フロントエンドはパスワードのみと鍵で暗号化された暗号化された文字列を送信します。このように、要求が傍受された場合でも、暗号化アルゴリズムが知られているが、原因の不足のために平文パスワードをクラックするのは難しいですがキー。したがって、このキーは非常に重要です。また、このキーはバックエンドコントロールによって生成および破棄され、使い切ると無効になるため、暗号化されたパスワードを使用してシミュレートされたログインリクエストを送信できても、キーの有効期限が切れている場合は、バックエンド検証できません。
ローカル環境が本質的に安全でなく、キーがわかっている場合、パスワードは復号化アルゴリズムによって瞬時に解読される可能性があることに注意してください。ここでは、送信中に状況が傍受されたと想定しています。したがって、フロントエンドの暗号化では悪役を防ぐことはできません。本当に防止したい場合は、暗号化アルゴリズムのjsファイルを圧縮して暗号化し、メソッドを絶えず更新してjsファイルを取得しにくくし、ハッカーが暗号化アルゴリズムを取得しにくくすることができます。これは、倒錯したグーグルがそれを行う方法です。それはそれ自体でjs仮想マシンを実装し、暗号化され難読化されたjsファイルを絶えず更新することによって暗号化アルゴリズムを取得することを困難にします。このように、ハッカーは暗号化アルゴリズムを知らずにクラックすることはできません。
ここで、キーは、ページがロードされて非表示フィールドに保存されたときにサーバーによって生成されます。
1.2.3 Java側の暗号化と復号化(PKCS5PaddingはjsのPkcs7と一致しています)
package com.jykj.demo.util;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;
import sun.misc.BASE64Decoder;
public class EncryptUtil {
private static final String KEY = "abcdefgabcdefg12";
private static final String ALGORITHMSTR = "AES/ECB/PKCS5Padding";
public static String base64Encode(byte[] bytes){
return Base64.encodeBase64String(bytes);
}
public static byte[] base64Decode(String base64Code) throws Exception{
return new BASE64Decoder().decodeBuffer(base64Code);
}
public static byte[] aesEncryptToBytes(String content, String encryptKey) throws Exception {
KeyGenerator kgen = KeyGenerator.getInstance("AES");
kgen.init(128);
Cipher cipher = Cipher.getInstance(ALGORITHMSTR);
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(encryptKey.getBytes(), "AES"));
return cipher.doFinal(content.getBytes("utf-8"));
}
public static String aesEncrypt(String content, String encryptKey) throws Exception {
return base64Encode(aesEncryptToBytes(content, encryptKey));
}
public static String aesDecryptByBytes(byte[] encryptBytes, String decryptKey) throws Exception {
KeyGenerator kgen = KeyGenerator.getInstance("AES");
kgen.init(128);
Cipher cipher = Cipher.getInstance(ALGORITHMSTR);
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(decryptKey.getBytes(), "AES"));
byte[] decryptBytes = cipher.doFinal(encryptBytes);
return new String(decryptBytes);
}
public static String aesDecrypt(String encryptStr, String decryptKey) throws Exception {
return aesDecryptByBytes(base64Decode(encryptStr), decryptKey);
}
/**
* 测试
*
*/
public static void main(String[] args) throws Exception {
String content = "Test String么么哒"; //0gqIDaFNAAmwvv3tKsFOFf9P9m/6MWlmtB8SspgxqpWKYnELb/lXkyXm7P4sMf3e
System.out.println("加密前:" + content);
System.out.println("加密密钥和解密密钥:" + KEY);
String encrypt = aesEncrypt(content, KEY);
System.out.println(encrypt.length()+":加密后:" + encrypt);
String decrypt = aesDecrypt(encrypt, KEY);
System.out.println("解密后:" + decrypt);
}
}