简体   繁体   English

为什么我的Java servlet过滤器不能通过HTTPS工作?

[英]Why does my Java servlet filter not work over HTTPS?

Spring (Boot) here, although that shouldn't matter at all. Spring(Boot)在这里,虽然这根本不重要。 I am trying to learn more about how HTTP/S proxies work and am building one to run locally on my machine. 我正在尝试了解有关HTTP / S代理如何工作的更多信息以及构建一个在我的机器上本地运行的代理。 I wrote (and registered) a servlet filter that replaces the body of the HTTP response with a silly HTML message: 我编写(并注册)了一个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() {
    }
}

I then run my Spring app, and change my browser's proxy settings to point to my app ( localhost:8080 ). 然后我运行我的Spring应用程序,并将浏览器的代理设置更改为指向我的应用程序( localhost:8080 )。

I am now able to go to HTTP websites and see my dummy message (" Proxy is working! ") as the HTML output. 我现在能够访问HTTP网站,看到我的虚拟消息(“ 代理正在工作! ”)作为HTML输出。 Success!!! 成功!!! However, I then went to Google's homepage, which apparently uses HTTPS, and the Google homepage rendered just fine. 然而,我然后去了谷歌的主页,显然使用HTTPS,谷歌主页渲染得很好。

So I changed my browser to also use my Spring app for proxying SSL (again, localhost:8080 ) and tried again. 所以我改变了我的浏览器以使用我的Spring应用程序代理SSL(再次, localhost:8080 )并再次尝试。 This time when I went to Google, my browser gave me an error stating that there was a problem with the connection. 这次我去谷歌时,我的浏览器给了我一个错误,说明连接有问题。 I assume this is because my stupid-simple proxy is causing problems with the SSL 'handshake' between the browser and the site requiring SSL (in this case, Google). 我认为这是因为我的愚蠢简单代理导致浏览器和需要SSL的网站(在本例中为Google)之间的SSL“握手”问题。

I know that using proxies over SSL is certainly possible, because (at the very least) the Charles Proxy can be configured to do this. 我知道在SSL上使用代理肯定是可能的,因为(至少) Charles Proxy可以配置为执行此操作。 Apparently, Charles operates by dynamically generating a cert for the site you are trying to access, based off its own root CA cert. 显然,Charles根据自己的根CA证书动态生成您尝试访问的站点的证书。 Charles and the SSL site use the site's cert, and the communication between the browser and Charles uses Charles' cert. Charles和SSL站点使用该站点的证书,浏览器和Charles之间的通信使用Charles的证书。

But knowing that doesn't help me understand why my simple proxy is causing problems in SSL-land in the first place. 但是知道这并没有帮助我理解为什么我的简单代理首先在SSL-land中引起问题。 What would I need to change in my code so that it could behave the same with HTTPS as it does with HTTP? 我需要在代码中进行哪些更改才能使其与HTTPS的行为相同,与HTTP相同?


Update 更新

I'm wondering if the following would work for me: 我想知道以下是否适合我:

  1. Create a self-signed wildcard cert for, say *.example.com (anything dot com) *.example.com创建一个自签名通配符证书(任何dot com)
  2. Configure my Sring app to use this wildcart cert and to serve HTTPS from port 443 (HTTPS default) 配置我的Sring应用程序以使用此wildcart证书并从端口443提供HTTPS(HTTPS默认值)
  3. Configure the browser's SSL proxy settings to point to localhost:443 将浏览器的SSL代理设置配置为指向localhost:443
  4. Add my self-signed wildcard cert to my browser's trust store 将我的自签名通配符证书添加到浏览器的信任存储区
  5. Now when I go to any URL under https://example.com , the browser reaches out to my proxy, which serves it back the self-signed cert (which it now trusts), and the proxy can talk with the example.com site's actual cert just fine. 现在,当我访问https://example.com下的任何URL时,浏览器会联系我的代理,代理服务于自签名证书(现在它信任),代理可以与example.com交谈网站的实际证书就好了。

Would this, or something similar, fix my problem? 这或类似的东西会解决我的问题吗?

The problems indicated really are HTTP/S basic ones. 表明的问题确实是HTTP / S基本问题。

When directing your browser to use a proxy at the given address ( localhost:8080 ), the browser is causing any subsequent HTTP call to the configured "proxy server" indicating to this "proxy" that it should execute a call on behalf of the calling browser to the original URL. 当指示您的浏览器在给定地址( localhost:8080 )使用代理时,浏览器会对配置的“代理服务器”进行任何后续HTTP调用,指示此“代理”它应该代表调用执行调用浏览器到原始URL。

In your case the "proxy" really is returning a canned message and does not really try connecting to the original URL. 在您的情况下,“代理”实际上是返回一个预制消息,并没有真正尝试连接到原始URL。 (At least you did not tell anything about what your "Proxy Server" is going to do in order to contacting the originally targeted site.) That would be the more material aspect of a proxy basic functionality. (至少你没有告诉任何关于你的“代理服务器”将要联系最初目标站点的事情。)这将是代理基本功能的更重要方面。

In the case of connecting to a server using HTTPS, it is then important, how you did configured that proxy connection with your browser. 在使用HTTPS连接到服务器的情况下,重要的是,您如何配置与浏览器的代理连接。

It would be possible to use a plain HTTP connection to the proxy and still request the proxy to using a HTTPS connection for the "external" call. 可以使用与代理的纯HTTP连接,并仍然请求代理使用HTTPS连接进行“外部”调用。 (Such configuration, however, is not so much widespread, as the proxy need to eg carefully treat redirects. Also it would invalidate some gains of using HTTPS in the first place (at least on the communication segment from browser to proxy.) (然而,这样的配置并不是那么普遍,因为代理需要仔细处理重定向。此外,它会使首先使用HTTPS的一些收益无效(至少在从浏览器到代理的通信段上)。

Most likely your browser configuration used an HTTPS connection to the "proxy" ( localhost:8080 ). 很可能您的浏览器配置使用HTTPS连接到“代理”( localhost:8080 )。 Then the browser tried an HTTPS request and hit an error as the target "responded" with regular HTTP. 然后,浏览器尝试了HTTPS请求,并在目标“使用常规HTTP”响应时遇到错误。

Configuring your proxy servlet to accepting HTTPS calls would "repair" that problem. 将代理servlet配置为接受HTTPS调用将“修复”该问题。 (Form this, your steps from the "Update" edit will "solve" the errors.) However, you do not need to use port 443 at localhost. (从此处,“更新”编辑中的步骤将“解决”错误。)但是,您不需要在localhost使用端口443。 Any port will do. 任何端口都可以。 Just if you want to provide an HTTP and an HTTPS proxy at the same time do you need to allocate two ports (eg you could use 8080 for HTTP and 8081 for HTTPS). 如果您想同时提供HTTP和HTTPS代理,您需要分配两个端口(例如,您可以使用8080用于HTTP,8081用于HTTPS)。

Just to empachase: Seeing the "Proxy is working" message does not prove having a working proxy. 只是为了解释:看到“代理正在工作”消息并不能证明有一个工作代理。 It just proves that your browser does talk to your servlet. 它只是证明您的浏览器确实与您的servlet通信。 (As you do not read any header information, it is not different from just calling URL localhost:8080 directly.) (因为您没有读取任何标头信息,所以它与直接调用URL localhost:8080没有区别。)

Beyond getting "contacted" a working proxy would need to take the request, analyze the headers passed in and react according to the standards (especially executing the requested "external" call and returning the results). 除了“联系”之外,工作代理还需要接收请求,分析传入的标头并根据标准做出反应(特别是执行请求的“外部”调用并返回结果)。 (Of course, you have read RFCs related to HTTP protocol (eg RFC7230)?) (当然,您已经阅读了与HTTP协议相关的RFC(例如RFC7230)?)

You must create a HTTPS connector. 您必须创建HTTPS连接器。 In order to create an HTTPS connector, you will need a few things; 要创建HTTPS连接器,您需要做一些事情; but most importantly, you will need to generate Certificate keystore that is used to encrypt and decrypt the SSL communication with the browser. 但最重要的是,您需要生成证书密钥库,用于加密和解密与浏览器的SSL通信。

If you are using Unix or Mac, you can do it by running the following command: $JAVA_HOME/bin/keytool -genkey -alias tomcat -keyalg RSA On Windows, this could be achieved via the following code: "%JAVA_HOME%\\bin\\keytool" -genkey -alias tomcat -keyalg RSA 如果您使用的是Unix或Mac,则可以通过运行以下命令来执行此操作: $ JAVA_HOME / bin / keytool -genkey -alias tomcat -keyalg RSA在Windows上,可以通过以下代码实现: “%JAVA_HOME%\\ bin \\ keytool“-genkey -alias tomcat -keyalg RSA

During the creation of the keystore, you should enter the information that is appropriate to you, including passwords, name, and so on. 在创建密钥库期间,您应输入适合您的信息,包括密码,名称等。 For the purpose of Once the execution is complete, a newly generated keystore file will appear in your home directory under the name: .keystore. 出于执行完成的目的,新生成的密钥库文件将出现在主目录中,名称为:.keystore。 Note You can find more information about preparing the certificate keystore at tomcat . 注意您可以在tomcat中找到有关准备证书密钥库的更多信息。

With the keystore creation complete, you will need to create a separate properties file in order to store your configuration for the HTTPS connector, such as port and others. 完成密钥库创建后,您需要创建单独的属性文件,以便存储HTTPS连接器的配置,例如端口和其他。 After that, you will create a configuration property binding object and use it to configure our new connector. 之后,您将创建一个配置属性绑定对象,并使用它来配置我们的新连接器。

See this example of a prop file. 请参阅prop文件的此示例。 you can cll it whatever name you want : tomcat.https.properties 你可以用你想要的任何名字命名: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

Don't need to change your code.You might be missing configuration.Check whether you configured ssl correctly . 不需要更改您的代码。您可能缺少配置。检查您是否正确配置了ssl。 Follow the steps to enable ssl in your spring app: 按照以下步骤在spring应用程序中启用ssl:

  1. create Keystore file 创建密钥库文件

    keytool -genkey -alias tomcat -keyalg RSA keytool -genkey -alias tomcat -keyalg RSA

2.Configuring Tomcat for using the keystore file – SSL config in your server.xml 2.配置Tomcat以使用密钥库文件 - server.xml中的SSL配置

Find the following declaration: 找到以下声明:

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

Uncomment it and modify it to look like the following: 取消注释并将其修改为如下所示:

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.Configuring your app to work with SSL (access through https://localhost:8443/yourApp ) 3.配置您的应用程序以使用SSL(通过https:// localhost:8443 / yourApp访问

add in your web.xml file of your application. 添加应用程序的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>

It works for me with my custom filter. 它适用于我的自定义过滤器。

Hope so it will help you.. 希望所以它会帮助你..

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM