为什么我的Java servlet过滤器无法通过HTTPS工作?

时间:2016-07-06 09:34:20

标签: java spring ssl https proxy

Spring(Boot)在这里,虽然这根本不重要。我正在尝试了解有关HTTP / S代理如何工作的更多信息以及构建一个在我的机器上本地运行的代理。我编写(并注册)了一个servlet过滤器,它用一条愚蠢的HTML消息替换了HTTP响应的主体:

public class DummyFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    @Override
    void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletResponse httpServletResponse = (HttpServletResponse)response;

        String html = "<html><head><title>Awesome!</title></head><body>Proxy is working!</body></html>";

        httpServletResponse.writer.write(html);
        httpServletResponse.writer.flush();

        return;
    }

    @Override
    public void destroy() {
    }
}

然后我运行我的Spring应用,并将浏览器的代理设置更改为指向我的应用(localhost:8080)。

我现在可以访问HTTP网站并查看我的虚拟消息(&#34; 代理正在工作!&#34;)作为HTML输出。成功!!!然而,我随后访问了谷歌的主页,该主页显然使用了HTTPS,谷歌主页也很好。

因此,我将浏览器更改为使用我的Spring应用程序代理SSL(再次,localhost:8080)并再次尝试。这次我去谷歌时,我的浏览器给了我一个错误,说明连接有问题。我认为这是因为我的愚蠢简单代理导致了SSL&#39;握手问题。浏览器和需要SSL的网站(在本例中为Google)。

我知道在SSL上使用代理肯定是可能的,因为(至少)Charles Proxy可以配置为执行此操作。显然,Charles根据自己的根CA证书动态生成您尝试访问的站点的证书。 Charles和SSL网站使用该网站的证书,浏览器和Charles之间的通信使用Charles&#39;证书。

但是知道这并不能帮助我理解为什么我的简单代理首先会导致SSL-land出现问题。 我需要在代码中更改哪些内容,以便它与HTTPS的行为相同,与HTTP相同?

更新

我想知道以下内容对我是否有用:

  1. *.example.com(任何点com)
  2. 创建一个自签名通配符证书
  3. 配置我的Sring应用程序以使用此通配符证书并从端口443提供HTTPS(默认为HTTPS)
  4. 将浏览器的SSL代理设置配置为指向localhost:443
  5. 将我的自签名通配符证书添加到我的浏览器的信任存储
  6. 现在,当我转到https://example.com下的任何网址时,浏览器会联系我的代理服务器,代理服务器返回自签名证书(它现在信任它),代理服务器可以与{{{ 1}}网站的实际证书就好了。
  7. 这或类似的东西会解决我的问题吗?

3 个答案:

答案 0 :(得分:4)

指出的问题确实是HTTP / S基本问题。

当指示您的浏览器在给定地址( localhost:8080 )使用代理时,浏览器会对配置的“代理服务器”进行任何后续HTTP调用,以指示此“代理”它应该代表调用浏览器执行一个调用原始URL。

在您的情况下,“代理”确实返回了一个预设消息,并没有真正尝试连接到原始URL。 (至少你没有告诉任何关于你的“代理服务器”将要联系最初目标站点的事情。) 这将是代理基本功能的更重要方面。

在使用HTTPS连接服务器的情况下,重要的是,您如何使用浏览器配置代理连接。

可以使用与代理的纯HTTP连接,并仍然请求代理使用HTTPS连接进行“外部”调用。 (然而,这样的配置并不是那么普遍,因为代理需要仔细处理重定向。此外,它会使首先使用HTTPS的一些收益无效(至少在从浏览器到代理的通信段上)。

您的浏览器配置很可能使用与“代理”( localhost:8080 )的HTTPS连接。然后,浏览器尝试了HTTPS请求,并在目标“使用常规HTTP”响应时遇到错误。

将代理servlet配置为接受HTTPS调用将“修复”该问题。 (从此处,“更新”编辑中的步骤将“解决”错误。)但是,您不需要在localhost使用端口443。任何端口都可以。如果您想同时提供HTTP和HTTPS代理,您需要分配两个端口(例如,您可以使用8080表示HTTP,8081表示HTTPS)。

只是为了解决:看到“代理正在工作”消息并不能证明有一个工作代理。它只是证明您的浏览器确实与您的servlet通信。 (由于您没有阅读任何标题信息,因此与直接调用URL localhost:8080 没有区别。)

除了“联系”之外,工作代理还需要接收请求,分析传入的标头并根据标准做出反应(特别是执行请求的“外部”调用并返回结果)。 (当然,您已经阅读了与HTTP协议相关的RFC(例如RFC7230)?)

答案 1 :(得分:1)

您必须创建HTTPS连接器。 要创建HTTPS连接器,您需要做一些事情;但最重要的是,您需要生成证书密钥库,用于加密和解密与浏览器的SSL通信。

如果您使用的是Unix或Mac,则可以通过运行以下命令来执行此操作: $ JAVA_HOME / bin / keytool -genkey -alias tomcat -keyalg RSA 在Windows上,这可以通过以下代码实现: “%JAVA_HOME%\ bin \ keytool”-genkey -alias tomcat -keyalg RSA

在创建密钥库期间,您应输入适合您的信息,包括密码,名称等。出于执行完成的目的,新生成的密钥库文件将出现在主目录中,名称为:.keystore。 注意 您可以在tomcat找到有关准备证书密钥库的更多信息。

完成密钥库创建后,您需要创建单独的属性文件,以便存储HTTPS连接器的配置,例如端口和其他。之后,您将创建一个配置属性绑定对象,并使用它来配置我们的新连接器。

请参阅prop文件的此示例。你可以用它来命名它:tomcat.https.properties

custom.tomcat.https.port=8443
custom.tomcat.https.secure=true
custom.tomcat.https.scheme=https
custom.tomcat.https.ssl=true
custom.tomcat.https.keystore=${user.home}/.keystore
custom.tomcat.https.keystore-password=changeit

答案 2 :(得分:1)

不需要更改您的代码。您可能缺少配置。请检查您是否正确配置了ssl。 按照以下步骤在spring应用程序中启用ssl:

  1. 创建密钥库文件

    keytool -genkey -alias tomcat -keyalg RSA

  2. 2.配置Tomcat以使用密钥库文件 - SSL配置 在您的server.xml中

    找到以下声明:

    <!--
    <Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"
        maxThreads="150" scheme="https" secure="true"
        clientAuth="false" sslProtocol="TLS" />
    -->
    

    取消注释并将其修改为如下所示:

    Connector SSLEnabled="true" acceptCount="100" clientAuth="false"
        disableUploadTimeout="true" enableLookups="false" maxThreads="25"
        port="8443" keystoreFile="/Users/prashant/.keystore" keystorePass="password"
        protocol="org.apache.coyote.http11.Http11NioProtocol" scheme="https"
        secure="true" sslProtocol="TLS" />
    

    3.配置您的应用以使用SSL(通过https://localhost:8443/yourApp访问)

    添加应用程序的web.xml文件。

    <security-constraint>
        <web-resource-collection>
            <web-resource-name>securedapp</web-resource-name>
            <url-pattern>/*</url-pattern>
        </web-resource-collection>
        <user-data-constraint>
            <transport-guarantee>CONFIDENTIAL</transport-guarantee>
        </user-data-constraint>
    </security-constraint>
    

    它适用于我的自定义过滤器。

    希望这对你有帮助..