微信支付回调解析问题

[ERROR]-[Thread: XNIO-1 task-4]-[com.jfinal.core.ActionHandler.handle()]: /api/users/payment/wxPayNotifyUrl
java.lang.RuntimeException: org.xml.sax.SAXParseException; lineNumber: 2; columnNumber: 10; DOCTYPE is disallowed when the feature "http://apache.org/xml/features/disallow-doctype-decl" set to true.
	at com.jfinal.weixin.sdk.utils.XmlHelper.create(XmlHelper.java:71)
	at com.jfinal.weixin.sdk.utils.XmlHelper.of(XmlHelper.java:85)
	at com.jfinal.weixin.sdk.kit.PaymentKit.xmlToMap(PaymentKit.java:114)
	at com.mibo.hdcm.modules.app.user.service.PaymentService.wxPayNotifyUrl(PaymentService.java:147)
	at com.mibo.hdcm.modules.app.user.service.PaymentService$$EnhancerByCGLIB$$2e7b0055.CGLIB$wxPayNotifyUrl$3(<generated>)
	at com.mibo.hdcm.modules.app.user.service.PaymentService$$EnhancerByCGLIB$$2e7b0055$$FastClassByCGLIB$$6a48b07d.invoke(<generated>)
	at net.sf.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:228)
	at com.jfinal.aop.Invocation.invoke(Invocation.java:84)
	at com.jfinal.aop.Callback.intercept(Callback.java:96)
	at com.mibo.hdcm.modules.app.user.service.PaymentService$$EnhancerByCGLIB$$2e7b0055.wxPayNotifyUrl(<generated>)
	at com.mibo.hdcm.modules.app.user.action.PaymentAction.wxPayNotifyUrl(PaymentAction.java:36)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at com.jfinal.aop.Invocation.invoke(Invocation.java:75)
	at com.jfinal.core.ActionHandler.handle(ActionHandler.java:89)
	at com.mibo.hdcm.framework.handler.CrossDomainHandler.handle(CrossDomainHandler.java:17)
	at com.jfinal.core.JFinalFilter.doFilter(JFinalFilter.java:89)
	at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61)
	at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131)
	at io.undertow.servlet.handlers.FilterHandler.handleRequest(FilterHandler.java:84)
	at io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:62)
	at io.undertow.servlet.handlers.ServletChain$1.handleRequest(ServletChain.java:68)
	at io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36)
	at io.undertow.servlet.handlers.security.SSLInformationAssociationHandler.handleRequest(SSLInformationAssociationHandler.java:132)
	at io.undertow.servlet.handlers.security.ServletAuthenticationCallHandler.handleRequest(ServletAuthenticationCallHandler.java:57)
	at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
	at io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:46)
	at io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.java:64)
	at io.undertow.security.handlers.AuthenticationMechanismsHandler.handleRequest(AuthenticationMechanismsHandler.java:60)
	at io.undertow.servlet.handlers.security.CachedAuthenticatedSessionHandler.handleRequest(CachedAuthenticatedSessionHandler.java:77)
	at io.undertow.security.handlers.AbstractSecurityContextAssociationHandler.handleRequest(AbstractSecurityContextAssociationHandler.java:43)
	at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
	at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
	at io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:292)
	at io.undertow.servlet.handlers.ServletInitialHandler.access$100(ServletInitialHandler.java:81)
	at io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:138)
	at io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:135)
	at io.undertow.servlet.core.ServletRequestContextThreadSetupAction$1.call(ServletRequestContextThreadSetupAction.java:48)
	at io.undertow.servlet.core.ContextClassLoaderSetupAction$1.call(ContextClassLoaderSetupAction.java:43)
	at io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:272)
	at io.undertow.servlet.handlers.ServletInitialHandler.access$000(ServletInitialHandler.java:81)
	at io.undertow.servlet.handlers.ServletInitialHandler$1.handleRequest(ServletInitialHandler.java:104)
	at io.undertow.server.Connectors.executeRootHandler(Connectors.java:360)
	at io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:830)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	at java.lang.Thread.run(Thread.java:748)
Caused by: org.xml.sax.SAXParseException; lineNumber: 2; columnNumber: 10; DOCTYPE is disallowed when the feature "http://apache.org/xml/features/disallow-doctype-decl" set to true.
	at com.sun.org.apache.xerces.internal.parsers.DOMParser.parse(DOMParser.java:257)
	at com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderImpl.parse(DocumentBuilderImpl.java:339)
	at com.jfinal.weixin.sdk.utils.XmlHelper.<init>(XmlHelper.java:61)
	at com.jfinal.weixin.sdk.utils.XmlHelper.create(XmlHelper.java:67)
	... 48 more

评论区

7479chen

2019-06-10 09:48

有一样的问题

JFinal

2019-06-10 10:07

异常提示了被解析的 XML 文档中有 DOCTYPE,而这个已经在 XmlHelper 禁止了

禁止这个是微信官方要求的,为了防 XXE 攻击,看这里:
https://www.oschina.net/news/97878/jfinal-weixin-2-1-released

我不知道你的 XML 中为什么存在触发防止 XXE 攻击的部分代码

疑思静想

2019-06-10 10:48

@JFinal 我也很好奇之前都没有这种问题,就这个月遇到了这个问题,目前支付也能业务也正常运转只是偶尔包这个错误,很是难受

JFinal

2019-06-10 11:04

@疑思静想 你排查一下是不微信平台的安全检测

我也会定期收到这种异常,是因为我在微信支付平台打开了安全检测, 微信平台每隔一段时间会故意发送检测请求

检查办法,登录微信支付后台管理,也就是商户平台,进入《产品中心》频道,点击下方的《安全医生》,看一下安全医生有没有打开,如果打开了,则点击产品设计查看里面的配置

可以通过关闭这个《安全医生》去除安全检测,你就收不到这类异常了

这个机制本质就是平台对你的安全保护,如果你的业务流程中不出异常,那么这个是正常情况

疑思静想

2019-06-10 12:03

@JFinal 没有开启安全医生,最怕支付相关出问题,如果是自己写的代码问题那就要出大事,还好目前支付相关业务流程正常,不过有报错还是有点慌

JFinal

2019-06-10 12:20

@疑思静想 如果没有开启安全医生,你要确认一下这个信息是谁发来的,通过记录发送者 ip 地址来追踪一下

这里的关键是,你要搞清楚这些请求是微信平台发的,还是你自己发的,还是第三方发的

我怀疑是有不怀好意的人在搞破坏

如果你希望更快解决,可以尝试改一下微信平台的回调 URL,并且这个 URL 不要透露出去,那么攻击者就找不到这个攻击入口了

疑思静想

2019-06-10 13:51

@JFinal 恩,增加了日志,回调url也改了,过一段时间看看日志就大致清楚了

JFinal

2019-06-10 15:28

@疑思静想 url 要改成不好猜的那种,例如放点前缀进去: "/my/haha/weixin/payment/callback"

有一些搞破坏的会用程序去猜测你的回调 url ,猜这个比猜密码要容易多了

疑思静想

2019-06-10 17:18

@JFinal 如果真的有人搞破坏用程序去猜测回调url的话那设置复杂一点的url也只是时间问题,只要破解不了签名就影响不了业务,虽然有些担心

JFinal

2019-06-10 17:20

@疑思静想 搞复杂点被猜中的概率几乎为 0 ,就跟猜密码一样

疑思静想

2019-06-10 17:24

@JFinal 这样的吗,那行我弄一个6级复杂路由试试