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

问题简介

内存中的敏感信息使用结束后如果不及时清理,会存在敏感信息泄露的风险,应尽量减小敏感信息在内 存中的生命周期,使用结束后立即清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();
        }
    }

实践结果

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 1.1 今天开始日清单 从今天开始,让日清单成为我们的左膀大家平时使用哪些事件管理工具呢?是待办事项清单,还是日程...
    faithalex阅读 550评论 0 0
  • 面试热点:老年人的“数字鸿沟” 【背景事件】 数字鸿沟指由不同性别、年龄、收入、阶层的人在接近、使用新信息技术的机...
    Anoxia_3748阅读 164评论 0 0
  • 2021-01-06 讲师训 Day 2 简书日更 51/100 日精进135天 开场,可以与伙伴互动,如果满分十...
    艳子的日记阅读 220评论 0 0
  • 久违的晴天,家长会。 家长大会开好到教室时,离放学已经没多少时间了。班主任说已经安排了三个家长分享经验。 放学铃声...
    飘雪儿5阅读 7,588评论 16 22
  • 今天感恩节哎,感谢一直在我身边的亲朋好友。感恩相遇!感恩不离不弃。 中午开了第一次的党会,身份的转变要...
    迷月闪星情阅读 10,620评论 0 11