防止CDN被滥用?自建一个简单的CDN远程鉴权服务器!

发布于 2023-02-04  1963 次阅读


最近在写一些私有后端调用的api,但是腾讯云的部分相关API不对外开放,且存在着诸多限制,于是看了看腾讯的远程鉴权文档,发现实现并不难,就简单写了一个可以用于cdn鉴权的小脚本,都是自己用得上的鉴权,目前已有根据referer IP url 进行鉴权。

此鉴权脚本几乎可以用于国内常见的CDN

  1. 在目录下新建一个auth.py
  2. 运行pip install Flask
  3. 在同一目录下新建以下三个txt文件
    ip.txt 存放被禁止访问CDN的IP地址 一行一个IP
    refer.txt 存放禁止访问CDN的refer 一行一个域名 支持通配符*严格匹配*. 注意输入网址符https:// ,例如https://github.com/ https://*.github.com/
    list.txt 存放禁止访问的目录 一行一个 如果是s.xml 则禁止对应的文件,如果是/结尾,则禁止相关子目录
  4. 在auth.py中写入以下代码保存后,运行python auth.py即可,您可以实时编辑对应的txt文件,无需重启程序,但需要您注意的是你需要保证程序后台保活,推荐linux服务器使用screen
  5. 可根据注释,自行将referer黑名单修改为referer白名单
# 导入Flask类
from flask import Flask
from flask import request
from flask import render_template
import logging
import datetime
import re

# 读取refer.txt
ban_refer_file = "refer.txt"
def read_ban_refer_file():
    with open(ban_refer_file, "r") as f:
        return [line.strip() for line in f.readlines()]

# 读取ip.txt
ban_ip_file = "ip.txt"
def read_ban_ip_file():
    with open(ban_ip_file, "r") as f:
        return [line.strip() for line in f.readlines()]

# 实例化
app = Flask(__name__)
# 读取禁止访问目录
list_file = "list.txt"
def read_list_file():
    with open(list_file, "r") as f:
        return [line.strip() for line in f.readlines()]
# /目录
@app.route('/', methods=['GET', 'POST','HEAD'])
def auth():
    #ban refer 支持通配符
    ban_refer_list = read_ban_refer_file()  
    referer = request.headers.get("Referer", None)  
    if referer:
        for ban_refer in ban_refer_list:
            if ban_refer.startswith("*."):
                ban_domain = ban_refer[2:]
                if referer.endswith(ban_domain):
                    return "Forbidden", 403
            elif referer == ban_refer:
                return "Forbidden", 403
    #ban ip
    ban_ip_list = read_ban_ip_file()
    client_ip = request.remote_addr
    if client_ip in ban_ip_list:
        return "Forbidden", 403

    if request.method == 'GET':
        print("HEAD请求")
        arges = request.form
        print("参数")
        logging.info(arges)
        print(request)
        print("请求头")
        headers = request.headers
        print(headers)
        logging.info(headers)
        print("请求数据")
        logging.info(request.data)
        return "login success", 200 # 403

    if request.method == 'HEAD':
        print("HEAD请求")
        arges = request.form
        print("参数")
        logging.info(arges)
        print(request)
        print("请求头")
        headers = request.headers
        print(headers)
        logging.info(headers)
        print("请求数据")
        logging.info(request.data)
        return "login success", 200 # 403
        
        
    if request.method == "POST":
        print("POST请求")
        arges = request.form
        print(request)
        headers = request.headers
        print("参数")
        logging.info(arges)
        print("请求头")
        logging.info(headers)
        print("请求数据")
        logging.info(request.data)
        return "login success", 200 # 403

# /~ 但不包含/目录
@app.route('/<path:sub_path>', methods=['GET', 'POST','HEAD'])
def auths(sub_path):
    #ban refer 支持通配符
    ban_refer_list = read_ban_refer_file()  
    referer = request.headers.get("Referer", None)  
    if referer:
        for ban_refer in ban_refer_list:
            if ban_refer.startswith("*."):
                ban_domain = ban_refer[2:]
                if referer.endswith(ban_domain):
                    return "Forbidden", 403 #200
            elif referer == ban_refer:
                return "Forbidden", 403 #200
    #ban ip
    ban_ip_list = read_ban_ip_file()
    client_ip = request.remote_addr
    if client_ip in ban_ip_list:
        return "Forbidden", 403
    #ban url目录
    list_dirs = read_list_file()
    for dir in list_dirs:
        if re.match(dir, sub_path):
            return "Forbidden", 403


    if request.method == 'GET':
        print("HEAD请求")
        arges = request.form
        print("参数")
        logging.info(arges)
        print(request)
        print("请求头")
        headers = request.headers
        print(headers)
        logging.info(headers)
        print("请求数据")
        logging.info(request.data)
        return "login success", 200 # 403

    if request.method == 'HEAD':
        print("HEAD请求")
        arges = request.form
        print("参数")
        logging.info(arges)
        print(request)
        print("请求头")
        headers = request.headers
        print(headers)
        logging.info(headers)
        print("请求数据")
        logging.info(request.data)
        return "login success", 200 # 403
        
        
    if request.method == "POST":
        print("POST请求")
        arges = request.form
        print(request)
        headers = request.headers
        print("参数")
        logging.info(arges)
        print("请求头")
        logging.info(headers)
        print("请求数据")
        logging.info(request.data)
        return "login success", 200 # 403

if __name__ == '__main__':
    app.run(host="0.0.0.0", port=6363)

上面的工作完成好之后你可以开放6363端口,也可以自行绑定域名反向代理

以腾讯云CDN为例:打开CDN控制台 访问控制 远程鉴权 自行配置即可

我的博客即将同步至腾讯云开发者社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=3pbd856b2uqsk