在c#中欺骗主机请求网页

时间:2008-12-11 11:27:57

标签: c# http http-headers

我需要创建一个发送到我们网站的网页请求,但我也需要能够设置主机头信息。我已经尝试使用HttpWebRequest,但Header信息是只读的(至少它的主机部分是)。我需要这样做,因为我们想在用户可以之前执行页面的初始请求。我们有10个负载均衡的Web服务器,因此我们需要从每个Web服务器请求该文件。

我尝试了以下内容:

HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://192.168.1.5/filename.htm");
request.Headers.Set("Host", "www.mywebsite.com");
WebResponse response = request.GetResponse();

显然这不起作用,因为我无法更新标题,我不知道这是否确实是正确的方法。

9 个答案:

答案 0 :(得分:10)

虽然这是一个非常晚的答案,但也许有人可以从中受益

HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(new Uri("http://192.168.1.1"));
request.Headers.GetType().InvokeMember("ChangeInternal", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.InvokeMethod, null, request.Headers, new object[] {"Host","www.mysite.com"});

反思是你的朋友:)

答案 1 :(得分:9)

我已经设法通过使用套接字找到更长的绕线路线。我在IPEndPoint的MSDN页面中找到了答案:

string getString = "GET /path/mypage.htm HTTP/1.1\r\nHost: www.mysite.mobi\r\nConnection: Close\r\n\r\n";
Encoding ASCII = Encoding.ASCII;
Byte[] byteGetString = ASCII.GetBytes(getString);
Byte[] receiveByte = new Byte[256];
Socket socket = null;
String strPage = null;
try
{
    IPEndPoint ip = new IPEndPoint(IPAddress.Parse("10.23.1.93"), 80);
    socket = new Socket(ip.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
    socket.Connect(ip);
}
catch (SocketException ex)
{
    Console.WriteLine("Source:" + ex.Source);
    Console.WriteLine("Message:" + ex.Message);
}
socket.Send(byteGetString, byteGetString.Length, 0);
Int32 bytes = socket.Receive(receiveByte, receiveByte.Length, 0);
strPage = strPage + ASCII.GetString(receiveByte, 0, bytes);

while (bytes > 0)
{
    bytes = socket.Receive(receiveByte, receiveByte.Length, 0);
    strPage = strPage + ASCII.GetString(receiveByte, 0, bytes);
}
socket.Close();

答案 2 :(得分:4)

我遇到的问题是我使用的URL dns有几个不同的IP地址,我想在主机中使用相同的dns名称分别调用每个地址 - 解决方案是使用代理:

string retVal = "";
            // Can't change the 'Host' header property because .NET protects it
            // HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
            // request.Headers.Set(HttpRequestHeader.Host, DEPLOYER_HOST);
            // so we must use a workaround
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
            request.Proxy = new WebProxy(ip);
            using (WebResponse response = request.GetResponse())
            {
                using (TextReader reader = new StreamReader(response.GetResponseStream()))
                {
                    string line;
                    while ((line = reader.ReadLine()) != null)
                        retVal += line;
                }
            }
            return retVal;

主机标头由.NET自动设置为'url','ip'包含您要联系的Web服务器的实际地址(您也可以在此处使用dns名称)

答案 3 :(得分:2)

我知道这是旧的,但我遇到了同样的问题,我找到了更好的解决方案,然后使用套接字或反射......

我所做的是创建一个来自WebHeaderCollection的新类,并绕过你在其中的内容验证:

public class MyHeaderCollection:WebHeaderCollection
{
    public new void Set(string name, string value)
    {
        AddWithoutValidate(name, value);
    }
    //or
    public new string this[string name]
    {
        get { return base[name]; }
        set { AddWithoutValidate(name, value); }
    }
}

以下是您使用它的方式:

    var http = WebRequest.Create("http://example.com/");
    var headers = new MyHeaderCollection();
    http.Headers = headers;

    //Now you can add/override anything you like without validation:
    headers.Set("Host", http.RequestUri.Host);
    //or
    headers["Host"] = http.RequestUri.Host;

希望这有助于任何寻找此事的人!

答案 4 :(得分:1)

我知道这是一个老问题,但是现在,你可以这样做。

HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://192.168.1.5/filename.htm");
request.Host = "www.mywebstite.com";
WebResponse response = request.GetResponse();

答案 5 :(得分:0)

好吧,稍微研究了一下:

https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=384456

似乎MS 可能会在某些时候对此做些什么。

答案 6 :(得分:0)

“Host”标头受保护,无法以编程方式进行修改。我想解决这个问题,您可以尝试通过反射绑定到WebRequest对象的私有“InnerCollection”属性,并在其上调用“Set”ar“Add”方法来修改Host标头。我没试过这个,但是从快速查看Reflector中的源代码,我认为它很容易实现。但是,绑定到框架对象的私有属性并不是完成任务的最佳方法。 :)只有你必须使用。

编辑:或者像其他人在链接问题中提到的那样,只需打开一个套接字并手动快速“GET”。如果你不需要修改其他东西,比如cookie或HttpWebRequest提供的任何其他细节,那就应该不费吹灰之力。

答案 7 :(得分:0)

你可以使用我的解决方案解决这个问题,它发布在这里:

How to set custom "Host" header in HttpWebRequest?

这可以帮助您编辑主机头,并避免使用代理和直接套接字请求。

答案 8 :(得分:0)

Necromancing。
对于仍然使用.NET 2.0的用户 事实上,如果你知道如何,这很容易。

问题是,您无法设置主机标头,因为框架不允许您在运行时更改该值。 (.net framework 4.0+将允许您覆盖httpwebrequest中的主机)。

下一次尝试将使用反射设置标题 - 如此处的顶部upvoted答案所示 - 绕过它,这将允许您更改标题值。但是在运行时,它会用 的主机部分 覆盖这个值,这意味着反射不会给你带来什么,这就是为什么我不要' t 了解为什么人们会坚持投票。

如果dns-name不存在,坦率地说,这是你想要首先做到这一点的唯一情况,你就不能设置它,因为.NET可以'解决它,你不能覆盖.NET DNS解析器。

但是你可以做的是设置一个与目标服务器完全相同的webproxy。

因此,如果您的服务器IP是28.14.88.71:

public class myweb : System.Net.WebClient
{
    protected override System.Net.WebRequest GetWebRequest(System.Uri address)
    {
        System.Net.WebRequest request = (System.Net.WebRequest)base.GetWebRequest(address);
        //string host = "redmine.nonexistantdomain.com";

        //request.Headers.GetType().InvokeMember("ChangeInternal",
        //    System.Reflection.BindingFlags.NonPublic |
        //    System.Reflection.BindingFlags.Instance |
        //    System.Reflection.BindingFlags.InvokeMethod, null,
        //    request.Headers, new object[] { "Host", host }
        //);

        //server IP and port
        request.Proxy = new System.Net.WebProxy("http://28.14.88.71:80");

        // .NET 4.0 only
        System.Net.HttpWebRequest foo = (System.Net.HttpWebRequest)request;
        //foo.Host = host;

        // The below reflection-based operation is not necessary, 
        // if the server speaks HTTP 1.1 correctly
        // and the firewall doesn't interfere
        // https://yoursunny.com/t/2009/HttpWebRequest-IP/
        System.Reflection.FieldInfo horribleProxyServicePoint = (typeof(System.Net.ServicePoint))
            .GetField("m_ProxyServicePoint", System.Reflection.BindingFlags.NonPublic |
            System.Reflection.BindingFlags.Instance);

        horribleProxyServicePoint.SetValue(foo.ServicePoint, false);
        return foo; // or return request; if you don't neet this
    }


    }

瞧,现在

myweb wc = new myweb();
string str = wc.DownloadString("http://redmine.netexistantdomain.com");

如果28.14.88.71是具有基于虚拟名称的托管(基于http-host-header)的网络服务器,则会返回正确的页面。

现在,对于WebRequest和WebClient,您对原始问题的答案都是正确的。我认为使用自定义套接字执行此操作将是错误的方法,尤其是在应该使用SSL时,以及当实际解决方案如此简单时...