首页 > 编程知识 正文

内网设置代理访问外网,如何限制外网访问权限

时间:2023-05-05 07:17:01 阅读:207650 作者:2832

标题可能有些绕口,意思就是我在外网要访问内网一资源(比如网站)时需要身份验证,只有通过身份验证才能访问,这个该如何实现?
其实这是一朋友问我的一个问题,需求就是:

领导在外出差,要通过企业微信访问内网资源,而这个资源又是高度保密的,不能随便让别人看到,公司又不提供VPN等工具,要如何实现?

我觉得这个需求蛮有意思的,就去深入思考了一下。我们知道,微信开发很多情况下是需要绑定域名的,那么绑定域名的情况下又要访问内网资源,很容易让人想到反向代理。所以,要实现这个需求,通过反向代理是必须的,问题就是,如何进行身份验证?今天会介绍两种 方式,一种使用Apache服务器+验证模块(这里利用Java Web的Servlet,实现的语言不唯一)实现,另外一种使用内网穿透工具,frp实现。

Apache实现 测试环境

Apache 2.2.31
JDK 1.8
IntelliJ IDEA 15

实现思路

首先,Apache服务器要架设在一台内外网都可访问的计算机上。
这个问题其实我想了蛮久的,最早想的是通过Apache服务器自带的验证模块,也就是记录用户名和密码到.htaccess文件,但是发现,这个只适用于架设在本机上的网站项目,通过反向代理就没用了。后来想到可以利图片防盗链的思路,我们在做防盗链时,常会判断请求HTTP头里是否有诸如HTTP_REFERER之类的参数,然后根据这个参数进行重定向。我们在实现访问权限控制时不妨也效仿它,整体思路都一样,不一样的地方就是在访问页面前进行授权,授权通过之后加上某个HTTP头,表示授权成功。

需求

假设我所在的公司开发了一套新的API,还没有开发完毕,不能随便公开,现在领导外出开会,需要对客户展示。(但是公司又不提供VPN)

实现步骤 Apache的httpd.conf文件配置

需要开启Apache的mod_rewrite模块。
Apache支持检测的HTTP头如下:

我这次就使用HTTP_REFERER头吧
Apache的反向代理设置如下:

<VirtualHost *:80> ServerName api.example.com ServerAlias api.example.com RewriteEngine On RewriteCond %{HTTP_REFERER} !^http://api.example.com/ RewriteRule ^(.*)$ http://www.baidu.com/ [R=401] ProxyPreserveHost On ProxyRequests Off ProxyPass / http://127.0.0.1:8080/api/sdk/ ProxyPassReverse / http://127.0.0.1:8080/api/sdk/</VirtualHost>

这里解释一下意思:
当对api.example.com发起请求时,Apache会检测请求头中是否有HTTP_REFERER,如果有,值是否以http://api.example.com/开头,如果不是,则401强制外部重定向到百度,其实你根本看不到百度的页面,只会看到401 Forbidden。
那为什么要判断HTTP_REFERER是否以http://api.example.com/呢?其实,当我们每次对api.example.com发起请求时,包括对子页面,Apache都会进行拦截,它会对每次的请求头进行检查,如果不符合就会直接返回401。所以,这个要观察子站点,看一下子站点是不是在页面见跳转时都会带HTTP_REFERER头,如果有的话就要按照它里面的规则来,验证成功后的入口页面的请求头要设置成一样的。否则我们永远只能看到一个页面了,页面间一旦跳转,就会401。

Apache的重写规则可以自行百度一下,这里推荐一篇简单的Apache的Rewrite规则详细介绍,里面关于重写标志的总结还是蛮清楚的。

Java端的编写

首先是Servlet

import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;/** * Created by Martin Huang on 2018/5/16. */public class ProxyServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //在这里进行验证授权 resp.addHeader("REFERER","http://api.example.com/"); resp.sendRedirect("http://api.example.com/"); }}

然后是HTML页面,这里比较简单,我直接使用一个a标签进行代替,主要是为了演示效果

<html><body><h2>Hello World!</h2><br/><a rel="external nofollow" href="proxyServlet">Jump</a></body></html>

最后是web.xml中Servlet的配置

<servlet> <servlet-name>proxyServlet</servlet-name> <servlet-class>com.example.servlet.ProxyServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>proxyServlet</servlet-name> <url-pattern>/proxyServlet</url-pattern> </servlet-mapping> 效果

未授权情况下:

可以发现子页面也是无法访问的

授权后:


子页面也是可以访问的

存在的问题 页面直接只能通过点击链接的方式跳转,不能直接输入地址栏,否则依然401HTTP_REFERER的值一旦被他人知道的话就容易使用第三方工具破解了 frp的实现(推荐)

对于访问网站的权限控制,我还是比较推荐frp的,毕竟这是一个开源项目,已经经过多个版本的迭代,安全性也好。
frp 是一个可用于内网穿透的高性能的反向代理应用,支持 tcp, udp, http, https 协议。
frp的文档点这里

实现步骤

搭建、配置可以见这篇文章LINUX | frp内网穿透穿透服务器
这里我们只关心网站访问的授权
frpc.ini配置文件如下:

[common]server_addr = x.x.x.x #frp服务器IPserver_port = 7000 #与服务器进行通信的端口[web01]type = httplocal_ip = 127.0.0.1local_port = 80http_user = abc #用于授权的用户名http_pwd = abc #用于授权的密码custom_domains = api.example.com

注:

我在服务器上设置了5520为web的访问端口,所以我利用api.example.com:5520进行访问

效果


访问时会让你输入用户名和密码进行验证,子页面也会。它这个验证是session级别的,也就是说如果浏览器关闭后要重新进行验证。

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。