Java安全——提供者相关的体系架构

简介:

标签(空格分隔): Java 安全


[toc]


安全提供者

Java的安全软件特性,是通过安全软件包的概念透出的。换句话说,安全领域常见的鉴别、加密、签名等概念,在Java中的支持是通过安全软件包来实现的。Java对于安全软件包的定义其实是一组抽象接口。Sun作为Java的作者,提供了一组实现。而安全软件包是由安全提供者、算法和引擎组成的。引擎可以理解为一组操作,算法定义了操作如何执行,而安全提供者则负责实现这两个抽象概念。

比如说,消息摘要是一个引擎,它是程序员能执行的一个操作。消息摘要的思想与如何计算消息摘要没有关系,所有的消息摘要具备同样的特性,因此抽象出来的接口就是引擎。而实现消息摘要可以有MD5和SHA等算法,算法由具体类实现。而安全提供者就是二者的桥梁,用来管理引擎和算法。安全提供者的目的就是提供一个简单的机制,从而可以方便的改变或替换算法及其实现。因此,通过安全提供者,程序员只需要使用引擎的接口,而不需要关系具体哪个类实现了算法,算法由哪个安全提供者提供。

体系结构

Java安全软件包的体系结构可以总结为四个部分:

引擎

JVM提供引擎类,是Java核心API的一部分。

算法

针对每一种引擎,都会有一组算法实现。Java提供了一组默认的算法实现(由Sun提供),第三方的机构可以提供其他实现。

提供者

算法类是由提供者来管理的,提供者知道如何将算法与实现的具体类对应起来。

安全类

安全类保存提供者列表,可以通过安全类查看有哪些提供者,以及它们提供的算法支持有哪些。

安全提供者体系的一个流程如下:

业务类->引擎: 调用某个接口
引擎->安全类: 询问
安全类->提供者: 找到提供者
提供者->算法: 找到对应算法
算法->业务类:返回计算结果

以MessageDigest的getInstance()方法为例,发现其实是调用Security.getImpl()方法实现的,而内部又是通过

GetInstance.getInstance
                (type, getSpiClass(type), algorithm, params, provider).toArray();

这样的语句来做的。而这个GetInstance会返回一个Instance对象,其类声明如下:

public static final class Instance {
        public final Provider provider;
        public final Object impl;

        private Instance(Provider arg0, Object arg1) {
            this.provider = arg0;
            this.impl = arg1;
        }

        public Object[] toArray() {
            return new Object[] {this.impl, this.provider};
        }
    }

可见就是一个Provider和Object(具体算法)的封装。

提供者选择

JVM在启动时,会去$JREHOME/lib/security/java.security中注册提供者。以我个人电脑中的文件为例:

#
# List of providers and their preference orders (see above):
#
security.provider.1=sun.security.provider.Sun
security.provider.2=sun.security.rsa.SunRsaSign
security.provider.3=sun.security.ec.SunEC
security.provider.4=com.sun.net.ssl.internal.ssl.Provider
security.provider.5=com.sun.crypto.provider.SunJCE
security.provider.6=sun.security.jgss.SunProvider
security.provider.7=com.sun.security.sasl.Provider
security.provider.8=org.jcp.xml.dsig.internal.dom.XMLDSigRI
security.provider.9=sun.security.smartcardio.SunPCSC
security.provider.10=apple.security.AppleProvider

JVM启动时会将这些provider注册进去,其实就是Security
初始化时会读这个文件。开发自定义的安全提供者,需要将类放到系统类路径下。其实看看Provider类的代码,就知道Provider本质上是一个Properties文件,里面的kv存储着引擎名和具体算法类的实现。

可以通过下面的程序示例查看具体的提供者引擎和算法:

package com.taobao.cd.security;

import java.security.Provider;
import java.security.Security;
import java.util.Enumeration;

public class ProviderTest {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Provider[] providers = Security.getProviders();
        for (int i = 0; i < providers.length; i++) {
            System.out.println("" + (i + 1) + ":" + providers[i]);
            for (Enumeration e = providers[i].keys(); e.hasMoreElements();) {
                System.out.println("\t" + e.nextElement());
            }
        }
    }

}

其输出如下,(截取部分)

1:SUN version 1.8
    Alg.Alias.Signature.SHA1/DSA
    Alg.Alias.Signature.1.2.840.10040.4.3
    Alg.Alias.Signature.DSS
    SecureRandom.SHA1PRNG ImplementedIn
    KeyStore.JKS
    Alg.Alias.MessageDigest.SHA-1
    MessageDigest.SHA
    ...

引擎类的结构设计

值得一提的是引擎类的结构设计。如上所说,引擎类除了给业务开发人员提供接口,还有一个任务就是要为第三方提供者使用。引擎为提供者提供了一个接口——SPI(security provider interface)。

还是以MessageDigest为例(这是消息摘要引擎)。MessageDigest继承了MessageDigestSpi。MessageDigestSpi抽象类定义了消息摘要引擎要做的事情。MessageDigest内部持有一个Delegate委托类,MessageDigest的核心方法就是getInstance()获取类的实例,实现见下:

public static MessageDigest getInstance(String algorithm, String provider)
        throws NoSuchAlgorithmException, NoSuchProviderException
    {
        if (provider == null || provider.length() == 0)
            throw new IllegalArgumentException("missing provider");
        Object[] objs = Security.getImpl(algorithm, "MessageDigest", provider);
        if (objs[0] instanceof MessageDigest) {
            MessageDigest md = (MessageDigest)objs[0];
            md.provider = (Provider)objs[1];
            return md;
        } else {
            MessageDigest delegate =
                new Delegate((MessageDigestSpi)objs[0], algorithm);
            delegate.provider = (Provider)objs[1];
            return delegate;
        }
    }

通过Security.getImpl()反射获取到对应的provider和算法实现类,并通过类型判断和else委托逻辑保证返回一个MessageDigest实例。

再具体一点,以Sun security提供的MD5算法实现为例。虽然MD5并没有直接实现MessageDigestSpi,但MD5的父类DigestBase继承了MessageDigestSpi。所以实际上还是满足这个架构的设计。DigestBase做了消息摘要通用的实现,留了三个abstract接口:

 abstract void implCompress(byte[] arg0, int arg1);

    abstract void implDigest(byte[] arg0, int arg1);

    abstract void implReset();

这几个代码在MD5中具体实现:(截取部分)

void implDigest(byte[] arg0, int arg1) {
        long arg2 = this.bytesProcessed << 3;
        int arg4 = (int) this.bytesProcessed & 63;
        int arg5 = arg4 < 56 ? 56 - arg4 : 120 - arg4;
        this.engineUpdate(padding, 0, arg5);
        ByteArrayAccess.i2bLittle4((int) arg2, this.buffer, 56);
        ByteArrayAccess.i2bLittle4((int) (arg2 >>> 32), this.buffer, 60);
        this.implCompress(this.buffer, 0);
        ByteArrayAccess.i2bLittle(this.state, 0, arg0, arg1, 16);
    }

最后补充一个类图说明下类的结构:

%5bMessageDigestSpi%7bbg%3awheat%7d%5d%5

目录
相关文章
|
29天前
|
SQL 安全 Java
安全问题已经成为软件开发中不可忽视的重要议题。对于使用Java语言开发的应用程序来说,安全性更是至关重要
在当今网络环境下,Java应用的安全性至关重要。本文深入探讨了Java安全编程的最佳实践,包括代码审查、输入验证、输出编码、访问控制和加密技术等,帮助开发者构建安全可靠的应用。通过掌握相关技术和工具,开发者可以有效防范安全威胁,确保应用的安全性。
48 4
|
1月前
|
存储 安全 Java
系统安全架构的深度解析与实践:Java代码实现
【11月更文挑战第1天】系统安全架构是保护信息系统免受各种威胁和攻击的关键。作为系统架构师,设计一套完善的系统安全架构不仅需要对各种安全威胁有深入理解,还需要熟练掌握各种安全技术和工具。
109 10
|
13天前
|
SQL 安全 Java
Java 异常处理:筑牢程序稳定性的 “安全网”
本文深入探讨Java异常处理,涵盖异常的基础分类、处理机制及最佳实践。从`Error`与`Exception`的区分,到`try-catch-finally`和`throws`的运用,再到自定义异常的设计,全面解析如何有效管理程序中的异常情况,提升代码的健壮性和可维护性。通过实例代码,帮助开发者掌握异常处理技巧,确保程序稳定运行。
25 0
|
1月前
|
监控 安全 Cloud Native
云原生安全:Istio在微服务架构中的安全策略与实践
【10月更文挑战第26天】随着云计算的发展,云原生架构成为企业数字化转型的关键。微服务作为其核心组件,虽具备灵活性和可扩展性,但也带来安全挑战。Istio作为开源服务网格,通过双向TLS加密、细粒度访问控制和强大的审计监控功能,有效保障微服务间的通信安全,成为云原生安全的重要工具。
45 2
|
3月前
|
设计模式 Java 关系型数据库
【Java笔记+踩坑汇总】Java基础+JavaWeb+SSM+SpringBoot+SpringCloud+瑞吉外卖/谷粒商城/学成在线+设计模式+面试题汇总+性能调优/架构设计+源码解析
本文是“Java学习路线”专栏的导航文章,目标是为Java初学者和初中高级工程师提供一套完整的Java学习路线。
464 37
|
2月前
|
Kubernetes 安全 微服务
使用 Istio 缓解电信 5G IoT 微服务 Pod 架构的安全挑战
使用 Istio 缓解电信 5G IoT 微服务 Pod 架构的安全挑战
61 8
|
2月前
|
安全 Java 编译器
Java 泛型深入解析:类型安全与灵活性的平衡
Java 泛型通过参数化类型实现了代码重用和类型安全,提升了代码的可读性和灵活性。本文深入探讨了泛型的基本原理、常见用法及局限性,包括泛型类、方法和接口的使用,以及上界和下界通配符等高级特性。通过理解和运用这些技巧,开发者可以编写更健壮和通用的代码。
|
3月前
|
安全 Java API
java安全特性
java安全特性
29 8
|
3月前
|
设计模式 架构师 Java
Java开发工程师转架构师需要学习什么
Java开发工程师转型为架构师需掌握多项技能:精通Java及框架、数据库与分布式系统;熟悉设计模式与架构模式;积累项目经验;提升沟通与领导力;持续学习新技术;培养系统设计与抽象能力;了解中间件及开发工具;并注重个人特质与职业发展。具体路径应结合个人目标与实际情况制定。
73 18
|
3月前
|
Kubernetes Java Android开发
用 Quarkus 框架优化 Java 微服务架构的设计与实现
Quarkus 是专为 GraalVM 和 OpenJDK HotSpot 设计的 Kubernetes Native Java 框架,提供快速启动、低内存占用及高效开发体验,显著优化了 Java 在微服务架构中的表现。它采用提前编译和懒加载技术实现毫秒级启动,通过优化类加载机制降低内存消耗,并支持多种技术和框架集成,如 Kubernetes、Docker 及 Eclipse MicroProfile,助力开发者轻松构建强大微服务应用。例如,在电商场景中,可利用 Quarkus 快速搭建商品管理和订单管理等微服务,提升系统响应速度与稳定性。
88 5