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

发布于 2024-07-10 07:36:45 字数 462 浏览 7 评论 0原文

我需要创建一个将网页发送到我们网站的请求,但我也需要能够设置主机标头信息。 我已经使用 HttpWebRequest 尝试过此操作,但标头信息是只读的(或者至少其主机部分是只读的)。 我需要这样做,因为我们希望在用户之前执行页面的初始请求。 我们有 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();

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

I need to create a request for a web page delivered to our web sites, but I need to be able to set the host header information too. I have tried this using HttpWebRequest, but the Header information is read only (Or at least the Host part of it is). I need to do this because we want to perform the initial request for a page before the user can. We have 10 web server which are load balanced, so we need to request the file from each of the web servers.

I have tried the following:

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

Obviously this does not work, as I can't update the header, and I don't know if this is indeed the right way to do it.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

少钕鈤記 2024-07-17 07:36:45

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

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

反射是你的朋友:)

Although this is a very late answer, maybe someone can get benefit of it

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

Reflection is your friend :)

等待圉鍢 2024-07-17 07:36:45

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

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

I have managed to find out a more long winded route by using sockets. I found the answer in the MSDN page for IPEndPoint:

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();
十二 2024-07-17 07:36:45

我遇到了一个问题,我使用的 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;

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

I had a problem where the URL dns I used had several different IP addresses, I wanted to call each address separately using the same dns name in the host - the solution is using a proxy:

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;

Host header is set from 'url' automatically by .NET, and 'ip' contains the actual address of the web server you want to contact (you can use a dns name here too)

墨小沫ゞ 2024-07-17 07:36:45

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

我所做的是创建一个从 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;

希望这可以帮助任何寻找这个的人!

I know this is old, but I came across this same exact problem, and I found a better solution to this then using sockets or reflection...

What I did was create a new class that durives from WebHeaderCollection and bypasses validation of what you stick inside it:

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

and here is how you use it:

    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;

Hope this helps anyone looking for this!

血之狂魔 2024-07-17 07:36:45

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

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

I know this is an old question, but these days, you can do.

HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://192.168.1.5/filename.htm");
request.Host = "www.mywebstite.com";
WebResponse response = request.GetResponse();
万劫不复 2024-07-17 07:36:45

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

编辑:或者像链接问题中的其他人提到的那样,只需打开一个套接字并手动快速执行“GET”即可。 如果您不需要修改其他东西,例如 cookie 或 HttpWebRequest 提供的任何其他细节,那么这应该是理所当然的。

The "Host" header is protected and cannot be modified programmatically. I suppose to work around this, you could try and bind via reflection to the private "InnerCollection" property of the WebRequest object and calling the "Set" ar "Add" method on it to modify the Host header. I haven't tried this, but from a quick look at the source code in Reflector, I think it's easily accomplished. But yeah, binding to private properties of framework objects is not the best way to accomplish things. :) Use only if you MUST.

edit: Or like the other guy mentions in the linked question, just open up a socket and do a quick "GET" manually. Should be a no brainer, if you don't need to tinker with other stuff, like cookies or whatever else niceties the HttpWebRequest provides.

攒眉千度 2024-07-17 07:36:45

好吧,一点点研究发现了这一点:

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

看来微软可能会在某个时候对此采取一些措施。

Alright, little bit of research turns up this:

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

Seems MS may do something about this at some point.

你是暖光i 2024-07-17 07:36:45

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

如何在HttpWebRequest中设置自定义“Host”标头?

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

You can use my solution for this problem, it posted here :

How to set custom "Host" header in HttpWebRequest?

This can help you to edit host header, and avoid to using proxy and direct socket requests.

凉栀 2024-07-17 07:36:45

死灵术。
对于那些仍在使用 .NET 2.0 的人
事实上,如果你知道怎么做的话,这很容易。

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

下一次尝试将使用反射设置标头 - 如此处最受好评的答案所示 - 来绕过它,这将允许您更改标头值。 但在运行时,它会用 url 的主机部分覆盖这个值,这意味着反射不会给你带来任何东西,这就是为什么我不< /strong> 理解为什么人们不断支持投票。

如果 dns-name 不存在(坦率地说,这是您首先想要执行此操作的唯一情况),则无法设置它,因为 .NET 无法解析它,而且您也无法覆盖 .NET DNS 解析器。

但您可以做的是设置一个与目标服务器 IP 完全相同的网络代理。

因此,如果您的服务器 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)的 Web 服务器,那么现在您将获得正确的页面。

现在,对于 WebRequest 和 WebClient,您已经有了原始问题的正确答案。 我认为使用自定义套接字来执行此操作是错误的方法,特别是当应该使用 SSL 且实际解决方案如此简单时......

Necromancing.
For those still on .NET 2.0
It is in fact quite easy, if you know how.

Problem is, you can't set the host header, because the framework won't let you change the value at runtime. (.net framework 4.0+ will let you override host in a httpwebrequest).

Next attempt will be setting the header with reflection - as demonstrated in the top upvoted answer here - to get around it, which will let you change the header value. But at runtime, it will overwrite this value with the host part of the url, which means reflection will bring you nothing, which is why I don't understand why people keep upvoting this.

If the dns-name doesn't exist, which is quite frankly the only case in which you want to do this in the first place, you can't set it, because .NET can't resolve it, and you can't override the .NET DNS resolver.

But what you can do, is setting a webproxy with the exact same IP as the destination server.

So, if your server IP is 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
    }


    }

and voila, now

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

and you get the correct page back, if 28.14.88.71 is a webserver with virtual name-based hosting (based on http-host-header).

Now you have the correct answer to the original question, for both WebRequest and WebClient. I think using custom sockets to do this would be the wrong approach, particularly when SSL should be used, and when an actual solution is that simple...

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文