脚本登录到Apache服务器突然失败

时间:2018-03-12 15:46:44

标签: apache dotnet-httpclient

多年来,我一直在使用C#程序来编写#34;脚本"登录FedEx的服务器下载我公司的发票。该程序只是模仿浏览器通常发送的URL / Headers / Cookies / Post数据,以便与FedEx服务器连接,登录,"导航"到下载页面,然后下拉发票。

上周我开始接受401(未经授权),当程序制作了#Aj;" Ajax"呼叫登录。我比较了我的所有标题,cookie和发布数据,它们与浏览器发送的内容完全匹配。不知何故,他们的Apache服务器没有看到我的编程请求与浏览器的请求相同。本周末,它从401变为简单地返回HTML,并显示有关未获得许可的消息。

我花了很多时间在两个调用(浏览器和代码)上检查小提琴检查员,我找不到任何会触发Apache服务器拒绝我的程序请求的东西,而不是浏览器'秒。两者都使用TLS 1.2。浏览器确实运行JavaScript,当然,他们的主页确实会创建一些cookie,但作为测试,我在网页上的ajax调用之前删除了JS创建的cookie(因此它们不会被发送,所以我们会这样做两者都发送相同的cookie - 只是不同的值,因为我们在不同的会话中返回从服务器发送的cookie,并且它仍然通过浏览器进行身份验证。

所以,我的问题是,除了请求标题(包括cookie)和发布数据之外,我还应该寻找什么才能使我的程序看起来像浏览器?如果有人想试一试,主页为https://www.fedex.com/en-us/home.html,您可以使用id / pass字段中的任何内容进行测试(单击右上角的“登录”按钮)。使用浏览器时,即使假冒的id / pass组合也会返回JSON(只是说Success = false),而程序化的调用则返回HTML,而#34;您无权查看此网页&#34 34;错误。

我的程序使用HTTPClient .Net类,我手动编写标题和cookie(我不使用CookieContainer,因为它似乎忽略了一些完全有效的set-cookie有时)。 / p>

using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace HTTPClient
{
    public class Fed
    {
        HttpClient client;
        public Fed(string host)
        {
            Uri uri = new Uri(host);
            client = new HttpClient(new HttpClientHandler() { UseCookies = false })
            {
                BaseAddress = uri,
            };
        }

        public Dictionary<string, Dictionary<string, string>> Application = new Dictionary<string, Dictionary<string, string>>();

        public async Task<List<byte[]>> GetBytes(string i_url, string[] i_parameters, bool i_asPost, string i_cookieContainerKey, string[] headers = null)
        {
            List<KeyValuePair<string, string>> a_parameters = new List<KeyValuePair<string, string>>();
            if (i_parameters != null)
                foreach (string a_parameter in i_parameters)
                {
                    string[] a_pair = a_parameter.Split(new char[] { '=' }, 2);
                    a_parameters.Add(new KeyValuePair<string, string>(a_pair[0], a_pair[1]));
                }

            Dictionary<string, string> cookieContainer = null;
            if (i_cookieContainerKey != null)
            {
                if (Application.ContainsKey(i_cookieContainerKey))
                    cookieContainer = Application[i_cookieContainerKey];
                else
                {
                    cookieContainer = new Dictionary<string, string>();
                    Application[i_cookieContainerKey] = cookieContainer;
                }
            }

            var results = await GetBytes(i_url, a_parameters, i_asPost, cookieContainer, headers);

            return results;
        }


        public async Task<List<byte[]>> GetBytes(string i_url, List<KeyValuePair<string, string>> i_parameters, bool i_asPost, Dictionary<string, string> cookieContainer, string[] headers = null)
        {
            Uri uri = new Uri(i_url);

            HttpMethod method = new HttpMethod(i_asPost ? "POST" : "GET");
            HttpRequestMessage request = new HttpRequestMessage(method, uri);

            if (headers != null)
            {
                foreach (string header in headers)
                {
                    string[] parts = header.Split(new char[] { '=' }, 2);
                    request.Headers.TryAddWithoutValidation(parts[0], parts[1]);
                }
            }
            if (cookieContainer != null && cookieContainer.Count > 0)
                request.Headers.TryAddWithoutValidation("Cookie", string.Join("; ", cookieContainer.Keys.Select(k => k + "=" + cookieContainer[k]).ToArray()));

            if (i_asPost && i_parameters != null)
                request.Content = new FormUrlEncodedContent(i_parameters);

            HttpResponseMessage response = await client.SendAsync(request);

            // grab any cookies
            try
            {
                foreach (string cookieSet in response.Headers.GetValues("Set-Cookie"))
                {
                    Cookie cookie = CreateCookie(cookieSet);
                    cookieContainer[cookie.Name] = cookie.Value;
                }
            }
            catch { }

            // Get the response content.
            HttpContent responseContent = response.Content;

            Stream responseStream = await responseContent.ReadAsStreamAsync();
            if (responseContent.Headers.ContentEncoding.Contains("gzip"))
                responseStream = new GZipStream(responseStream, CompressionMode.Decompress);
            else if (responseContent.Headers.ContentEncoding.Contains("deflate"))
                responseStream = new DeflateStream(responseStream, CompressionMode.Decompress);

            List<byte[]> a_bytesArray = new List<byte[]>();
            const int c_bufferSize = 1000 * 1024;
            byte[] a_buffer = new byte[1000 * 1024];
            int a_bufferOffset = 0;
            int a_bytesAllowed = c_bufferSize;
            int a_bytesRead;

            while ((a_bytesRead = responseStream.Read(a_buffer, a_bufferOffset, a_bytesAllowed)) > 0)
            {
                a_bufferOffset += a_bytesRead;
                a_bytesAllowed -= a_bytesRead;
                if (a_bytesAllowed == 0)
                {
                    a_bytesArray.Add(a_buffer);
                    a_buffer = new byte[c_bufferSize];
                    a_bufferOffset = 0;
                    a_bytesAllowed = c_bufferSize;
                }
                System.Diagnostics.Debug.WriteLine(a_bytesRead + " bytes read");

            }

            // if we actually read something into this last buffer...
            if (a_bufferOffset != 0)
            {
                // it needs to be adjusted to fit only the exact amount read
                byte[] a_lastBuffer = new byte[a_bufferOffset];
                for (int a_ix = 0; a_ix < a_bufferOffset; a_ix++)
                    a_lastBuffer[a_ix] = a_buffer[a_ix];
                // and added to the array
                a_bytesArray.Add(a_lastBuffer);
            }

            return a_bytesArray;
        }

        private Cookie CreateCookie(string headerValue)
        {
            string[] parts = headerValue.Split(';').Select(v => v.Trim()).ToArray();
            Cookie cookie = new Cookie();
            for (int ix = 0; ix < parts.Length; ix++)
            {
                string[] innerParts = parts[ix].Split(new char[] { '=' }, 2);
                if (ix == 0)
                {
                    cookie.Name = innerParts[0];
                    cookie.Value = innerParts[1];
                }
                else
                {
                    // ignore cookies that don't correctly parse
                    switch (innerParts[0])
                    {
                        case "path": cookie.Path = innerParts[1]; break;
                        //case "domain": cookie.Domain = innerParts[1]; break;
                        case "expires":
                            {
                                try
                                {
                                    cookie.Expires = DateTime.Parse(innerParts[1]);
                                }
                                catch
                                {
                                    cookie.Expires = DateTime.UtcNow.AddDays(1);
                                }
                                break;
                            }
                        //case "max-age": cookie.MaxAge = Int32.Parse(innerParts[1]); break;
                        //case "secure": cookie.Secure = true; break;
                        //case "httponly": cookie.HttpOnly = true; break;
                    }

                }
            }
            return cookie;
        }


        public async Task Run()
        {
            string cookieContainerKey = Guid.NewGuid().ToString();
            string[] headers = new string[]
            {
                "User-Agent=Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36",
                "Accept=text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8",
                "Accept-Language=en-US,en;q=0.9",
                "Accept-Encoding=gzip, deflate, br",
                "DNT=1",
                "Connection=keep-alive",
                "Upgrade-Insecure-Requests=1",
            };


            //  Request Home page
            List<byte[]> results = await GetBytes("https://www.fedex.com/en-us/home.html", null, false, cookieContainerKey, headers);

            StringBuilder a_streamData = new StringBuilder("");
            foreach (byte[] a_bytes in results)
                a_streamData.Append(Encoding.ASCII.GetString(a_bytes, 0, a_bytes.Length));
            var resultsStr = a_streamData.ToString();



            string[] JSONheaders = new string[]
            {
                "User-Agent=Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36",
                "Accept=application/json, text/javascript, */*; q=0.01",
                "Accept-Language=en-US,en;q=0.9",
                "Accept-Encoding=gzip, deflate, br",
                "Referer=https://www.fedex.com/en-us/home.html",
                "Origin=https://www.fedex.com",
                "X-Requested-With=XMLHttpRequest",
                "DNT=1",
                "Connection=keep-alive",
            };

            string[] parameters = new string[]
            {
                "method=isLoggedIn",
            };

            results = await GetBytes("https://www.fedex.com/etc/services/fedexlogin", parameters, true, cookieContainerKey, JSONheaders);
            a_streamData = new StringBuilder("");
            foreach (byte[] a_bytes in results)
                a_streamData.Append(Encoding.ASCII.GetString(a_bytes, 0, a_bytes.Length));
            resultsStr = a_streamData.ToString();

            parameters = new string[]
            {
                "user=xxxxxx",
                "pwd=yyyyyyyy",
                "url=#",
            };

            results = await GetBytes("https://www.fedex.com/etc/services/fedexlogin", parameters, true, cookieContainerKey, JSONheaders);
            a_streamData = new StringBuilder("");
            foreach (byte[] a_bytes in results)
                a_streamData.Append(Encoding.ASCII.GetString(a_bytes, 0, a_bytes.Length));
            resultsStr = a_streamData.ToString();

        }
    }


    class Program
    {


        static void Main(string[] args)
        {
            Fed fed = new Fed("https://www.fedex.com");
            fed.Run().Wait();
        }
    }

1 个答案:

答案 0 :(得分:0)

我明白了。他们在他们的网络上使用机器人拦截软件。我猜其中一个cookie的内容实际上有一些关于软件调用类型的信息,并且他们已经决定他们不希望人们脚本访问他们自己的数据。羞。