使用Nginx代理restful实现SSL链路加密

1 目标说明

1.1 调研目的

本次调研主要为了解决两个问题:

  • 不需要对restful的web容器做任何配置,实现对restful链路进行加密;
  • 方便restful应用进行扩展,采用多个服务进行负载均衡,以提升吞吐量。

1.2 目标网络模型

    希望达到的目标网络模型如下:

1.3 SSL说明

    通过对SSL的学习,结合自身业务的考虑,对SSL的使用做如下说明:

    我这里SSL使用TLSv1,并且服务端不需要校验客户端的身份合法性,则使用SSL单向认证方式,只需要服务端证书。另外我们只需要用到SSL的链路加密,所以可以设置客户端对服务端证书保持永久信任

2 调研过程

这里restful使用jersey来实现,使用jetty作为javaee容器。

2.1 测试非加密restful

通过jetty发布非加密restful服务,url为 http://localhost:8080/api/v1/....

2.1.1 服务端代码

web.xml

    <servlet>
        <servlet-name>RestApplication</servlet-name>
        <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
        <init-param>
            <param-name>javax.ws.rs.Application</param-name>
            <param-value>com.spiro.test.jersey.MyApplication</param-value>
        </init-param>
    </servlet>
    <servlet-mapping>
        <servlet-name>RestApplication</servlet-name>
        <url-pattern>/api/v1/*</url-pattern>
    </servlet-mapping>

Resource:

import com.spiro.test.jersey.entity.Terminal;

import javax.inject.Singleton;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.util.ArrayList;
import java.util.List;

@Path("terminals")
@Singleton
public class TerminalsResource {

    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public Response getAll() {

        List<Terminal> terminals = new ArrayList<Terminal>();

        Terminal ter1 = new Terminal();
        ter1.setId("101");
        ter1.setDesc("I'm 101");
        terminals.add(ter1);

        Terminal ter2 = new Terminal();
        ter2.setId("102");
        ter2.setDesc("I'm 102");
        terminals.add(ter2);


//        if(true) {
//            return Response.status(Response.Status.UNAUTHORIZED).build();
//        }

        return Response.ok(terminals).build();
    }
}

ResourceConfig:

import com.spiro.test.jersey.resources.TerminalsResource;
import org.glassfish.jersey.jackson.JacksonFeature;
import org.glassfish.jersey.server.ResourceConfig;

public class MyApplication extends ResourceConfig {

    public MyApplication() {
        register(TerminalsResource.class);
        register(JacksonFeature.class);
    }
}

2.1.2 客户端代码

    public static void testHttp() {

        ClientConfig clientConfig = new ClientConfig();
        Client client = ClientBuilder.newClient(clientConfig);

        String url = "http://localhost:8080/api/v1/";

        String entity = client.target(url)
                .path("terminals")
                .request(MediaType.APPLICATION_JSON)
                .get(String.class);

        System.out.println(entity);
    }

经测试成功打印:[{"id":"101","desc":"I'm 101"},{"id":"102","desc":"I'm 102"}]

2.2 测试https 加密restful

2.2.1 nginx安装配置

    在windows7机器上安装nginx-1.10.1,配置如下:

worker_processes  1;

events {
    worker_connections  1024;
}

http {
    include       mime.types;
    default_type  application/octet-stream;

    server {
        listen       443 ssl;
        server_name  localhost;

		ssl_certificate       D:/server.crt;
		ssl_certificate_key   D:/_server.key;

        location / {
            proxy_pass   http://127.0.0.1:8080;
        }
    }
}

2.2.2 服务端代码

   同2.1.1

2.2.3 客户端代码

// Create a trust manager that does not validate certificate chains
TrustManager[] trustAllCerts = new TrustManager[] {new X509TrustManager() {
    public X509Certificate[] getAcceptedIssuers() {
        return null;
    }
    public void checkClientTrusted(X509Certificate[] certs, String authType) {
    }
    public void checkServerTrusted(X509Certificate[] certs, String authType) {
    }
}
};

// Install the all-trusting trust manager
SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());

// Create all-trusting host name verifier
HostnameVerifier allHostsValid = new HostnameVerifier() {
    public boolean verify(String hostname, SSLSession session) {
        return true;
    }
};

HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);

Client client = ClientBuilder.newBuilder().sslContext(sslContext).build();

String entity = client.target("https://127.0.0.1:443/api/v1/")
        .path("terminals")
        .request(MediaType.APPLICATION_JSON)
        .get(String.class);

System.out.println(entity);

设置客户端请求连接为ssl加密,并且客户端永久信任服务端,不对服务端证书进行验证。

经测试成功打印:[{"id":"101","desc":"I'm 101"},{"id":"102","desc":"I'm 102"}]

3 总结

    经测试,可以通过nginx https代理restful 实现链路加密,后续可通过nginx upstream实现负载均衡。

完整代码请查看

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Linyb极客之路

在Spring Boot中使用HTTPS

24220
来自专栏玩转JavaEE

为我们的Web添加HTTPS支持

按:最近公众号文章主要是整理一些老文章,以个人CSDN上的博客为主,也会穿插一些新的技术点。 ---- 上篇博客使用Spring Boot开发Web项目我们简单...

75370

获得具有商业签名的TLS证书

如果您打算托管一个可公开访问的使用HTTPS的网站,那么您将需要安装一个具有商业签名的TLS证书,这样访问您网站的人就不会在浏览器中收到有关不安全连接的警告。

12030
来自专栏猿天地

前后端API交互如何保证数据安全性?

前后端分离的开发方式,我们以接口为标准来进行推动,定义好接口,各自开发自己的功能,最后进行联调整合。无论是开发原生的APP还是webapp还是PC端的软件,只要...

42620
来自专栏JMCui

Jenkins修改管理员密码.

前言:Jenkins修改管理员密码,我看了网上所有的教程,竟然全都是拿着一串已经加密好的111111的密文去替代config.xml文件里面的密码,然后大家的...

37940
来自专栏蓝天

SecureCRT和乱码

对于vi或vim乱码,则需要在~/.vimrc文件中设置encoding、fileencoding或fileencodings,如:

8510
来自专栏腾讯Bugly的专栏

iOS 中 HTTPS 证书验证浅析

导语 在 WWDC 16 中,Apple 表示, 从 2017年1月1日起(最新消息, 实施时间已延期),所有新提交的 App 使用系统组件进行的 HTTP 网...

68080
来自专栏编程

Nginx双证书ECC/RSA配置

大家好,我是你们的老朋友Alex。今天教大家使用nginx配置证书,双证书! Nginx1.11.0版本后提供了ESA/ECC双证书的支持,以下是参考链接: h...

80880
来自专栏做全栈攻城狮

React Native APP签名打包release版本APK

首先React Native开发的APP是无法通过Android Studio进行打包的,因为AS打包的APK,也是和debug版本一样,需要进行依托local...

22620
来自专栏Ryan Miao

spring boot启用tomcat ssl

首先要生成一个keystore证书。参考:Tomcat创建HTTPS访问,java访问https,ssl证书生成:cer&jks文件生成摘录,spring-bo...

688140

扫码关注云+社区

领取腾讯云代金券