# 钓鱼？这是反代理！

Author: 乌云历史资料库 (@wooyun_archive)
Published: 2015-06-16T03:30:00Z
Canonical: https://wepostx.com/topics/854

> 乌云历史资料归档
>
> **原始作者：** wrfly
> **原始编号：** superkieran-wooyundrops:599
> **原始发布时间：** 2015-06-16 11:30
> **声明：内容仅用于技术研究和个人使用，版权归 wooyun.org。**

---

# 0x00 前言

我是学弟。
进入正题之前，感谢那些分享知识的前辈们，我在参考了他们的文章之后学习到了很多东西。
奉上详细链接：
[Nginx反向代理、负载均衡、页面缓存、URL重写及读写分离详解](http://freeloda.blog.51cto.com/2033581/1288553)
[Nginx官方文档](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_cookie_domain)
[nginx反向代理配置](http://www.nginx.cn/927.html)
[调度算法](http://lzysg172.blog.51cto.com/6624306/1199412)
其中第一篇已经写的很详细了，有关正向代理，反向代理的介绍什么的；第二篇是nginx的官方文档，也是最最详细和标准的一个；第三篇是我参考的文件，第一遍当然看不懂，但是理解了每句话的内容之后也就明白了，下面的评论也挺搞笑的～。

# 0x01 简介

那我们就开始步入正题吧！
关于学习，无非就是，是什么，为什么，和怎样做。

# 是什么？
首先说明反向代理（reverse proxy）是什么，但是在这之前要先说明正向代理是什么，没错，真有正向代理（proxy）。
我们平时所说的代理就是正向代理，最常见的就是QQ代理，和VPN代理，以前的QQ主登陆界面的背面都会藏着一些设置选项，最醒目的就是代理，什么http代理啊，socks代理啊，https代理啊，我觉得这个功能是提供给那些在公司里面上不了QQ的人准备的，为什么上不了QQ？老板不让呗！所以就出现了“代理”这个工具，包括现在，也有很多网站提供免费的[在线代理](http://www.xici.net.co/)（我不是来打广告哒！），有匿名的，也有非匿名的，但是安全性，嘿嘿，真不好说。
代理的过程大概是这个样子的：
我上不了QQ，但是你可以上，所以我就把数据包发给你，你再帮我把数据包转给QQ服务器，当QQ服务器返回消息的时候，你再返回给我，这样你就充当了一个中间人的角色，也就是，代理。并不是多么难理解，就跟小时候传纸条差不多，中间传递的那个家伙就是我们的代理。当然，被老师抓到的也是他，不过，他也是有可能把你供出来的。所以在这里也提醒一下各位小黑阔们（海伦请无视），天网恢恢，疏而不漏，别以为挂了代理就找不到你了哦。
那么什么是反向代理？
有这样一种场景，你可以访问QQ的网站，但是我不行，我只能访问360的网站（先不要管为什么了）。但是我们之间的通信是畅通的，也就是说，我可以访问你的网站，那么，我该如何访问QQ呢？当然，我可以通过你这个跳板去上网，比如在你上面弄弄弄个VPN啊，ssh啊，但是如果你不让我这样做呢？你只开放了80端口给我，也就是说，我只能从你这里得到WWW的服务，这可如何是好？（不要问我为什么非要上QQ！）那么有一种办法就是你把QQ的内容抓取下来，放到80端口给我看，也就是说，我间接地通过你上了QQ。而你呢，就充当了反向代理的角色。注意，这里是间接上网，我表面上是访问的你，但是你再后端把QQ给抓过来了，所以，实质上我还是访问的QQ，这样说应该就会很好理解了。

# 0x02 为什么？

那么，为什么需要用反向代理呢？

## 1.服务器群的负载均衡
你有很多服务器对外提供服务，虽然说提供的服务都是一样的，但是每台服务器都有自己的IP啊，你不可能只让一台工作吧，那么怎样才能通过一个网址来调动所有的服务器都对外工作呢？这就需要反向代理了，设立一台主机对外开放，剩余的那些作为服务器群在后端负责处理数据，然后，当有请求发送到对外开放的主机上面时，这台主机就会通过算法去调动在后端的主机处理数据，然后把结果返回给客户，这样这台主机就仅仅起到了一个前台的作用，脏活累活什么的就交给了后面的那群主机们干了～前台作为调度员，是有责任处理好这些事务的，刚才说道通过算法进行处理，那么，究竟是什么算法呢？客官且听我慢慢说来。
[静态方法：仅根据算法本身实现调度：][a]

- Round-robin（轮回调度）
我有十台肉鸡，啊不，是服务器，每台服务器的性能都差不多，所以我就采用了这个轮回查询算法，每当有新的业务进来了，前台的调度员就会每台服务器每台服务器的给分配任务，不会偏袒着谁，因为是按照次序来的，1号有任务就分给是2号，2号完了是3号，3号完了就让4号上，但是，如果4号要是挂了呢？这就需要我们设置一个fail_timeout，意思是如果服务器在这个时间里没能应答或者啥的，就把任务再分配给下一台肉鸡，啊不，主机。

- Weighted round-robin（加权轮回调度）
还是那十台主机，但是有的是Digitalocean的，有的是阿里云的，有的用的是SSD，有的还tm用软盘，有的CPU用的是i7，有的用的是8086...性能不一样啊！要是按照上面的轮回算法，让一个超级电脑去等一台内存只有512M虚拟机，不能忍！所以，这时候就需要给我们的电脑加权了。好电脑就把权值分配的大一点，渣主机就把权值写小一点。这样前台在调度的时候就会按照他们的权值进行分配，主机A更快，那我就给他多分配点任务，主机B比较慢，那我分配任务的时候就少点。如果你还有兴趣了解，请谷歌“Weighted round-robin”。

- Source ip Hashing（源地址散列调度）
通俗点讲就是按照你的IP地址给你hash一个主机，然后这台主机就为你服务了，这种算法的优点是什么的？很明显的一对一金牌服务嘛！记得有一次CTF，出题的妖怪在后台部署了好多好多服务器，上传shell每次都会到不同的主机上，那么，你猜他们用的是什么调度方法？没错，反正不是这种。那么如果巧了，同一时间好多任务都给了一台主机，而这台主机又没反应咋弄？调度员也不是傻X，当服务器没有正常反应的时候，他就会给下一台主机分配这个任务了，涉及到很多算法的问题吧，我想。

- Destination ip Hashing（目标地址散列调度)
这种调度方法主要应用在缓存服务上面，如果好多主机访问的是同一台主机，那么前台调度员就会把这些主机看成同一类，把他们统统交给某一台服务器，怎么说呢，跟上面的哈希溯源正好相反着的，上面是一对一的服务，下面是一对多的服务。反正是缓存服务器嘛，性能肯定棒棒的，让他多做点事情也是没问题的。

动态方法：根据算法及后端RS当前的负载状况实现调度：
啊发现这些东西已经跑题了，所以各位看官有兴趣了解的话就不要听我在这里白活了，链接上面有哦～ 虽然那些文字看起来皱巴巴的 =。=

## 2. 海外代理
这就跟海外代购差不多的，我想买化妆品，但是国内没有啊，我就让代购去买，买完了给我就行了。放在服务器上呢，比如说，我想上谷歌，但是伟大的防火墙不让啊，所以我就交给海外的一台主机，让它帮我访问谷歌，然后我在向这台主机请求资源，这样就达到了访问谷歌的目的。[https://google.kfd.me](https://google.kfd.me)上面的站是我搭建的google。
“哎等会儿，你说的这个反向代理和VPN啥的有什么区别，还有我用的Shadowsocks，Goagent，不也都可以实现这种功能吗？”
哦。
那我就来扯一扯他们之间的区别。要是让我详细讲，估计一天也讲不完（其实是不会QAQ）。那我就简单粗略的给大家说一下有啥不同。首先说下VPN，VPN可以理解为一条虚拟的网线，我上不去谷歌，但是我远在日本的女朋友可以上啊，所以我就让女朋友答了一个VPN服务器，我呢，就通过VPN这条虚拟的网线连接上了女朋友的电脑，当然就可以上谷歌啦，不仅可以上谷歌，而且还可以……嘿嘿嘿。
那么，shadowsocks和goagent呢，他们都是代理软件，原理类似于上面讲到的正向代理，但是，代理的主机是127.0.0.1，也就是你自己的主机，如果在浏览器上设置了代理的话，那么你浏览器的流量都会先在本机走一圈，也就是通过那些shadowsocks啊goagent啊走一遍，而goagent呢，是连接了外网的家伙，我这里的外网，指的是out of China 的网，当然，在国内部署Goagent也不是不可以，只是你上不了谷歌而已，上上百度啊，QQ啊，360啊还都是可以的。Goagent会把流经它的数据转发到你部署的服务器上，在通过服务器进行资源请求。我之前也写过一篇关于goagent的，感兴趣的可以看[一下](http://im-faker.blogspot.com/2014/10/goagent.html/)。Shadowsocks的原理类似，不在赘述。

# 0x03 怎样做？

基本的配置Nginx我就不说了，网上一搜一大把，我在这里啰啰嗦嗦，大家也觉着没意思。如果说有什么需要注意的，那可能就是注意代理谷歌的时候不要被墙了你的域名。（我简直就是在作死……）
然后，我也不想做一个搬运工，把那些长篇大论以及图片复制粘贴过来，所以我就直接贴出配置文档以供大家参考，如果你把这份配置放在服务器上的话，你也会得到一个谷歌的反向代理以造福国人。顺便说下，kfd.me 这个域名是我的。

```text
proxy_cache_path /var/www/cache/ levels=1:2 keys_zone=one:100m max_size=1g; proxy_cache_key $host$request_uri; upstream google{ server 74.125.200.103 max_fails=3 fail_timeout=10s; server 74.125.200.105 max_fails=3 fail_timeout=10s; server 74.125.200.99 max_fails=3 fail_timeout=10s; server 74.125.200.147 max_fails=3 fail_timeout=10s; server 74.125.200.104 max_fails=3 fail_timeout=10s; } server { listen 80; server_name google.kfd.me; # rewrite ^/(.*) https://google.kfd.me$1 permanent; #} #server { # listen 443; # server_name google.kfd.me; # ssl on; # ssl_certificate /etc/ssl/private/google_kfd_me.crt; # ssl_certificate_key /etc/ssl/private/kfd_me.key; location / { proxy_pass http://google; proxy_cache one; proxy_cache_valid 200 302 2h; proxy_cache_valid 404 1h; proxy_buffering off; proxy_cookie_domain google.com google.kfd.me; proxy_redirect https://www.google.com.sg/ /; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Accept-Encoding ""; proxy_set_header User-Agent $http_user_agent; proxy_set_header Accept-Language "zh-CN"; proxy_set_header Cookie "PREF=ID=047818f19f6de346:U=0f622f33dd8549d11:FF=25:LD=zh-CN:NW=1:TM=1325238577:LM=1332342444:GM=5:SG=1:S=rE01SyJh2w1IQ-Maw"; sub_filter www.google.com google.kfd.me; sub_filter_once off; } }
```
下面就详细的解释一下每句话的作用，其实也就是口头翻译下官方文档（⊙﹏⊙b汗）
上面的两句是用来配置缓存目录的，首先定义了一个缓存目录，然后设置了目录的级别，也就是说，可以有几层目录keys_zone这个是设置空间名称的，可以随便定义，但是在下面引用的时候名字必须相同，而且要唯一。100m代表100分钟，缓存时间。最后的1g是代表缓存的总大小。 key代表的是通过什么方式来定义缓存，这里用的是主机名+url地址来确定的。这样每次有主机访问反代理的时候都会先查询一下这个缓存文件，如果有的话就不再请求新的资源。下面是缓存文件夹的一个tree。

![原文图片](/media/2016/06/abd746e11275e549495077d327acfb8b)

这个upstream google，表示的是上游服务器们，google只是一个代号，你完全可以写成guge，只要你知道这是什么意思就行了，而且下面引用的时候不要引用错。下面引用的条目是 proxy_pass。在这个栏目里面我们要写的是服务器的ip，其实你写网址也行，毕竟解析的都是ip。然后这里要注意的是里面的调度算法，这里面可以说是大有学问，我在[上面][a]讲的只是一点点皮毛而已。“max_fails=3” -> 最多允许三次失败。三次失败过后默认服务器挂掉，并将请求转入下一个服务器。 fail_timeout=10s -> 失败的时间为10秒。由于俺代理的是谷歌，而且谷歌的服务器这么坚挺，绝壁不会down，所以这里写上去也就没什么太大的鸟用。仅作教学示范～
proxy_pass 这一条是最最重要的，别的可以什么都没有，但是这一条是作为反向代理最重要的，它后面跟的值就是你要代理的网址，我这里的google是引用了上面定义的那些server，如果不需要那些server，你也可以直接放一个网址在这里，比如，http://zh.wikipedia.org/wiki/ 然后他就会访问这个网址了，哦对了，这里还有一个比较重要的地方，如果你的代理是一个ip地址，但是直接访问这个ip地址又得不到东西，那么这时候就需要定义header里面的 Host 了，可以这样来一条 prxy_set_header Host "zh.wikipedia.org"; 比如我要代理百度，然而百度并不让我直接上，所以我就可以这样写：

```text
proxy_pass http://www.baidu.com; proxy_set_header Host "www.baidu.com";
```
这样就可以蒙混过关～

![原文图片](/media/2016/06/7f2d5d75b6449bd0aab339acf4e9a3e1)

![原文图片](/media/2016/06/d2173b01b8266ad2a6024bb56b625d67)

proxy_cache 这里就是在上面 keys_zone 定义的那个名字。至于为什么要在这里声明一下，是因为一台服务器上可能不仅有一个缓存池，这里的声明是为了更好的区分。
proxy_cache_valid 200 302 2h; 这个说的是，当返回状态200和302的时候，缓存时间为两个小时。这里的返回状态是指我反代服务器给我的返回状态，一般可以设置的大一点，如果这个站经常被访问的话。想我这反代的谷歌，没几个人上，我也就写的这么小了。
proxy_cache_valid 404 1h; 404缓存一个小时。
proxy_cookie_domain google.com google.kfd.me; 替换cookie的domain，把google.com换成google.kfd.me。在这里你要有一个“域”的概念，cookie是不能随便用的，更不能串着用。（大牛们见笑了，我是说给小白听的，哎哎别打我脸啊，哎轻点轻点……）
proxy_redirect https://www.google.com.sg/ /； 重定向 "https://www.google.com.sg" 到 "/"，也就是说，当有请求google的资源的时候都会请求本地，这才是我们搭这个反代理的目的所在。
proxy_buffering off; 关闭缓冲.（内存中的缓存，不是cache）无关紧要的东西。
proxy_set_header这个是用来定义header的，也就是我们发送给谷歌的header，在这里我定义了用户的真实ip，和一部分cookie，还有语言，以及User agent。
sub_filter www.google.com google.kfd.me; 这个是最好玩的，但是只能玩一次。将返回结果中的www.google.com全部替换为google.kfd.me，这样当返回的网页中存在下一链接的时候，就会继续请求我们的 google.kfd.me 而不是跳到谷歌去。这里也可以好好地发挥一下，比如，偷点东西出来。当然，不在这里深究。P牛早已看穿了[一切](http://drops.wooyun.org/tips/6403)。
sub_filter_once off; 是否只替换一次？ 否。
当然，这个是全局代理谷歌，因为location是 / 嘛。你也可以在下面在加上一个location /hello { ... }然后访问 google.kfd.me/hello 就可以重新定义到另一个地方了。花样location，看起来很简单，但，做的事情却有很多。最简单的，定义robots，然后说不定就会有好玩的事情发生了呢～

# 0x04 写在最后

我一直以为，不想当厨子的裁缝不是好司机，其实我错了，不相当司机的厨子才不是好裁缝。
事情并没有这样简单地结束，因为这东西是一把刀，然而你要用这把刀犯罪还是防身，分寸在你心中。
钓鱼网站就是这么简单，我写这篇文章的目的也不是教你怎样钓鱼，而是让你知道，下一个被钓鱼的就是你。
如果你要问我为什么这么做，那么我的回答就跟为什么要去爬珠峰一样，因为我能。
提高防范意识，切勿玩火自焚。

![原文图片](/media/2016/06/38c268b573efbf9e25cc2daf8abadd1e)

## Replies
