美文网首页
开发规范—String类型保存敏感信息

开发规范—String类型保存敏感信息

作者: 东西汉 | 来源:发表于2021-01-06 20:40 被阅读0次

    问题简介

    内存中的敏感信息使用结束后如果不及时清理,会存在敏感信息泄露的风险,应尽量减小敏感信息在内 存中的生命周期,使用结束后立即清0。Java中的 String 是不可变对象(创建后无法更改),使用 String 保存口令、秘钥等敏感信息时,这些敏感信息会一直在内存中直至被垃圾收集器回收(其生命 周期不可控),如果进程的内存被dump,会导致敏感信息泄露风险。

    开发规范

    内存中的敏感信息不能依赖垃圾回收机制的清理,而是在使用结束后主动将内存中的信息清0。为了方 便内存的清理,推荐优先使用 char[] / byte[] 存储敏感信息。对于必须使用String进行数据处理的场 景(如web系统获取请求数据、数据需要转为json字符串进行传递、接口中预定义使用String传递参数 等),不需要将String转为char[]这样的无效处理,但要对所有涉及敏感信息的String中的信息进行清 理,不要遗漏,例如将一个含敏感信息的对象转为json串,使用结束后要将对象中敏感信息及json串全 部清0。String的清理可以通过反射、调用JNI接口等方式实现

    反例

    void doSomething() {
    String password = getPassword();
    verifyPassword(password);
    ...
    }
    boolean verifyPassword(String pwd) {
    ...
    }
    
    

    正例(建议使用数组存储敏感信息,方便清理)

    void doSomething() {
    char[] password = getPassword();
    verifyPassword(password);
    // 清除password
    Arrays.fill(password, (char) 0x00);
    }
    boolean verifyPassword(char[] pwd) {
    ...
    }
    
    

    正例(补救方案:三方件中的String清0)

    void doSomething() {
    ...
    String user = request.getParameter("username");
    String password = request.getParameter("pwd");
    verifyLoginInfo(user, password);
    // 清除password
    try {
    Field valueFieldOfString = String.class.getDeclaredField("value");
    valueFieldOfString.setAccessible(true);
    char[] value = (char[]) valueFieldOfString.get(password);
    Arrays.fill(value, (char) 0x00);
    ...
    }
    ...
    }
    

    通用方法Demo

        private static void erasureString(String sensitiveString) {
            try {
                Field valueFieldOfString = String.class.getDeclaredField("value");
                valueFieldOfString.setAccessible(true);
                char[] value = (char[]) valueFieldOfString.get(sensitiveString);
                Arrays.fill(value, (char) 0x00);
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
    
        private static <T> void erasureString(T model, Function<T, String> getSensitiveString) {
            try {
                Field valueFieldOfString = String.class.getDeclaredField("value");
                valueFieldOfString.setAccessible(true);
                char[] value = (char[]) valueFieldOfString.get(getSensitiveString.apply(model));
                Arrays.fill(value, (char) 0x00);
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
    
        private static <T> void erasureString(Collection<T> list, Function<T, String> getSensitiveString) {
            try {
                Field valueFieldOfString = String.class.getDeclaredField("value");
                valueFieldOfString.setAccessible(true);
                list.stream().forEach(model -> {
                    char[] value = new char[0];
                    try {
                        value = (char[]) valueFieldOfString.get(getSensitiveString.apply(model));
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    }
                    Arrays.fill(value, (char) 0x00);
                });
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
            }
        }
    

    实践结果

    相关文章

      网友评论

          本文标题:开发规范—String类型保存敏感信息

          本文链接:https://www.haomeiwen.com/subject/udmooktx.html