WinInet:HTTPS 请求出现无效的证书颁发机构的处理

     首先,微软提供的WinInet库封装了对网页访问的方法。

     最近工作需要从https服务器获取数据,都知道https和http网页的访问方式不同,多了一道证书认证程序,这样就使得https在请求起来比http要复杂的多;好在,WinInet库中提供了对https网页请求的处理,这样就不需要在使用openssl中的一些方法来复杂化程序了。

     下面贴上我的解决前的代码,再对比我遇到问题之后的代码,在通过实际遇到的问题和环境来阐述:

  解决前代码:

#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <fstream>
#include "Windows.h"
#include "wininet.h"
using namespace std;
//链接需要 wininet.lib
#pragma comment(lib,"wininet.lib")
int main(int argc, char* argv[])
{LPCTSTR lpszAgent = "WinInetGet/0.1";//初始化HINTERNET hInternet = InternetOpen(lpszAgent,INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);LPCTSTR lpszServerName = "data.btcchina.com";//"ssl.google-analytics.com"; //设置serverINTERNET_PORT nServerPort = INTERNET_DEFAULT_HTTPS_PORT; // HTTPS端口443LPCTSTR lpszUserName = NULL; //无登录用户名LPCTSTR lpszPassword = NULL; //无登录密码DWORD dwConnectFlags = 0;DWORD dwConnectContext = 0;//连接HINTERNET hConnect = InternetConnect(hInternet,lpszServerName, nServerPort,lpszUserName, lpszPassword,INTERNET_SERVICE_HTTP,dwConnectFlags, dwConnectContext);//使用GetLPCTSTR lpszVerb = "GET";LPCTSTR lpszObjectName = "/data/ticker";LPCTSTR lpszVersion = NULL;    // 默认.LPCTSTR lpszReferrer = NULL;   // 没有引用页LPCTSTR *lplpszAcceptTypes = NULL; // Accpet所有类型.DWORD dwOpenRequestFlags = INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTP |INTERNET_FLAG_KEEP_CONNECTION |INTERNET_FLAG_NO_AUTH |INTERNET_FLAG_NO_COOKIES |INTERNET_FLAG_NO_UI |//设置启用HTTPSINTERNET_FLAG_SECURE |INTERNET_FLAG_RELOAD;DWORD dwOpenRequestContext = 0;//初始化RequestHINTERNET hRequest = HttpOpenRequest(hConnect, lpszVerb, lpszObjectName, lpszVersion,lpszReferrer, lplpszAcceptTypes,dwOpenRequestFlags, dwOpenRequestContext);//发送Request
HttpSendRequest(hRequest, NULL, 0, NULL, 0); 
//获得HTTP Response Header信息DWORD dwInfoLevel = HTTP_QUERY_RAW_HEADERS_CRLF;DWORD dwInfoBufferLength = 2048;BYTE *pInfoBuffer = (BYTE *)malloc(dwInfoBufferLength + 2);while(!HttpQueryInfo(hRequest, dwInfoLevel, pInfoBuffer, &dwInfoBufferLength, NULL)) {DWORD dwError = GetLastError();if(dwError == ERROR_INSUFFICIENT_BUFFER) {free(pInfoBuffer);pInfoBuffer = (BYTE *)malloc(dwInfoBufferLength + 2);} else {fprintf(stderr, "HttpQueryInfo failed, error = %d (0x%x)/n",GetLastError(), GetLastError());break;}}pInfoBuffer[dwInfoBufferLength] = '/0';pInfoBuffer[dwInfoBufferLength + 1] = '/0';printf("%S", pInfoBuffer); //很奇怪HttpQueryInfo保存的格式是wchar_t 和下面的InternetReadFile不一样 free(pInfoBuffer);//HTTP Response 的 Body, 需要的内容就在里面 DWORD dwBytesAvailable;while(InternetQueryDataAvailable(hRequest, &dwBytesAvailable, 0, 0)) {BYTE *pMessageBody = (BYTE *)malloc(dwBytesAvailable + 1);DWORD dwBytesRead;BOOL bResult = InternetReadFile(hRequest, pMessageBody,dwBytesAvailable, &dwBytesRead);if(!bResult) {fprintf(stderr, "InternetReadFile failed, error = %d (0x%x)/n",GetLastError(), GetLastError());break;}if(dwBytesRead == 0)break; // End of File.pMessageBody[dwBytesRead] = '/0';printf("%s", pMessageBody); //InternetReadFile读出来的是普通的char. InternetReadFileEx 似乎是有宽字节版本的 ofstream out("ofs.txt");std::string s = (char *)pMessageBody;out << s.c_str()<< endl;free(pMessageBody);}getchar(); }

  解决后代码:

#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <fstream>
#include "Windows.h"
#include "wininet.h"using namespace std;
//链接需要 wininet.lib
#pragma comment(lib,"wininet.lib")int main(int argc, char* argv[])
{LPCTSTR lpszAgent = "WinInetGet/0.1";//初始化HINTERNET hInternet = InternetOpen(lpszAgent,INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);LPCTSTR lpszServerName = "data.btcchina.com";//"ssl.google-analytics.com"; //设置serverINTERNET_PORT nServerPort = INTERNET_DEFAULT_HTTPS_PORT; // HTTPS端口443LPCTSTR lpszUserName = NULL; //无登录用户名LPCTSTR lpszPassword = NULL; //无登录密码DWORD dwConnectFlags = 0;DWORD dwConnectContext = 0;//连接HINTERNET hConnect = InternetConnect(hInternet,lpszServerName, nServerPort,lpszUserName, lpszPassword,INTERNET_SERVICE_HTTP,dwConnectFlags, dwConnectContext);//使用GetLPCTSTR lpszVerb = "GET";LPCTSTR lpszObjectName = "/data/ticker";LPCTSTR lpszVersion = NULL;    // 默认.LPCTSTR lpszReferrer = NULL;   // 没有引用页LPCTSTR *lplpszAcceptTypes = NULL; // Accpet所有类型.DWORD dwOpenRequestFlags = INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTP |INTERNET_FLAG_KEEP_CONNECTION |INTERNET_FLAG_NO_AUTH |INTERNET_FLAG_NO_COOKIES |INTERNET_FLAG_NO_UI |//设置启用HTTPSINTERNET_FLAG_SECURE |INTERNET_FLAG_RELOAD;DWORD dwOpenRequestContext = 0;//初始化RequestHINTERNET hRequest = HttpOpenRequest(hConnect, lpszVerb, lpszObjectName, lpszVersion,lpszReferrer, lplpszAcceptTypes,dwOpenRequestFlags, dwOpenRequestContext);//发送Request
again:DWORD dwError = 0;if (!HttpSendRequest(hRequest, NULL, 0, NULL, 0)){dwError = GetLastError();}if (dwError == ERROR_INTERNET_INVALID_CA){fprintf(stderr, "HttpSendRequest failed, error = %d (0x%x)/n",dwError, dwError );DWORD dwFlags;DWORD dwBuffLen = sizeof(dwFlags);InternetQueryOption(hRequest, INTERNET_OPTION_SECURITY_FLAGS,(LPVOID)&dwFlags, &dwBuffLen);dwFlags |= SECURITY_FLAG_IGNORE_UNKNOWN_CA;InternetSetOption (hRequest, INTERNET_OPTION_SECURITY_FLAGS,&dwFlags, sizeof(dwFlags));goto again;}//获得HTTP Response Header信息DWORD dwInfoLevel = HTTP_QUERY_RAW_HEADERS_CRLF;DWORD dwInfoBufferLength = 2048;BYTE *pInfoBuffer = (BYTE *)malloc(dwInfoBufferLength + 2);while(!HttpQueryInfo(hRequest, dwInfoLevel, pInfoBuffer, &dwInfoBufferLength, NULL)) {DWORD dwError = GetLastError();if(dwError == ERROR_INSUFFICIENT_BUFFER) {free(pInfoBuffer);pInfoBuffer = (BYTE *)malloc(dwInfoBufferLength + 2);} else {fprintf(stderr, "HttpQueryInfo failed, error = %d (0x%x)/n",GetLastError(), GetLastError());break;}}pInfoBuffer[dwInfoBufferLength] = '/0';pInfoBuffer[dwInfoBufferLength + 1] = '/0';printf("%S", pInfoBuffer); //很奇怪HttpQueryInfo保存的格式是wchar_t 和下面的InternetReadFile不一样
    free(pInfoBuffer);//HTTP Response 的 Body, 需要的内容就在里面
    DWORD dwBytesAvailable;while(InternetQueryDataAvailable(hRequest, &dwBytesAvailable, 0, 0)) {BYTE *pMessageBody = (BYTE *)malloc(dwBytesAvailable + 1);DWORD dwBytesRead;BOOL bResult = InternetReadFile(hRequest, pMessageBody,dwBytesAvailable, &dwBytesRead);if(!bResult) {fprintf(stderr, "InternetReadFile failed, error = %d (0x%x)/n",GetLastError(), GetLastError());break;}if(dwBytesRead == 0)break; // End of File.pMessageBody[dwBytesRead] = '/0';printf("%s", pMessageBody); //InternetReadFile读出来的是普通的char. InternetReadFileEx 似乎是有宽字节版本的
ofstream out("ofs.txt");std::string s = (char *)pMessageBody;out << s.c_str()<< endl;free(pMessageBody);}getchar();
}

 

    大家看到HttpOpenRequest这个函数中,dwOpenRequestFlag参数:

    DWORD dwOpenRequestFlags = INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTP |INTERNET_FLAG_KEEP_CONNECTION |INTERNET_FLAG_NO_AUTH |INTERNET_FLAG_NO_COOKIES |INTERNET_FLAG_NO_UI |//设置启用HTTPSINTERNET_FLAG_SECURE |INTERNET_FLAG_RELOAD;

要request到https网页的数据,INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTP和INTERNET_FLAG_SECURE两个选项要设置。

  从上面的前后两段代码,大家应该能看到逻辑的变化在哪里,就在于HttpSendRequest这个函数的返回值的处理上。

    看HttpSendRequest这层逻辑的处理,你会好奇为什么要用到这样的逻辑呢?答案其实并不是那么好告诉你的,因为,这样设置逻辑是因为微软当时在设计这个库的时候留下的一个漏洞。

  因为,https协议涉及到证书认证问题,而IE低版本内核的浏览器打开你要请求的https Url的时候,会出现证书认证失败,(比如我这里的:btc.china.com/data/ticker),而高级版本的浏览器可能就不会有任何问题。

  在解决问题前,我的环境是Win7系统,IE10浏览器,在我运行程序的时候一切正常,能正常获取到程序,浏览器也能打开网页看到网页上的数据,但是当我把程序发布release然后交给运维测试的时候,他那边环境是(win server 2003, IE7环境),这就出现了问题,他那边获取不到那个请求https网站的数据,于是我建议他们按照步骤通过浏览器端安装该网站的认证证书,安装之后浏览器可以看到数据,但是运行程序并不能正常获得数据,这就是我的问题所在。

  于是,就问Google大婶们,无果,所以只有解铃还须系铃人了,遂到微软的问题解决网站寻求帮助,结果,查出来这是微软设计的一个缺陷,但是他们给出了很好的解决办法,那就是忽略证书认证。

微软解决办法:http://support.microsoft.com/kb/182888/zh-cn

  考虑到有的时候,有些人会打不开微软的这个网站,我在这里把他复制粘贴出来,如下:

客户端不知道有关颁发服务器证书的证书颁发机构时,就会发生此错误。通过安装证书颁发机构的根证书,问题可能得到解决。可以从 Internet Explorer 查看所有已安装的证书列表。从视图菜单上,单击 Internet 选项,单击内容选项卡,单击机构。很可能绕过此 WinInet 应用程序中的错误,而不安装证书。有两种方法来处理该错误。您可以使用类似于以下示例的代码。方法 1。与用户界面 (生成类似于 Internet Explorer 的消息框):...Again:if (!HttpSendRequest (hReq,...))dwError = GetLastError ();if (dwError == ERROR_INTERNET_INVALID_CA){// Make sure to check return code from InternetErrorDlg// user may click either OK or Cancel. In case of Cancel// request should not be resumbitted.
       InternetErrorDlg (GetDesktopWindow(),hReq,ERROR_INTERNET_INVALID_CA,FLAGS_ERROR_UI_FILTER_FOR_ERRORS |FLAGS_ERROR_UI_FLAGS_GENERATE_DATA |FLAGS_ERROR_UI_FLAGS_CHANGE_OPTIONS,NULL);goto again;}...方法 2。而无需用户界面:...Again:if (!HttpSendRequest (hReq,...))dwError = GetLastError ();if (dwError == ERROR_INTERNET_INVALID_CA){DWORD dwFlags;DWORD dwBuffLen = sizeof(dwFlags);InternetQueryOption (hReq, INTERNET_OPTION_SECURITY_FLAGS,(LPVOID)&dwFlags, &dwBuffLen);dwFlags |= SECURITY_FLAG_IGNORE_UNKNOWN_CA;InternetSetOption (hReq, INTERNET_OPTION_SECURITY_FLAGS,&dwFlags, sizeof (dwFlags) );goto again;}...与 MFC WinInet 类可以使用相似的逻辑。在这种情况下,下列 MFC 方法对应于 WinInet 上面使用的 Api:CInternetFile::SendRequest
CInternetFile::QueryOption
CInternetFile::SetOption
CInternetFile::ErrorDlg
请注意缺少 Visual C++ 5.0 CInternetFile::ErrorDlg,CInternetFile::QueryOption 和 CInternetFile::SetOption 上的文档。请参阅 Inet.cpp MFC 源代码文件的信息如何使用此方法。注 1: InternetErrorDlg 可能会返回下列值:ERROR_SUCCESSERROR_CANCELLEDERROR_INTERNET_FORCE_RETRY.仅当返回 ERROR_INTERNET_FORCE_RETRY 时,才应重新提交请求。在 Internet Explorer 4.04.01 中,但是,该请求必须重新提交即使 ERROR_SUCCESS 将返回。Microsoft 已经确认这是 InternetErrorDlg API 中的问题。注 2: SECURITY_FLAG_IGNORE_UNKNOWN_CA 在 Internet Explorer 3.03.02 未实现。InternetErrorDlg 仍然起作用,但有以下例外。此 api 生成对话框中不允许忽略无效的证书颁发机构的错误 ;它是只是通知页该用户不能查看。注 3: 在错误发生之前,不能设置选项,将忽略此错误。您首先必须尝试发送请求、 收到错误消息,然后设置选项 (或调用 InternetErrorDlg),然后重新提交。
View Code

 

  我用的是提供的第二个方法无用户界面的解决方法。然后这样大家应该就会明白我那里的处理逻辑为啥会那个样子了。

  好了,问题就是这个样子了,我的问题解决了,你的呢?

 

转载于:https://www.cnblogs.com/foundwant/p/3453963.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/493658.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

热度下的冷思考——智能眼镜到底有没有前途?

来源&#xff1a;环球网我们曾期望Google眼镜能够成为革命性的新产品&#xff0c;因为它某种程度上实现了大家对未来的幻想。然而Google眼镜作为概念产品虽然有趣&#xff0c;但它仍然太不成熟&#xff0c;而且因为存在侵犯隐私的可能还被大众抵触&#xff0c;更重要的是它花去…

TFRecords文件的存储与读取

将cats和dogs两个文件夹各1000张图片存储为&#xff1a;train.tfrecords#将图片文件生成train record import os import tensorflow as tf from PIL import Image #生成cats和dogs的record文件 path./data/train filenamesos.listdir(path) writertf.python_io.TFRecordWriter(…

对比激光SLAM与视觉SLAM:谁会成为未来主流趋势?

来源&#xff1a;智车科技摘要&#xff1a;SLAM&#xff08;同步定位与地图构建&#xff09;&#xff0c;是指运动物体根据传感器的信息&#xff0c;一边计算自身位置&#xff0c;一边构建环境地图的过程&#xff0c;解决机器人等在未知环境下运动时的定位与地图构建问题。目前…

链表中的指针

中期答辩改在了国庆之后&#xff0c;终于有时间可以看看剑指offer了。在看到单向链表的部分&#xff0c;对指针&#xff0c;尤其是头指针有点疑惑。首先容易理解的是链表的节点是一个结构体&#xff0c;该结构体包含一个数据&#xff08;一般是int型&#xff09;&#xff0c;还…

实现TFrecords文件的保存与读取

import os import cv2 import numpy as np import tensorflow as tf """ 将train文件夹下的cats和dog文件夹处理成train.tfrecords放在train文件夹里 """ #将图片的路径和对应的标签存储在list中返回 def deal(dir):images []temp []for root,…

工具推荐-css3渐变生成工具

今天工作用到了css3渐变&#xff0c;但是写起来才发现太麻烦了&#xff0c;而却很浪费时间&#xff0c;所以在这里向大家推荐一个在线的css3 渐变生成工具 地址是&#xff1a;http://www.colorzilla.com/gradient-editor/ 这个工具是可视化视图&#xff0c;用起来就和photoshop…

神经网络相关的笔试题目集合(一)

在找工作的过程中发现好多公司没有专门的、传统的图像处理岗位&#xff0c;所以只能参加算法类的笔试甚至AI类的笔试。在AI的笔试中几乎全是关于神经网络的问题&#xff0c;其实也都是很基础的一些问题&#xff0c;如果事先做了准备&#xff0c;可以从容应对。而对于我这种从传…

中美超算“你追我赶” 中国优势可圈可点

来源&#xff1a;新华网摘要&#xff1a;中美超算“你追我赶” 中国优势可圈可点新一期全球超级计算机&#xff15;&#xff10;&#xff10;强榜单&#xff11;&#xff12;日在美国达拉斯发布。与半年前的榜单相比&#xff0c;全球格局变化不大&#xff0c;美国在最快超算上…

吴恩达作业1:逻辑回归实现猫的分类

思路&#xff1a;输入样本X与随机初始权重W相乘&#xff0c;利用sigmoid激活函数输出值&#xff0c;对于二分类问题&#xff0c;用交叉熵损失函数来计算损失值&#xff0c;通过交叉熵损失函数利用链式法则求出W和b的偏导&#xff0c;梯度下降更新W和b即可&#xff0c;&#xff…

双摄与双目视觉

越来越多的手机开始上双摄&#xff0c;首先解释一下双摄的目的&#xff0c;双摄可以达到什么样的效果。首先双摄可以分为两类&#xff0c;一类是利用双摄获得图像中物体到镜头或者焦距的距离&#xff0c;得到景深信息就可以进行后续的3D重建、图像分割、背景虚化等&#xff1b;…

“脑补”的科学依据:眼前的黑不是黑,靠得是你的大脑

一个在眨眼的婴儿 | 图片来源&#xff1a;Leungcho Pan/Shutterstock撰文&#xff1a;Mindy Weisberger来源&#xff1a;科研圈编译&#xff1a;向菲菲人们常说&#xff1a;“别眨眼&#xff0c;精彩稍纵即逝。”但其实在我们眨眼的时候&#xff0c;精彩仍在我们眼前上演。我们…

基于Sql Server 2008的分布式数据库的实践(三)

配置PHP 1.打开PHP配置文件&#xff0c;找到extensionphp_mssql.dll&#xff0c;将前面的注释符号去掉 2.找到mssql.secure_connection&#xff0c;将Off改为On 3.找到com.allow_dcom true&#xff0c;将前面的注释符号去掉 4.下载正确版本的 ntwdblib.dll (2000.80.194.0)&am…

ORB论文研读与代码实现

首先&#xff0c;ORB算法来自于OpenCV Labs&#xff0c;相比于SIFT和SURF&#xff0c;ORB在使用中不必担心专利的问题。但同时ORB在保证了一定性能的条件下做到了高效。在论文《ORB: An efficient alternative to SIFT or SURF》2011中&#xff0c;ORB在特征点检测和描述子生成…

腾讯发布人工智能辅助翻译,致敬人工翻译

来源&#xff1a;腾讯AI实验室11月13日&#xff0c;深圳 - 腾讯AI Lab今日发布了一款AI辅助翻译产品 - “腾讯辅助翻译”&#xff08;Transmart&#xff09;&#xff0c;可满足用户快速翻译的需求&#xff0c;用AI辅助人工翻译提高效率和质量。该产品采用业内领先的人机交互式机…

吴恩达作业2 利用两层神经网络实现不同颜色点的分类,可更改隐藏层数量

任务&#xff1a;将400个两种颜色的点用背景色分为两类。 前面的还是建议重点学神经网络知识&#xff0c;至于数据集怎么做的后面在深究&#xff0c;首先先看看数据集&#xff0c;代码如下&#xff1a; def load_planar_dataset():np.random.seed(1)m 400 # number of exampl…

利用tensorflow构建AlexNet模型,实现小数量级的猫狗分类(只有train)

首先看路径&#xff1a; data文件夹分为&#xff0c;model文件夹&#xff0c;train文件夹和文件夹&#xff0c;model文件夹存放模型文件&#xff0c;train存放cat和dog的两个文件夹图片&#xff0c; validation和train一样。config.py存放配置的一些参数&#xff0c;util.py定…

脑网络的可塑性——随时都在发生

来源&#xff1a;神经科技前沿神经元的突起是神经元胞体的延伸部分&#xff0c;由于形态结构和功能的不同&#xff0c;可分为树突(dendrite)和轴突(axon)&#xff1b;树突是从胞体发出的一至多个突起&#xff0c;呈放射状。轴突每个神经元只有一根胞体发出轴突的细胞 质部位多呈…

KAZE论文研读

KAZE是发表在ECCV2012的一种特征点检测算法&#xff0c;相比于SIFT和SURF&#xff0c;KAZE建立的高斯金字塔是非线性的尺度空间&#xff0c;采用加性算子分裂算法(Additive Operator Splitting, AOS)来进行非线性扩散滤波。一个很显著的特点是在模糊图像的同时还能保留边缘细节…

简单的线性模型实现tensorflow权重的生成和调用,并且用类的方式实现参数共享

首先看文件路径&#xff0c;line_regression是总文件夹&#xff0c;model文件夹存放权重文件&#xff0c; global_variable.py写了一句话. save_path./model/weight 权重要存放的路径&#xff0c;以weight命名. lineRegulation_model.py代码 import tensorflow as tf "…

comparing ORB and AKAZE

文章全称是《Comparing ORB and AKAZE for visual odometry of unmanned aerial vehicles》。这是一篇来自巴西的文章&#xff0c;没有在百度文库中找到&#xff0c;是在其他博客中给出的链接得到的。从链接的URL可以看出这是一篇来自会议CCIS云计算与智能系统国际会议的文章。…