浏览器提交表单 Html<输入类型文件生成请求,但 Ubuntu Tomcat Apache 服务器拒绝



我有一个Java servlet应用程序在Tomcat9 apache的Ubuntu 20.04.2上运行。servlet需要使用https传输来运行。我正在使用自签名证书在Tomcat9上启用https/TLS。

servlet尝试使用一个表单上传一个文件,该表单包含一个类型为file的html输入标记。

在我的局域网上,tomcat正在ip4地址为10.0.0.200的机器上运行。

如果我在tomcat服务器运行时从同一台机器上的浏览器访问servlet(例如ip4地址10.0.0.200)(例如urlhttps://10.0.0.200:8443/MyServlet),工作正常,文件已上载。

如果我从运行tomcat服务器的机器上的浏览器访问servlet(例如来自ip4地址为10.0.0.30的机器),则表单提交按钮的post请求将永远不会到达servlet(例如urlhttps://10.0.0.200:8443/MyServlet来自机器10.0.0.30)

浏览器(FireFox)报告:"连接到10.0.0.20:8443时出错。PR_CONNECT_RESET_ERROR无法显示您试图查看的页面,因为无法验证收到的数据的真实性。请联系网站所有者,将此问题告知他们">

为什么这不起作用?

这是从帖子中记录的:


POST /TempClientServlet/TempResult undefined
Host: 24.63.181.39:8443
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:89.0) Gecko/20100101 Firefox/89.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Content-Type: multipart/form-data; boundary=---------------------------3698066889622667783588722062
Content-Length: 970929
Origin: https://24.63.181.39:8443
Connection: keep-alive
Referer: https://24.63.181.39:8443/TempClientServlet/TempResult
Cookie: user_name=ccervo; textCookie=ccervo; JSESSIONID=401E418CE0A56EFB5A34784DE97DC996
Upgrade-Insecure-Requests: 1

这是web.xml文件:


<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" 
id="WebApp_ID" version="3.0">
<display-name>TempClientServlet</display-name>
<absolute-ordering />
<welcome-file-list>
<welcome-file>TempClient</welcome-file>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
<session-config>
<cookie-config>
<http-only>true</http-only>
<secure>true</secure>
</cookie-config>
</session-config>

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

这是server.xml文件:

<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements.  See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License.  You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
--><!-- Note:  A "Server" is not itself a "Container", so you may not
define subcomponents such as "Valves" at this level.
Documentation at /docs/config/server.html
-->
<Server port="8081" shutdown="SHUTDOWN">
<Listener className="org.apache.catalina.startup.VersionLoggerListener"/>
<!--APR library loader. Documentation at /docs/apr.html -->
<Listener SSLEngine="on" className="org.apache.catalina.core.AprLifecycleListener"/>
<!-- Prevent memory leaks due to use of particular java/javax APIs-->
<Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener"/>
<Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener"/>
<Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener"/>
<!-- Global JNDI resources
Documentation at /docs/jndi-resources-howto.html
-->
<GlobalNamingResources>
<!-- Editable user database that can also be used by
UserDatabaseRealm to authenticate users
-->
<Resource auth="Container" description="User database that can be updated and saved" factory="org.apache.catalina.users.MemoryUserDatabaseFactory" name="UserDatabase" pathname="conf/tomcat-users.xml" type="org.apache.catalina.UserDatabase"/>
</GlobalNamingResources>
<!-- A "Service" is a collection of one or more "Connectors" that share
a single "Container" Note:  A "Service" is not itself a "Container",
so you may not define subcomponents such as "Valves" at this level.
Documentation at /docs/config/service.html
-->
<Service name="Catalina">
<!--The connectors can use a shared executor, you can define one or more named thread pools-->
<!--
<Executor name="tomcatThreadPool" namePrefix="catalina-exec-"
maxThreads="150" minSpareThreads="4"/>
-->
<Connector connectionTimeout="20000"
port="8080"
protocol="HTTP/1.1"
redirectPort="8443"
/>
<!-- uncomment this to run servlets secure ie. https -->
<Connector SSLEnabled="true"
clientAuth="false"
keystoreFile="/home/foobar/.keystore"
keystorePass="changeit"
maxThreads="200"
port="8443"
protocol="org.apache.coyote.http11.Http11NioProtocol"
scheme="https"
secure="true" 
sslProtocol="TLS"
/>
<!-- Define an AJP 1.3 Connector on port 8009 -->
<!--
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
-->
<!-- An Engine represents the entry point (within Catalina) that processes
every request.  The Engine implementation for Tomcat stand alone
analyzes the HTTP headers included with the request, and passes them
on to the appropriate Host (virtual host).
Documentation at /docs/config/engine.html -->
<!-- You should set jvmRoute to support load-balancing via AJP ie :
<Engine name="Catalina" defaultHost="localhost" jvmRoute="jvm1">
-->
<Engine defaultHost="localhost" name="Catalina">
<!--For clustering, please take a look at documentation at:
/docs/cluster-howto.html  (simple how to)
/docs/config/cluster.html (reference documentation) -->
<!--
<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"/>
-->
<!-- Use the LockOutRealm to prevent attempts to guess user passwords
via a brute-force attack -->
<Realm className="org.apache.catalina.realm.LockOutRealm">
<!-- This Realm uses the UserDatabase configured in the global JNDI
resources under the key "UserDatabase".  Any edits
that are performed against this UserDatabase are immediately
available for use by the Realm.  -->
<Realm className="org.apache.catalina.realm.UserDatabaseRealm" resourceName="UserDatabase"/>
</Realm>
<Host appBase="webapps" autoDeploy="true" name="localhost" unpackWARs="true">

<!-- SingleSignOn valve, share authentication between web applications
Documentation at: /docs/config/valve.html -->
<!--
<Valve className="org.apache.catalina.authenticator.SingleSignOn" />
-->

<!-- Access log processes all example.
Documentation at: /docs/config/valve.html
Note: The pattern used is equivalent to using pattern="common" -->
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" pattern="%h %l %u %t &quot;%r&quot; %s %b" prefix="localhost_access_log" suffix=".txt"/>

<Context docBase="TempClientServlet" path="/TempClientServlet" reloadable="true" source="org.eclipse.jst.jee.server:TempClientServlet"/>
<Context path="/TempClientServlet/images" docBase="/var/opt/TempClientServletimages" crossContext="true"/>
<Context docBase="Temp_Service" path="/Temp_Service" reloadable="true" source="org.eclipse.jst.jee.server:Temp_Service"/>
<Context docBase="Temp_ServiceClient" path="/Temp_ServiceClient" reloadable="true" source="org.eclipse.jst.jee.server:Temp_ServiceClient"/>
</Host>
</Engine>
</Service>
</Server>

没有100%的答案,但距离足够近,我会自己到达那里。

获得答案的步骤:

  1. 我编写了一个隧道/代理,将用户代理(浏览器)连接到tomcat运行我的servlet并记录两者之间的所有TCP流量
  2. 在我的servlet中添加了调试代码,以消除对会话id和cookie的使用。我会在发现错误后恢复它
  3. Eclipse中配置的server.xml在端口8080和8443上创建连接器是HTTP连接器
  4. 已为servlet配置web.xml以允许http访问。注意事项和建议:如果您试图调试一个安全的servlet,那么有很多陷阱需要避免
  5. 如果您试图从Eclipse调试servlet,请注意这些陷阱。a) Eclipse调试器在与Tomcat不同的环境中运行Tomcat服务正在运行。特别是Tomcat服务是沙盒式的。Tomcat运行Eclipse调试器不是。这可能会导致servlet行为异常在调试器中运行和通过服务运行时有所不同。b) Linux,Ubuntu,以用户名"Tomcat"作为服务运行Tomcat;tomcat";。日食Ubuntu上的调试器以启动用户的用户名运行Tomcat日食这可能会导致servlet行为异常在调试器中运行和通过服务运行时有所不同
  6. 如果在调试时在http和https之间切换,请注意这些陷阱。a) 如果servlet使用J2EE会话和/或cookie,请注意servlet容器的行为取决于适用的web.xml(应用程序和/或服务器)中的设置。如果web.xml指定了一个具有机密传输保证的安全约束,那么servlet容器设置";"安全";以及";http/only";所有cookie的属性(包括jsession cookie)。如果不存在servlet容器不设置的约束;"安全";和/或";http/only";在饼干上。http规范规定,用户代理、浏览器将如果传输是安全的,则仅传递/返回安全cookie(https/tls)。这可能导致servlet在使用http和http访问时丢失会话并表现出截然不同的行为。https。b) 如果您在与您的servlet服务器,http规范规定用户代理可以安全地传递cookie,即使传输不是https并且不安全。这可能导致servlet在使用与servlet服务器在同一台机器上运行的用户代理。因此,在自学了所有这些陷阱之后,我现在让servlet通过http隧道运行。我可以观察到所有的TCP流量。在不同的机器上使用用户代理和servlet服务器运行;在Eclipse调试器中运行;在HTTP中运行;在使用cookie和删除会话的情况下运行;我的servlet运行完全没有问题(只是通过http隧道记录的结果会减慢速度)。我现在需要恢复server.xml和web.xml才能使用https;恢复会话和cookie的使用,并确定该配置引发错误的原因。这将是缓慢而痛苦的,但我想我可以艰难地度过

servlet没有损坏。它运行正常。该行为是围绕HTML"的额外严格的用户代理安全性的结果<输入";带有类型"的标签;文件";。当用户代理(浏览器)与servlet服务器(Tomcat)位于同一物理机器上时,用户代理将放宽安全要求,servlet将按预期运行,表单将成功上载文件。当用户代理(浏览器)在servlet服务器(Tomcat)运行的机器之外的机器上运行时。用户代理检测到servlet是通过在"https"下建立的https/TLS连接运行的;自签名证书";。即使用户已经被警告并接受了";自签名证书";,用户代理认为它"是";不安全";并报告错误:

"PR_CONNECT_RESET_ERROR由于无法验证接收到的数据的真实性,因此无法显示您试图查看的页面">

因此,解决方案是:

  1. 注册域并购买经过身份验证的证书
  2. 使用http不安全地运行servlet
  3. 直面问题