不理解为什么WinHTTP不验证某些HTTPS资源

时间:2013-01-06 17:49:26

标签: vba authentication https winhttp

我非常感谢任何可以帮助我解决问题的帮助。

从Excel VBA代码我需要下载&从HTTPS站点https://redmine.itransition.com/解析CSV文件。我尝试使用WinHTTP来获取文件。但是,我无法理解为什么身份验证不起作用。以下是相关代码:

TargetURL = "https://redmine.itransition.com/projects/pmct/time_entries.csv"
Set HTTPReq = CreateObject("WinHttp.WinHttpRequest.5.1")
HTTPReq.Option(4) = 13056 ' WinHttpRequestOption_SslErrorIgnoreFlags 13056: ignore all err, 0: accept no err
HTTPReq.Open "GET", TargetURL, False
HTTPReq.SetCredentials "UN", "PW", 0
HTTPReq.send

返回以下响应(仅列出某些字符串):

Content-Type: text/html; charset=utf-8
Status: 406
X-Runtime: 5

但是,如果我使用

成功进行手动验证后从Firefox cookie发送“Cookie”字符串
HTTPReq.setRequestHeader "Cookie", SetCookieString
HTTPReq.send

我很容易得到预期的文件。当然,我对这种解决方案不满意,并希望执行真正的WinHTTP身份验证。但是,我无法理解我的代码中出错了什么或错过了什么。我很可能必须使用.SetClientCertificate方法,但这对我来说还不清楚 - 需要哪个证书?

或者,更一般:我应该使用哪些WinHTTP方法或函数进行调试,以找出哪个步骤阻塞/不正确并阻止我进行正确的身份验证?我花了两周时间通过MSDN和各种资源寻求帮助,但仍然没有解决方案。

提前感谢您的建议!

3 个答案:

答案 0 :(得分:6)

以上的@Alex K.响应正是我所寻找的那么久! 在Firebug和MSDN的帮助下,我完成了3个请求:

  • 使用RegEx
  • 获取从登录页面收集authenticity_token数据的请求
  • POST请求进行身份验证&从响应中收集必需的Cookie字符串
  • 获取最终获得我心爱的CSV的请求

以下代码正在按预期工作:

Set RegX_AuthToken = CreateObject("VBScript.RegExp")
' Below Pattern w/o double-quotes encoded: (?:input name="authenticity_token" type="hidden" value=")(.*)(?:")
RegX_AuthToken.Pattern = "(?:input name=" & Chr(34) & "authenticity_token" & Chr(34) & " type=" & Chr(34) & "hidden" & Chr(34) & " value=" & Chr(34) & ")(.*)(?:" & Chr(34) & ")"
RegX_AuthToken.IgnoreCase = True
RegX_AuthToken.Global = True

TargetURL = "https://redmine.itransition.com/login"

Set HTTPReq = CreateObject("WinHttp.WinHttpRequest.5.1")
HTTPReq.Open "GET", TargetURL, False
HTTPReq.Send

Set Token_Match = RegX_AuthToken.Execute(HTTPReq.ResponseText)
AuthToken = Token_Match.Item(0).SubMatches.Item(0)

PostData = "authenticity_token=" & AuthToken & "&back_url=https://redmine.itransition.com/" & "&username=" & UN & "&password=" & PW & "&login=Login »"

HTTPReq.Open "POST", TargetURL, False
HTTPReq.setRequestHeader "Content-Type", "application/x-www-form-urlencoded"
HTTPReq.Send (PostData)

SetCookieString = HTTPReq.GetResponseHeader("Set-Cookie")

TargetURL = "https://redmine.itransition.com/projects/pmct/time_entries.csv"
HTTPReq.Open "GET", TargetURL, False
HTTPReq.setRequestHeader "Cookie", SetCookieString
HTTPReq.Send

以下网址有助于构建POST请求:http://tkang.blogspot.com/2010/09/sending-http-post-request-with-vba.html

  

您需要加载没有凭据的页面,抓住看起来像   来自生成的形式&的volatile字段authenticity_token。岗位   这与用户名和&密码到/登录。

Alex K. - 再次感谢这个精彩的建议! (:

答案 1 :(得分:3)

https://redmine.itransition.com/上的登录只是一个发布用户名&的HTML表单。密码到/login的脚本。

这与基于服务器的身份验证方案(如basic / digest / ntlm)设计的SetCredentials不兼容。

您需要在没有凭据的情况下加载该页面,从生成的表单中获取类似于volatile字段authenticity_token的内容。发布与用户名和&密码到/login

如果它是基于会话的系统,它将使用您需要在后续请求中使用的set-cookie标头+数据进行响应。

答案 2 :(得分:0)

还有一件事(除上述解决方案外),在使用类似于上述代码的POST请求时应该注意:出于某些不明原因,我仍然有4-5次(甚至更多)来自网站的讨厌的406响应,这意味着在我的情况下身份验证不完整。经过几个小时的逐步调试后,我很高兴地找到了原因:auth令牌值可能有+个标志,并且通过分析几十个auth令牌/响应代码的箭头,我发现+ - 包含令牌与406码完全匹配。

解决方案变得非常明显:为+安全地对PostData进行网址编码。在http://www.blooberry.com/indexdot/html/topics/urlencoding.htm的帮助下,我终于找到了以下内容:

PostData = "authenticity_token=" & Replace(AuthToken, "+", "%2B", vbTextCompare) & _
    "&back_url=https://redmine.itransition.com/projects/" & Trim(RedmineProject) & _
    "/time_entries" & "&username=" & UN & "&password=" & PW & "&login=Login »"

+%2B替换,这就是 - 不再是406s!)

其他特殊字符在我的情况下并不重要,但是吸取了教训。希望这能为其他人节省几个小时的生命!