[Java] SSL 证书使用

SSL 证书创建

Springboot

适用于 jar 直接运行

单向

  • yml
mydefine:
  port: 8081
server:
  port: 8011
  ssl:
    enabled: true
    key-store: classpath:certificate/server.p12 # src/main/resources/certificate/server.p12
    key-store-password: 123456
    key-store-type: PKCS12
  • SSLConfig
@Configuration
public class SSLConfig {

    // http 请求端口
    @Value("${mydefine.port}")
    private int serverPortHttp;

    // HTTPS 请求端口
    @Value("${server.port}")
    private int serverPortHttps;


    @Bean
    public Connector connector (){
        Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
        connector.setScheme("http");
        //Connector监听的http的端口号
        connector.setPort(serverPortHttp);
        connector.setSecure(false);
        //监听到http的端口号后转向到的https的端口号
        connector.setRedirectPort(serverPortHttps);
        return connector;
    }

    //springboot 2.x 可用
    @Bean
    public TomcatServletWebServerFactory tomcatServletWebServerFactory(Connector connector){
        TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory() {
            @Override
            protected void postProcessContext(Context context) {
                SecurityConstraint securityConstraint = new SecurityConstraint();
                securityConstraint.setUserConstraint("CONFIDENTIAL");
                SecurityCollection collection = new SecurityCollection();
                collection.addPattern("/*");
                securityConstraint.addCollection(collection);
                context.addConstraint(securityConstraint);
            }
        };
        tomcat.addAdditionalTomcatConnectors(connector);
        return tomcat;
    }
}

双向

  • yml
mydefine:
  port: 8082
server:
  port: 8022
  ssl:
    enabled: true
    key-store-type: PKCS12 # PKCS12 #JKS
    key-store: classpath:certificate/server.p12
    key-store-password: 123456
    key-alias: server
    client-auth: none
    #trust-store-provider: SUN
    trust-store-type: PKCS12
    trust-store: classpath:certificate/server.p12
    trust-store-password: 123456
  • SSLConfig
@Configuration
public class SSLConfig {

    // http 请求端口
    @Value("${mydefine.port}")
    private int serverPortHttp;

    // HTTPS 请求端口
    @Value("${server.port}")
    private int serverPortHttps;

    @Bean
    public Connector connector (){
        Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
        connector.setScheme("http");
        //Connector监听的http的端口号
        connector.setPort(serverPortHttp);
        connector.setSecure(false);
        //监听到http的端口号后转向到的https的端口号
        connector.setRedirectPort(serverPortHttps);
        return connector;
    }

    //springboot 2.x 可用
    @Bean
    public TomcatServletWebServerFactory tomcatServletWebServerFactory(Connector connector){
        TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory() {
            @Override
            protected void postProcessContext(Context context) {
                SecurityConstraint securityConstraint = new SecurityConstraint();
                securityConstraint.setUserConstraint("CONFIDENTIAL");
                SecurityCollection collection = new SecurityCollection();
                collection.addPattern("/*");
                securityConstraint.addCollection(collection);
                context.addConstraint(securityConstraint);
            }
        };
        tomcat.addAdditionalTomcatConnectors(connector);
        return tomcat;
    }
}
  • RestTemplateConfig
@Configuration
public class RestTemplateConfig {
    @Value("${server.ssl.key-store-type}")
    String clientKeyType;
    @Value("${server.ssl.key-store}")
    String clientPath;
    @Value("${server.ssl.key-store-password}")
    String clientPass;

    @Value("${server.ssl.trust-store-type}")
    String trustKeyType;
    @Value("${server.ssl.trust-store}")
    String trustPath;
    @Value("${server.ssl.trust-store-password}")
    String trustPass;

    @Bean
    public RestTemplate restTemplate() {
        RestTemplate restTemplate = null;
        try {
            HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
            // 客户端证书类型
            KeyStore clientStore = KeyStore.getInstance(clientKeyType);
            // 加载客户端证书,即自己的私钥
            InputStream keyStream = getClass().getClassLoader().getResourceAsStream(clientPath);
            clientStore.load(keyStream, clientPass.toCharArray());
            // 创建密钥管理工厂实例
            KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
            // 初始化客户端密钥库
            keyManagerFactory.init(clientStore, clientPass.toCharArray());
            KeyManager[] keyManagers = keyManagerFactory.getKeyManagers();

            // 创建信任库管理工厂实例
            TrustManagerFactory trustManagerFactory = TrustManagerFactory
                    .getInstance(TrustManagerFactory.getDefaultAlgorithm());
            KeyStore trustStore = KeyStore.getInstance(trustKeyType);
            InputStream trustStream = getClass().getClassLoader().getResourceAsStream(trustPath);
            trustStore.load(trustStream, trustPass.toCharArray());

            // 初始化信任库
            trustManagerFactory.init(trustStore);
            TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
            // 建立TLS连接
            SSLContext sslContext = SSLContext.getInstance("TLS");
            // 初始化SSLContext
            sslContext.init(keyManagers, trustManagers, new SecureRandom());
            // INSTANCE 忽略域名检查
            SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE);
            CloseableHttpClient httpclient = HttpClients
                    .custom()
                    .setSSLSocketFactory(sslConnectionSocketFactory)
                    .setSSLHostnameVerifier(new NoopHostnameVerifier())
                    .build();
            requestFactory.setHttpClient(httpclient);
            requestFactory.setConnectTimeout((int) Duration.ofSeconds(15).toMillis());
            restTemplate = new RestTemplate(requestFactory);
        } catch (KeyManagementException | FileNotFoundException | NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (KeyStoreException | CertificateException | UnrecoverableKeyException | IOException e) {
            e.printStackTrace();
        }
        return restTemplate;
    }
}

Tomcat

  • tomcat/conf/server.xml
<Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol" maxThreads="150" SSLEnabled="true">
    <SSLHostConfig>
        <Certificate certificateKeystoreFile="conf/localhost-rsa.jks" type="RSA" certificateKeystorePassword="123456" />
    </SSLHostConfig>
</Connector>

或者

<Connector 
     port="443" 
     protocol="org.apache.coyote.http11.Http11NioProtocol" 
     maxThreads="150" 
     SSLEnabled="true" 
     scheme="https" 
     secure="true" 
     clientAuth="false" 
     sslProtocol="TLS" 
     keystoreFile="conf/localhost-rsa.jks" 
     keystorePass="123456" />

Nginx

nginx 配置后 tomcat / jar 不用配置

编辑配置文件 vim /usr/local/nginx/conf/nginx.conf

#user  nobody;
worker_processes  1;

events {
   worker_connections  1024;
}

http {
   include  mime.types;
   default_type  application/octet-stream;
   sendfile  on;
   keepalive_timeout  65;

   # http
   server {
      listen  80;
      server_name  localhost 192.168.1.1;
      return 301 https://$server_name$request_uri;
   }

   # https 单向认证
   server {
      listen       443 ssl;
      server_name  localhost 192.168.1.1;

      ssl_certificate /root/ssl/server.crt;
      ssl_certificate_key /root/ssl/server.key;

      location / {
         # 反向代理
         proxy_pass http://localhost:8080;
      }
   }

   # https 双向认证
   server {
        listen       443 ssl;
        server_name  localhost 192.168.1.1;

        ssl_certificate /root/ssl/server.crt;
        ssl_certificate_key /root/ssl/server.key;
        ssl_client_certificate /root/ssl/root.crt; # 根证书 也可以是单个的客户端证书
        ssl_verify_client on; # 开启双向认证
        
        ssl_session_timeout 10m;
        ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
        ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE; 
        ssl_prefer_server_ciphers on;

        location / {
            # 反向代理
            proxy_pass http://localhost:8080;
        }
   }

   server {
        listen       443 ssl;
        server_name  localhost 192.168.1.1;

        ssl_certificate /root/ssl/server.crt;
        ssl_certificate_key /root/ssl/server.key;
        ssl_client_certificate /root/ssl/root.crt; # 根证书 也可以是单个的客户端证书
        ssl_verify_client optional; # 配置校验客户端策略, ssl_client_verify = SUCCESS
        
        ssl_session_timeout 10m;
        ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
        ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE; 
        ssl_prefer_server_ciphers off;

        location / { # 需要双向验证https的接口
            if ($ssl_client_verify != SUCCESS) {
                 return 401;
            }
            proxy_pass http://localhost:8080;
            proxy_connect_timeout 600;
            proxy_read_timeout 600;
        }

        location /other/downloadUpdateFile { # 获取证书版本和下载证书接口,不需要验证Https
            proxy_pass http://localhost:8080;
            proxy_connect_timeout 600;
            proxy_read_timeout 600;
        }
   }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,884评论 6 513
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,212评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 167,351评论 0 360
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,412评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,438评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,127评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,714评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,636评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,173评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,264评论 3 339
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,402评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,073评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,763评论 3 332
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,253评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,382评论 1 271
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,749评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,403评论 2 358

推荐阅读更多精彩内容