📜  使用注解隐藏表单域 | Java小服务程序(1)

📅  最后修改于: 2023-12-03 15:22:25.234000             🧑  作者: Mango

使用注解隐藏表单域 | Java小服务程序

许多网站需要在表单中包含敏感信息,例如密码或信用卡号码。通常,开发人员使用JavaScript等客户端脚本来隐藏这些字段。但是,这种方法会暴露敏感数据并降低安全性。本文介绍使用注解来保护表单域中的敏感信息,同时提高网站的安全性。

方案介绍

使用隐藏表单域标准是,将敏感数据输入表单中的字段设置为 type="hidden",这样它就不会在提交时重新显示给用户。但是,这样仍然存在安全隐患,因为Post提交数据可以很容易被人攻击截获。而使用注解可以将表单字段加密或编码,并在服务端处理后,将其还原回原始的敏感信息。

常见的实现方案有:

  • 将信息存储在DB中,并在加密/解密时调用数据库记录
  • 在内存中加密并在使用时进行解密
  • 使用对称加密算法,例如AES

在此,我们采用在内存中加密,通过对Cipher对象进行初始化和构造,将加密、解密和编码、解码容易地实现。

代码实现
1. 导入必要库和定义注解
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Hidden {
}
2. 定义加密和解密函数
public static String encrypt(String strToEncrypt, String secret) {
    try {
        //Create new instance of Cipher object
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5PADDING");
        byte[] keyBytes = secret.getBytes();
        SecretKeySpec secretKey = new SecretKeySpec(keyBytes, "AES");
        cipher.init(Cipher.ENCRYPT_MODE, secretKey);

        return Base64.getEncoder().encodeToString(cipher.doFinal(strToEncrypt.getBytes()));
    } catch (Exception e) {
        System.out.println("Error while encrypting: " + e.toString());
    }
    return null;
}

public static String decrypt(String strToDecrypt, String secret) {
    try {
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5PADDING");
        byte[] keyBytes = secret.getBytes();
        SecretKeySpec secretKey = new SecretKeySpec(keyBytes, "AES");
        cipher.init(Cipher.DECRYPT_MODE, secretKey);

        return new String(cipher.doFinal(Base64.getDecoder().decode(strToDecrypt)));
    } catch (Exception e) {
        System.out.println("Error while decrypting: " + e.toString());
    }
    return null;
}
3. 实现隐藏表单域注解
import java.lang.reflect.Field;
import java.util.Base64;

public class HiddenFieldProcessor {

    private static String secretKey = "mysecretkey";

    public static String hideHiddenFields(Object obj) throws Exception {
        Class<?> objClass = obj.getClass();
        Field[] fields = objClass.getDeclaredFields();

        for (Field field : fields) {
            if (field.isAnnotationPresent(Hidden.class)) {
                field.setAccessible(true);
                String fieldValue = field.get(obj).toString();
                String encryptedFieldValue = encrypt(fieldValue, secretKey);
                field.set(obj, encryptedFieldValue);
            }
        }

        return obj.toString();
    }

    public static String revealHiddenFields(String objStr) throws Exception {
        Class<?> objClass = objStr.getClass();
        Object obj = objClass.newInstance();

        Field[] fields = objClass.getDeclaredFields();

        for (Field field : fields) {
            if (field.isAnnotationPresent(Hidden.class)) {
                field.setAccessible(true);
                String hiddenFieldValue = field.getName() + "=([^,]*)";
                String encryptedFieldValue = objStr.replaceAll(hiddenFieldValue, "$1");
                String decryptedFieldValue = decrypt(encryptedFieldValue, secretKey);
                field.set(obj, decryptedFieldValue);
            }
        }

        return obj.toString();
    }
}
4. 使用隐藏表单域注解

定义一个 POJO 类:

public class User {

    private String name;
    private String email;
    private String password;
    @Hidden
    private String ssn;

    // Getter and Setter methods
}

在控制器中对注解应用:

@PostMapping("/users")
public String addUser(@ModelAttribute User user, Model model) throws Exception {
    String encryptedUserData = HiddenFieldProcessor.hideHiddenFields(user);
    // Code for inserting encryptedUserData into database

    String decryptedUserData = HiddenFieldProcessor.revealHiddenFields(encryptedUserData);
    model.addAttribute("user", decryptedUserData);

    return "user-details";
}
结束语

使用注解隐藏表单域是一种保护敏感信息的安全措施。在本文中,我们介绍了使用注解作为一种方法,来保护表单间收集到的敏感信息。此方案在安全性和易用性上做到了一个良好的平衡点,是非常不错的实现方式。