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


利用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 = "\r\n DocumentCookies(" + bwCookie.Count.ToString() + "):\r\n" + this.webBrowser1.Document.Cookie + "\r\n "
                                        + "\r\n拆分查看詳情:\r\n***" + bwCookie.GetCookieHeader(new Uri(this.txt_url.Text)).Replace(";", ";\r\n***");

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

        /// <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 + ">>\r\n" + 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博客


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM