C# 错误禁止403通过C模拟请求#

C# 错误禁止403通过C模拟请求#,c#,httpwebrequest,C#,Httpwebrequest,范围: 我正在开发一个C#应用程序来模拟查询。我非常熟悉模拟web请求以实现相同的人工步骤,但使用代码代替 如果您想自己试一试,只需在CNPJ框中键入以下号码: 0877572400119编写验证码并点击Confirmar 我已经处理过验证码了,所以这不再是问题了 问题: 我一执行“CNPJ”的POST请求,就会抛出一个异常: 远程服务器返回错误:(403)禁止 Fiddler调试器输出: 这是由我的浏览器生成的请求,而不是由我的代码生成的请求 POSThttps://www.sefaz.rr

范围:

我正在开发一个C#应用程序来模拟查询。我非常熟悉模拟web请求以实现相同的人工步骤,但使用代码代替

如果您想自己试一试,只需在CNPJ框中键入以下号码:
0877572400119
编写验证码并点击
Confirmar

我已经处理过验证码了,所以这不再是问题了

问题:

我一执行“CNPJ”的POST请求,就会抛出一个异常:

远程服务器返回错误:(403)禁止

Fiddler调试器输出:

这是由我的浏览器生成的请求,而不是由我的代码生成的请求

POSThttps://www.sefaz.rr.gov.br/sintegra/servlet/hwsintco HTTP/1.1
主持人:www.sefaz.rr.gov.br
连接:保持活力
内容长度:208
缓存控制:最大年龄=0
来源:https://www.sefaz.rr.gov.br
用户代理:Mozilla/5.0(Windows NT 6.1;WOW64)AppleWebKit/537.11(KHTML,如Gecko)Chrome/23.0.1271.97 Safari/537.11
内容类型:application/x-www-form-urlencoded
接受:text/html、application/xhtml+xml、application/xml;q=0.9,*/*;q=0.8
推荐人:https://www.sefaz.rr.gov.br/sintegra/servlet/hwsintco
接受编码:gzip、deflate、sdch
接受语言:pt BR,pt;q=0.8,在美国;q=0.6,en;q=0.4
接受字符集:ISO-8859-1,utf-8;q=0.7,*;q=0.3
Cookie:GX_SESSION_ID=gguyxyut5xraijm0fx9ou7wnxbvguuyoytiktdydvm%3D;JSSessionId=OVuuMFCgQv9k2b3fGyHjSZ9a.undefined
//PostData:
_EventName=E%27CONFIRMAR%27.&U EventGridId=&U EventRowId=&U MSG=&U CONINSEST=&U CONINSESTG=0877572400119&cfield=rice&&u VALIDATIONRESULT=1&BUTTON1=Confirmar&sCallerURL=http%3A%2F%2F www.sintegra.gov.br%2Fnew\u bv.html
使用的代码示例和参考:

我正在使用一个自行开发的库来处理/包装帖子并获取请求

请求对象的参数(主机、来源、引用、Cookies…)与浏览器发出的参数(此处记录了我的小提琴手)相同

我还通过以下方法设置了证书的
ServicePointValidator

ServicePointManager.ServerCertificateValidationCallback = 
    new RemoteCertificateValidationCallback (delegate { return true; });
在所有这些配置之后,我仍然得到了禁止的异常

下面是我模拟请求和抛出异常的方式

        try
        {
            this.Referer = Consts.REFERER;

            // PARAMETERS: URL, POST DATA, ThrownException (bool)
            response = Post (Consts.QUERYURL, postData, true);
        }
        catch (Exception ex)
        {
            string s = ex.Message;
        }
提前感谢您对我问题的任何帮助/解决方案

更新1:

我错过了生成cookies的主页请求(感谢@W0lf指出这一点)

现在还有一件奇怪的事。Fiddler没有在请求中显示我的Cookies,但它们是:

我使用浏览器成功地提出了请求,并将其记录在Fiddler中

唯一与您的要求不同的是:

  • 我的浏览器没有为
    sCallerURL
    参数发送任何值(我有
    sCallerURL=
    而不是
    sCallerURL=http%3A%2F%2Fwww….
  • 会话ID不同(显然)
  • 我还有其他的
    接受语言:
    值(我很确定这并不重要)
  • 内容长度不同(显然)
更新 好的,我以为Fiddler的痕迹来自你的申请。如果您没有根据请求设置cookies,请执行以下操作:

  • 在发布数据之前,向
    https://www.sefaz.rr.gov.br/sintegra/servlet/hwsintco
    。如果检查响应,您会注意到网站发送了两个会话cookie
  • 当您执行POST请求时,请确保附加上上一步获得的cookies
如果您不知道如何存储cookies并在其他请求中使用它们,请查看

更新2 问题 好的,我设法复制了403,找出了它的原因,并找到了修复方法

POST请求中发生的情况是:

  • 服务器响应状态302(临时重定向)和重定向位置
  • 浏览器将重定向(基本上执行GET请求)到该位置,同时发布两个cookie

.NET的HTTPWebRebug尝试无缝地重定向,但在这种情况下,有两个问题(我将考虑.NET实现中的bug):

  • POST(重定向)后的GET请求与POST请求具有相同的内容类型(
    application/x-www-form-urlencoded
    )。对于GET请求,不应指定此选项

  • cookie处理问题(最重要的问题)-网站发送两个cookie:
    GX_SESSION_ID
    JSESSIONID
    。第二个具有指定的路径(
    /sintegra
    ),而第一个没有

  • 区别在于:默认情况下,浏览器为第一个cookie分配路径
    /
    (root),而.NET为其分配请求url路径(
    /sintegra/servlet/hwsintco

    因此,重定向到
    /sintegra/servlet/hwsintpe…
    的最后一个GET请求(重定向后)没有获得传入的第一个cookie,因为其路径不对应

    修复
    • 对于重定向问题(使用内容类型获取),修复方法是手动执行重定向,而不是依赖.NET
    要执行此操作,请告诉它不要遵循重定向:

    postRequest.AllowAutoRedirect = false
    
    然后从POST响应中读取重定向位置,并手动对其执行GET请求

    • cookie问题(也是如此)
    为此,我找到的修复方法是从CookieContainer中取出放错位置的cookie,正确设置其路径,然后将其添加回容器的正确位置

    这是执行此操作的代码:

    private void FixMisplacedCookie(CookieContainer cookieContainer)
    {
        var misplacedCookie = cookieContainer.GetCookies(new Uri(Url))[0];
    
        misplacedCookie.Path = "/"; // instead of "/sintegra/servlet/hwsintco"
    
        //place the cookie in thee right place...
        cookieContainer.SetCookies(
            new Uri("https://www.sefaz.rr.gov.br/"), 
            misplacedCookie.ToString());
    }
    

    以下是使其工作的所有代码:
    有时HttpWebRequest需要代理初始化:
    request.Proxy=newwebproxy()//在我的例子中,它不需要参数,但您可以将其设置为您的代理地址

    多么糟糕的验证码系统!您可以发布用于生成请求的所有代码吗?上面的Fiddler数据用于请求gen
    using System;
    using System.IO;
    using System.Net;
    using System.Text;
    
    namespace XYZ
    {
        public class Crawler
        {
    
            const string Url = "https://www.sefaz.rr.gov.br/sintegra/servlet/hwsintco";
    
            public void Crawl()
            {
                var cookieContainer = new CookieContainer();
    
                /* initial GET Request */
                var getRequest = (HttpWebRequest)WebRequest.Create(Url);
                getRequest.CookieContainer = cookieContainer;
                ReadResponse(getRequest); // nothing to do with this, because captcha is f#@%ing dumb :)
    
                /* POST Request */
                var postRequest = (HttpWebRequest)WebRequest.Create(Url);
    
                postRequest.AllowAutoRedirect = false; // we'll do the redirect manually; .NET does it badly
                postRequest.CookieContainer = cookieContainer;
                postRequest.Method = "POST";
                postRequest.ContentType = "application/x-www-form-urlencoded";
    
                var postParameters =
                    "_EventName=E%27CONFIRMAR%27.&_EventGridId=&_EventRowId=&_MSG=&_CONINSEST=&" +
                    "_CONINSESTG=08775724000119&cfield=much&_VALIDATIONRESULT=1&BUTTON1=Confirmar&" +
                    "sCallerURL=";
    
                var bytes = Encoding.UTF8.GetBytes(postParameters);
    
                postRequest.ContentLength = bytes.Length;
    
                using (var requestStream = postRequest.GetRequestStream())
                    requestStream.Write(bytes, 0, bytes.Length);
    
                var webResponse = postRequest.GetResponse();
    
                ReadResponse(postRequest); // not interested in this either
    
                var redirectLocation = webResponse.Headers[HttpResponseHeader.Location];
    
                var finalGetRequest = (HttpWebRequest)WebRequest.Create(redirectLocation);
    
    
                /* Apply fix for the cookie */
                FixMisplacedCookie(cookieContainer);
    
                /* do the final request using the correct cookies. */
                finalGetRequest.CookieContainer = cookieContainer;
    
                var responseText = ReadResponse(finalGetRequest);
    
                Console.WriteLine(responseText); // Hooray!
            }
    
            private static string ReadResponse(HttpWebRequest getRequest)
            {
                using (var responseStream = getRequest.GetResponse().GetResponseStream())
                using (var sr = new StreamReader(responseStream, Encoding.UTF8))
                {
                    return sr.ReadToEnd();
                }
            }
    
            private void FixMisplacedCookie(CookieContainer cookieContainer)
            {
                var misplacedCookie = cookieContainer.GetCookies(new Uri(Url))[0];
    
                misplacedCookie.Path = "/"; // instead of "/sintegra/servlet/hwsintco"
    
                //place the cookie in thee right place...
                cookieContainer.SetCookies(
                    new Uri("https://www.sefaz.rr.gov.br/"),
                    misplacedCookie.ToString());
            }
        }
    }