C# winform在WebBrowser下获取完整的Cookies(包括含HTTPOnly属性的)

摘要:
使用wininet获取网页cookie,以模拟检索数据的post请求。使用普通cookie无法获得完整的cookie信息,但只能获得其中的一部分。因此,检索的是重新登录页面。WinInetWinInet API帮助程序员使用三种常见的Internet协议,即用于万维网的超文本传输协议、文件传输协议和另一种名为Gopher的文件传输协议。打开网页表单以添加webBrowser组件,并将其与this.webBrowser1.Document.Cookie进行比较。

利用wininet获取网页Cookie

模拟post请求取数据,使用普通的Cookies无法获取完整的Cookies信息 只能获取了一部分 ,导致取回来的是重新登陆的页面。

后来经过不懈的精神,终于找到了方法实现获取HTTPOnly。

WinInet

WinInet(“Windows Internet”)API帮助程序员使用三个常见的Internet协议,这三个协议是用于World Wide Web万维网的超文本传输协议(HTTP:Hypertext Transfer Protocol)、文件传输协议(FTP:File Transfer Protocol)和另一个称为Gopher的文件传输协议。
WinInet函数的语法与常用的Win32 API函数的语法类似,这使得使用这些协议就像使用本地硬盘上的文件一样容易。
1、WinInet 是一个网络编程接口,包含了 Internet 底层协议 HTTP,FTP。
2、借助 WinInet 接口,可不必去了解 Winsock、TCP/IP 和特定 Internet 协议
的细节就可以编写出高水平的 Internet 客户端程序。
3、WinInet 为 HTTP、FTP 提供了统一的函数集,也就是 Win32 API 接口。
4、WinInet 简化了 HTTP、FTP 协议的编程,可轻松地将 Internet 集成到应用程序中。

Cookie

cookie的概念与作用请查看该链接:
https://www.cnblogs.com/andy-zhou/p/5360107.html
只记录一下cookie与session的区别
Session是另一种记录客户状态的机制,不同的是Cookie保存在客户端浏览器中,而Session保存在服务器上。客户端浏览器访问服务器的时候,服务器把客户端信息以某种形式记录在服务器上。这就是Session。客户端浏览器再次访问时只需要从该Session中查找该客户的状态就可以了。

如果说Cookie机制是通过检查客户身上的“通行证”来确定客户身份的话,那么Session机制就是通过检查服务器上的“客户明细表”来确认客户身份。Session相当于程序在服务器上建立的一份客户档案,客户来访的时候只需要查询客户档案表就可以了。

实现

打开网页

窗体添加webBrowser组件,和和this.webBrowser1.Document.Cookie进行对比。

using System;
using System.ComponentModel;
using System.Net;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Windows.Forms;

namespace cookieTest
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        /// <summary>
        ///
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnOpen_Click(object sender, EventArgs e)
        {
            this.webBrowser1.Navigate(this.txt_url.Text);//打开网页
        }

        /// <summary>
        /// 和this.webBrowser1.Document.Cookie进行对比
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnGetCookies_Click(object sender, EventArgs e)
        {
            CookieContainer bwCookie = getCookie(this.webBrowser1.Document.Cookie);
            CookieContainer realCookie = getCookie(GetCookieString(this.txt_url.Text));///api获取

            textBox1.Text = "
 DocumentCookies(" + bwCookie.Count.ToString() + "):
" + this.webBrowser1.Document.Cookie + "
 "
                                        + "
拆分查看详情:
***" + bwCookie.GetCookieHeader(new Uri(this.txt_url.Text)).Replace(";", ";
***");

            textBox2.Text = "
 真实cookies(" + realCookie.Count.ToString() + "):
" + GetCookieString(this.txt_url.Text) + "
"
                              + "
拆分查看详情:
***" + realCookie.GetCookieHeader(new Uri(this.txt_url.Text)).Replace(";", ";
***");
        }

        /// <summary>
        /// Api返回cookie的string类型
        /// </summary>
        /// <param name="url"></param>
        /// <returns></returns>
        private static string GetCookieString(string url)
        {
            return FullWebBrowserCookie.GetCookieInternal(new Uri(url), true);
        }

        /// <summary>
        /// 按照格式以“;”分行,并以“=”来查看cookie的个数。
        /// </summary>
        /// <param name="cookieStr"></param>
        /// <returns></returns>
        public CookieContainer getCookie(string cookieStr)
        {
            CookieContainer myCookieContainer = new CookieContainer();
            string CurHost = new Uri(this.txt_url.Text).Host;
            //string cookieStr = webBrowser1.Document.Cookie;
            string[] cookstr = cookieStr.Split(';');

            string flag = "";
            foreach (string str in cookstr)
            {
                if (str.IndexOf("_saltkey") != -1)
                {
                    string[] cookieNameValue = str.Split('=');
                    flag = cookieNameValue[0].Replace("_saltkey", "").Trim();
                }
            }
            //
            //MessageBox.Show(flag);
            //flag = "";
            myCookieContainer.PerDomainCapacity = 40;

            foreach (string str in cookstr)
            {
                try
                {
                    string[] cookieNameValue = str.Split('=');
                    string strvalue = cookieNameValue[1].Trim().ToString().Replace(",", "%2C");
                    strvalue = str.Replace(cookieNameValue[0] + "=", "");
                    strvalue = strvalue.Trim().ToString().Replace(",", "%2C");

                    Cookie ck = new Cookie(cookieNameValue[0].Trim().ToString(), strvalue);
                    ck.Domain = CurHost;
                    myCookieContainer.Add(ck);
                }
                catch (Exception ex) { MessageBox.Show(ex.Message + ">>
" + cookieStr); }
            }

            return myCookieContainer;
        }

        private void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
        {
            if (webBrowser1.Url.ToString() != txt_url.Text.Trim())
            {
                if (MessageBox.Show("已经登录,是否关闭此窗口", "退出窗口", MessageBoxButtons.OKCancel) == DialogResult.OK)
                {
                    this.Close();
                }
            }
        }
    }

    /// <summary>
    /// 利用在浏览器地址栏输入javascript:alert (document. cookie)的方法取不到HttpOnly的cookie,所以使用wininetAPI能够取得完整cookie并且可以根据你想要的格式返回给你。
    /// 构造获取cookie的类,首先把url转为string,获取访问url的权限,然后利用wininet下的InternetGetCookieEx获取cookie,返回为string格式。
    /// </summary>
    public class FullWebBrowserCookie
    {
        /// <summary>
        /// 从托管代码中访问非托管DLL函数之前,需要知道该函数的名称以及该DLL的名称,然后为DLL的非托管函数编写托管定义。
        ///它将用到static和extern修饰符,此类型的公共静态成员对于多线程操作是安全的。DllImport属性提供非托管DLL函数的调用信息。
        /// </summary>
        internal sealed class NativeMethods
        {
            #region enums

            public enum ErrorFlags
            {
                ERROR_INSUFFICIENT_BUFFER = 122,
                ERROR_INVALID_PARAMETER = 87,
                ERROR_NO_MORE_ITEMS = 259
            }

            public enum InternetFlags
            {
                INTERNET_COOKIE_HTTPONLY = 8192, //Requires IE 8 or higher
                INTERNET_COOKIE_THIRD_PARTY = 131072,
                INTERNET_FLAG_RESTRICTED_ZONE = 16
            }

            #endregion enums

            #region DLL Imports

            [SuppressUnmanagedCodeSecurity, SecurityCritical, DllImport("wininet.dll", EntryPoint = "InternetGetCookieExW", CharSet = CharSet.Unicode, SetLastError = true, ExactSpelling = true)]
            internal static extern bool InternetGetCookieEx([In] string Url, [In] string cookieName, [Out] StringBuilder cookieData, [In, Out] ref uint pchCookieData, uint flags, IntPtr reserved);

            #endregion DLL Imports
        }

        [SecurityCritical]
        public static string GetCookieInternal(Uri uri, bool throwIfNoCookie)
        {
            uint pchCookieData = 0;
            string url = UriToString(uri);
            uint flag = (uint)NativeMethods.InternetFlags.INTERNET_COOKIE_HTTPONLY;

            //获取 string builder的大小
            if (NativeMethods.InternetGetCookieEx(url, null, null, ref pchCookieData, flag, IntPtr.Zero))
            {
                pchCookieData++;
                StringBuilder cookieData = new StringBuilder((int)pchCookieData);

                //读取cookie
                if (NativeMethods.InternetGetCookieEx(url, null, cookieData, ref pchCookieData, flag, IntPtr.Zero))
                {
                    DemandWebPermission(uri);
                    return cookieData.ToString();
                }
            }
            //返回由上一个非托管函数返回的错误代码调用的dll文件函数
            int lastErrorCode = Marshal.GetLastWin32Error();

            if (throwIfNoCookie || (lastErrorCode != (int)NativeMethods.ErrorFlags.ERROR_NO_MORE_ITEMS))
            {
                throw new Win32Exception(lastErrorCode);
            }

            return null;
        }

        private static void DemandWebPermission(Uri uri)
        {
            string uriString = UriToString(uri);

            if (uri.IsFile)
            {
                string localPath = uri.LocalPath;
                new FileIOPermission(FileIOPermissionAccess.Read, localPath).Demand();
                //如果未对调用堆栈中处于较高位置的所有调用方授予当前实例所指定的权限,则在运行时强制SecurityException
            }
            else
            {
                new WebPermission(NetworkAccess.Connect, uriString).Demand();
            }
        }

        //URI转string
        private static string UriToString(Uri uri)
        {
            if (uri == null)
            {
                throw new ArgumentNullException("uri");
            }

            UriComponents components = (uri.IsAbsoluteUri ? UriComponents.AbsoluteUri : UriComponents.SerializationInfoString);//获取绝对url
            return new StringBuilder(uri.GetComponents(components, UriFormat.SafeUnescaped), 2083).ToString();
        }
    }
}

image

详细介绍:

C#利用wininet获取网页Cookie_勤能补拙-CSDN博客

免责声明:文章转载自《C# winform在WebBrowser下获取完整的Cookies(包括含HTTPOnly属性的)》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇C# 配置文件读取与修改侦测卡 变色龙侦测卡 chameleon-Mini(迷你变色龙) (二)下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

大文件上传 之 改版了的SlickUpload.HttpUploadModule(Krystalware.SlickUpload.dll)

以下代码中所注释的部分是所改版的地方。:)Krystalware.SlickUpload.dll/Files/bigmouthz/SlickUpload.rar------------------------------------------------------using System;using System.Collections;using S...

Golang的高级数据类型-切片(slice)实战篇

          Golang的高级数据类型-切片(slice)实战篇                              作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任。        切片(slice)是Go中一种比较特殊的数据结构,这种数据结构更便于使用和管理数据集合,切片是围绕动态数组的概念构建的,可以按需自动增长。   ...

Nginx跨域及Https配置

一、跨域 1. 什么是跨域? 跨域:指的是浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的,是浏览器对javascript施加的安全限制(指一个域下的文档或脚本试图去请求另一个域下的资源,这里跨域是广义的) 例如:a页面想获取b页面资源,如果a、b页面的协议、域名、端口、子域名不同,所进行的访问行动都是跨域的,而浏览器为了安全问题一般都限制了跨域...

stream流 list转map

package com.mayikt.stream; import com.mayikt.entity.UserEntity; import java.util.ArrayList; import java.util.Map; import java.util.function.BiConsumer; import java.util.functio...

Java 关于中文乱码处理的经验总结【转载】

为什么说乱码是中国程序员无法避免的话题呢?这个首先要从编码机制上说起,大家都是中文和英文的编码格式不是一样,解码也是不一样的!如果中国的程序员不会遇到乱码,那么只有使用汉语编程。汉语编程是怎么回事我也不大清楚,应该是前年吧,我一朋友给我介绍汉语编程,怎么不错不错?当时因为学习忙没去关注这个,等我闲了,那个朋友不弄这个,问他他也不说不大清楚,最后自己对这个学...

StackExchange.Redis.DLL 操作redis加强版

直接引用StackExchange.Redis.dll这一个dll来操作redis App.config配置 <?xml version="1.0" encoding="utf-8" ?> <configuration> <startup> <supportedRuntime...