从代码验证网站的问题

时间:2012-03-06 01:25:58

标签: c# authentication .net-3.5 httpwebrequest

我正在尝试编写将对网站wallbase.cc进行身份验证的代码。我看过它使用Firfebug / Chrome Developer工具做了什么,看起来相当简单:

发布“usrname = $ USER& pass = $ PASS& nopass_email =在+您的+电子邮件中键入+ + +并按+输入& nopass = 0”到网页“http://wallbase.cc/user / login“,存储返回的cookie并在将来的所有请求中使用它们。

这是我的代码:

    private CookieContainer _cookies = new CookieContainer();

    //......

    HttpPost("http://wallbase.cc/user/login", string.Format("usrname={0}&pass={1}&nopass_email=Type+in+your+e-mail+and+press+enter&nopass=0", Username, assword));

    //......


    private string HttpPost(string url, string parameters)
    {
        try
        {
            System.Net.WebRequest req = System.Net.WebRequest.Create(url);
            //Add these, as we're doing a POST
            req.ContentType = "application/x-www-form-urlencoded";
            req.Method = "POST";

            ((HttpWebRequest)req).Referer = "http://wallbase.cc/home/";
            ((HttpWebRequest)req).CookieContainer = _cookies;

            //We need to count how many bytes we're sending. Post'ed Faked Forms should be name=value&
            byte[] bytes = System.Text.Encoding.ASCII.GetBytes(parameters);
            req.ContentLength = bytes.Length;
            System.IO.Stream os = req.GetRequestStream();
            os.Write(bytes, 0, bytes.Length); //Push it out there
            os.Close();

            //get response
            using (System.Net.WebResponse resp = req.GetResponse())
            {

                if (resp == null) return null;
                using (Stream st = resp.GetResponseStream())
                {
                    System.IO.StreamReader sr = new System.IO.StreamReader(st);
                    return sr.ReadToEnd().Trim();
                }
            }
        }
        catch (Exception)
        {
            return null;
        }
    }

在使用我的登录参数调用HttpPost后,我希望将来使用相同方法的所有调用都要进行身份验证(假设有效的用户名/密码)。我在我的cookie集合中获得了一个会话cookie但由于某种原因我没有经过身份验证。我在我的cookie集合中获得了一个会话cookie,无论我访问哪个页面,所以我尝试首先加载主页以获取初始会话cookie,然后登录但没有变化。

据我所知,这个Python版本有效:https://github.com/sevensins/Wallbase-Downloader/blob/master/wallbase.sh(第336行)

有关如何使身份验证工作的任何想法?

更新#1
当使用正确的用户/密码对时,响应会自动重定向到引用者,但是当收到不正确的用户/传递对时,它不会重定向并返回错误的用户/密码对。基于此,似乎认证正在发生,但可能并非所有关键信息都被保存了?

更新#2

我使用的是.NET 3.5 。当我在.NET 4中尝试上面的代码时,添加了System.Net.ServicePointManager.Expect100Continue = false行(在我的代码中,这里没有显示),它可以工作,不需要进行任何更改。问题似乎直接源于一些pre-.Net 4问题。

3 个答案:

答案 0 :(得分:6)

这是基于我的一个项目的代码,以及stackoverflow上各种答案中的代码。

首先,我们需要设置一个Cookie aware WebClient来使用HTML 1.0

public class CookieAwareWebClient : WebClient
{
    private CookieContainer cookie = new CookieContainer();

    protected override WebRequest GetWebRequest(Uri address)
    {
        HttpWebRequest request = (HttpWebRequest)base.GetWebRequest(address);
        request.ProtocolVersion = HttpVersion.Version10;
        if (request is HttpWebRequest)
        {
            (request as HttpWebRequest).CookieContainer = cookie;
        }
        return request;
    }
}

接下来,我们设置处理Authentication的代码,然后最终加载response

var client = new CookieAwareWebClient();
client.UseDefaultCredentials = true;
client.BaseAddress = @"http://wallbase.cc";

var loginData = new NameValueCollection();
loginData.Add("usrname", "test");
loginData.Add("pass", "123");
loginData.Add("nopass_email", "Type in your e-mail and press enter");
loginData.Add("nopass", "0");
var result = client.UploadValues(@"http://wallbase.cc/user/login", "POST", loginData);

string response = System.Text.Encoding.UTF8.GetString(result);

我们可以在保持调试模式的同时使用HTML Visualizer内置到Visual Studio中进行尝试,并使用它来确认我们能够authenticate并在停留期间加载主页{ {1}}。

Success

此处的关键是设置authenticated并使用CookieContainer,而不是HTTP 1.0。我不完全确定为什么强制它使用1.1允许您成功验证和加载页面,但解决方案的一部分是基于这个答案。 https://stackoverflow.com/a/10916014/408182

我使用Fiddler确保1.0发送的响应与我的网络浏览器C# Client相同。它还允许我确认Chrome是否正确重定向。在这种情况下,我们可以看到C# client HTML 1.0,我们正在获取HTTP/1.0 302 Found,然后按预期将我们重定向到主页。如果我们切换回HTML 1.1,我们会收到HTTP/1.1 417 Expectation Failed messageFiddler

此stackoverflow线程中提供了有关此错误消息的一些信息。 HTTP POST Returns Error: 417 "Expectation Failed."

编辑:Hack / Fix for .NET 3.5

我花了很多时间试图找出3.5和4.0之间的差异,但我真的不知道。看起来3.5在验证后创建了一个新的cookie,我发现的唯一方法就是对用户进行两次身份验证。

我还必须根据这篇文章中的信息对WebClient进行一些更改。 http://dot-net-expertise.blogspot.fr/2009/10/cookiecontainer-domain-handling-bug-fix.html

public class CookieAwareWebClient : WebClient
{
    public CookieContainer cookies = new CookieContainer();
    protected override WebRequest GetWebRequest(Uri address)
    {
        var request = base.GetWebRequest(address);
        var httpRequest = request as HttpWebRequest;
        if (httpRequest != null)
        {
            httpRequest.ProtocolVersion = HttpVersion.Version10;
            httpRequest.CookieContainer = cookies;

            var table = (Hashtable)cookies.GetType().InvokeMember("m_domainTable", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.GetField | System.Reflection.BindingFlags.Instance, null, cookies, new object[] { });
            var keys = new ArrayList(table.Keys);
            foreach (var key in keys)
            {
                var newKey = (key as string).Substring(1);
                table[newKey] = table[key];
            }
        }
        return request;
    }
}

var client = new CookieAwareWebClient();

var loginData = new NameValueCollection();
loginData.Add("usrname", "test");
loginData.Add("pass", "123");
loginData.Add("nopass_email", "Type in your e-mail and press enter");
loginData.Add("nopass", "0");

// Hack: Authenticate the user twice!
client.UploadValues(@"http://wallbase.cc/user/login", "POST", loginData);
var result = client.UploadValues(@"http://wallbase.cc/user/login", "POST", loginData);

string response = System.Text.Encoding.UTF8.GetString(result);

答案 1 :(得分:3)

您可能需要添加以下内容:

//get response
using (System.Net.WebResponse resp = req.GetResponse())
{
    foreach (Cookie c in resp.Cookies)
        _cookies.Add(c);
    // Do other stuff with response....
}

您可能需要做的另一件事是,如果服务器以302(重定向)响应,.Net Web请求将自动跟随它,在此过程中您可能会丢失您之后的cookie。您可以使用以下代码关闭此行为:

req.AllowAutoRedirect = false;

答案 2 :(得分:2)

您引用的Python使用不同的引用者(http://wallbase.cc/start/)。此后还有另一篇文章(http://wallbase.cc/user/adult_confirm/1)。尝试其他推荐人并通过此POST进行跟进。

我认为您正确进行了身份验证,但在继续之前,该网站需要您提供更多信息/断言。