【问题标题】:Error Forbidden 403 simulating request via C#错误禁止 403 通过 C# 模拟请求
【发布时间】:2013-01-03 13:17:30
【问题描述】:

范围:

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

如果您想亲自尝试,只需在 CNPJ 框中输入此数字即可: 08775724000119 并输入验证码并点击Confirmar

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

问题:

一旦我对“CNPJ”执行 POST 请求,就会引发异常:

远程服务器返回错误:(403) Forbidden。

Fiddler 调试器输出:

Link for Fiddler Download

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

POST https://www.sefaz.rr.gov.br/sintegra/servlet/hwsintco HTTP/1.1
Host: www.sefaz.rr.gov.br
Connection: keep-alive
Content-Length: 208
Cache-Control: max-age=0
Origin: https://www.sefaz.rr.gov.br
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.11 (KHTML, like Gecko)    Chrome/23.0.1271.97 Safari/537.11
Content-Type: application/x-www-form-urlencoded
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Referer: https://www.sefaz.rr.gov.br/sintegra/servlet/hwsintco
Accept-Encoding: gzip,deflate,sdch
Accept-Language: pt-BR,pt;q=0.8,en-US;q=0.6,en;q=0.4
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3
Cookie: GX_SESSION_ID=gGUYxyut5XRAijm0Fx9ou7WnXbVGuUYoYTIKtnDydVM%3D;   JSESSIONID=OVuuMFCgQv9k2b3fGyHjSZ9a.undefined


//    PostData : 
_EventName=E%27CONFIRMAR%27.&_EventGridId=&_EventRowId=&_MSG=&_CONINSEST=&_CONINSESTG=08775724000119&cfield=rice&_VALIDATIONRESULT=1&BUTTON1=Confirmar&sCallerURL=http%3A%2F%2Fwww.sintegra.gov.br%2Fnew_bv.html

使用的代码示例和参考:

我正在使用自行开发的库来处理/包装 Post 和 Get 请求。

请求对象具有与浏览器发出的相同参数(Host、Origin、Referer、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:

我错过了生成 cookie 的主页请求(感谢 @W0lf 指出)

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

【问题讨论】:

  • 多么糟糕的验证码系统!
  • 你能发布你用来构建请求的所有代码吗?上面的 Fiddler 数据是针对您的程序生成的请求,还是来自浏览器的请求?
  • @W0lf 浏览器发出的请求。我想有一个cookie丢失,但我不确定它是在哪里生成的。现在仔细检查一下,如果没有帮助,我会发布代码
  • @W0lf Captcha 验证是通过 Javascript,Pff 完成的。即使是客户端,每个验证码都是由从 1 到 191 的索引生成的,这也很糟糕。这不是动态生成的验证码。 sefaz.rr.gov.br/sintegra/images/images/60.jpg 永远是“债务”字。
  • 它不是动态的部分令人惊讶地不是最愚蠢的事情。最糟糕的是验证是在 JS 中完成的。如果您基本上将cfield=much&_VALIDATIONRESULT=1 传递给每个请求,那么您应该没问题。

标签: c# httpwebrequest


【解决方案1】:

我使用浏览器成功请求并记录在Fiddler中。

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

  • 我的浏览器没有为sCallerURL 参数发送任何值(我有sCallerURL= 而不是sCallerURL=http%3A%2F%2Fwww....
  • 会话 ID 不同(显然)
  • 我还有其他 Accept-Language: 值(我很确定这不重要)
  • Content-Length 不同(显然)

更新

好的,我认为 Fiddler 跟踪来自您的应用程序。如果您没有根据请求设置 cookie,请执行以下操作:

  • 在发布数据之前,向https://www.sefaz.rr.gov.br/sintegra/servlet/hwsintco 发出GET 请求。如果您检查响应,您会注意到该网站发送了两个会话 cookie。
  • 当您发出 POST 请求时,请务必附上您在上一步中获得的 cookie

如果您不知道如何存储 cookie 并在其他请求中使用它们,请查看 here

更新 2

问题

好的,我设法重现了 403,找出了导致它的原因,并找到了修复方法。

POST 请求中发生的情况是:

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

.NET 的 HttpWebRequest 尝试无缝地执行此重定向,但在这种情况下存在两个问题(我会考虑 .NET 实现中的错误):

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

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

不同之处在于:浏览器默认为第一个 cookie 分配路径 /(root),而 .NET 为其分配请求 url 路径 (/sintegra/servlet/hwsintco)。

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

修复

  • 对于重定向问题(带有内容类型的 GET),解决方法是手动执行重定向,而不是依赖 .NET。

为此,告诉它不要遵循重定向:

postRequest.AllowAutoRedirect = false

然后从 POST 响应中读取重定向位置并手动对其执行 GET 请求。

为此,我找到的解决方法是从 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());
}

以下是使其工作的所有代码:

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());
        }
    }
}

【讨论】:

  • 我在我的请求库上使用了一个 CookieJar,它设法保存了所有 cookie。正如您所建议的,我刚刚执行了对主页的请求,但仍然没有运气,但是 cookie 在那里。
  • cookies 在代码中找到,但 fiddler 没有显示它们。 Fiddler 在我的代码发出的请求中没有显示任何 cookie
  • @MarcelloGrechiLins 如果 Fiddler 没有显示 cookie,这意味着它们可能没有被发送。仔细检查您的代码以确保将它们附加到第二个请求。
  • @MarcelloGrechiLins 这是一个棘手的问题,但我想我解决了。请查看我的答案的更新。
  • 我只是使用 Fiddler 来比较浏览器完成的请求和程序完成的请求。在注意到差异后,我想出了上面描述的修复方法。
【解决方案2】:

有时 HttpWebRequest 需要代理初始化: request.Proxy = new WebProxy();//在我的情况下它不需要参数,但你可以将它设置为你的代理地址

【讨论】:

    猜你喜欢
    • 2017-05-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-10
    • 1970-01-01
    • 1970-01-01
    • 2018-02-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多