服务器访问权限控制

公网上服务器开通代理和ssh登录总是不安全,通过源IP限制有效加强服务器访问防护。
原理:通过HTTP服务将要授权的源IP加入白名单,后台程序将白名单中的IP加入代理和ssh等应用的授权中。

1. 用nginx和lua实现简单白名单添加服务
nginx配置lua

server {  
        listen 80 default_server;

        root /data0/site;

        location ~ \.lua {
                default_type text/plain;
                lua_code_cache on;
                content_by_lua_file $document_root/$uri;
                access_log off;
        }
}


lua代码

local secret_key = "yourkey"  
local arg_key = ngx.var.arg_key

if arg_key ~= secret_key then  
    ngx.status = ngx.HTTP_FORBIDDEN
    ngx.header.content_type = "text/html"
    ngx.say("<html><body><h1>Forbidden</h1></body></html>")
    ngx.exit(ngx.HTTP_FORBIDDEN)
end

local fp = io.open(string.format("%s/data/client.txt", ngx.var.document_root), "r")  
if fp ~= nil then  
    for line in fp:lines() do
        if line == string.format("%s", ngx.var.remote_addr) then
            ngx.say("Repeat")
            ngx.exit(ngx.HTTP_OK)
        end
    end
    fp:close()
end

fp = io.open(string.format("%s/data/client.txt", ngx.var.document_root), "a")  
fp:write(string.format("%s\n", ngx.var.remote_addr))  
fp:close()  
ngx.say("OK")  


接口会自动获取请求的源IP地址并添加之白名单/data0/site/data/client.txt中,添加实例

$ curl http://yoursite.net/client.lua?key=yourkey
OK  
$ curl http://yoursite.net/client.lua?key=yourkey
Repeat  

如果参数key值不是定义的yourkey直接返回Forbidden,第一次添加返回OK,重复添加返回Repeat

2. 后台程序修改应用配置
python程序代码

#!/usr/bin/python
import sys  
import os  
import re  
import hashlib  
import time


def diffconf(conf, newconf):  
    with open(conf, "r") as fp:
        old = hashlib.md5(fp.read()).hexdigest()
    new = hashlib.md5(newconf).hexdigest()
    if new == old:
        return 0
    return 1


def createconf(conf, safeconf):  
    fp = open(conf, "r")
    newconf = ""
    start = 0
    while True:
        line = fp.readline()
        if not line:
            break
        if re.match("#safeend", line):
            start = 0
        if start == 1:
            continue
        if re.match("#safeclient", line):
           start = 1
           line += safeconf
        newconf += line
    fp.close()
    return newconf


def squidconf(clients):  
    conf = "/etc/squid3/squid.conf"
    safeconf = ""
    for client in clients:
        safeconf += "acl safeclient src {}/32\n".format(client)
    newconf = createconf(conf, safeconf)
    if diffconf(conf, newconf) == 0:
        return
    with open(conf, "w") as f:
        f.write(newconf)

    os.system("/etc/init.d/squid3 reload")


def sshdconf(clients):  
    conf = "/etc/ssh/sshd_config"
    safeconf = ""
    for client in clients:
        safeconf += "AllowUsers debian@{}\n".format(client)
    newconf = createconf(conf, safeconf)
    if diffconf(conf, newconf) == 0:
        return
    with open(conf, "w") as f:
        f.write(newconf)

    os.system("/etc/init.d/ssh reload")

def iptables_ssh(clients):  
    for client in clients:
        os.system("/sbin/iptables -t filter -D INPUT -p tcp --src {0}/32 --dport 22 -j ACCEPT".format(client))
        os.system("/sbin/iptables -t filter -A INPUT -p tcp --src {0}/32 --dport 22 -j ACCEPT".format(client))
    os.system("/sbin/iptables -t filter -D INPUT -p tcp --src 192.168.0.0/24 --dport 22 -j ACCEPT")
    os.system("/sbin/iptables -t filter -A INPUT -p tcp --src 192.168.0.0/24 --dport 22 -j ACCEPT")
    os.system("/sbin/iptables -t filter -D INPUT -p tcp --dport 22 -j DROP".format(client))
    os.system("/sbin/iptables -t filter -A INPUT -p tcp --dport 22 -j DROP".format(client))


def main():  
    clientfile = "/data0/site/data/client.txt"
    if not os.access(clientfile, os.R_OK):
        sys.exit(1)

    fp = open(clientfile, "r")
    clients = set(fp.read().strip().split("\n"))
    squidconf(clients)
    sshdconf(clients)
    iptables_ssh(clients)

    tm = time.localtime()
    if tm.tm_hour == 0 and tm.tm_min == 0:
        os.remove(clientfile)


if __name__ == "__main__":  
    main()

程序会根据白名单client.txt中的IP地址去修改代理squidssh的配置文件并reload服务,每天零点清除白名单,程序使用cron每分钟跑一次,所以添加IP后,要下一分钟才生效
ssh配置/etc/ssh/sshd_config被添加

#safeclient
AllowUsers debian@clientip1  
AllowUsers debian@clientip2  
#safeend

squid配置/etc/squid3/squid.conf被添加

#safeclient
acl safeclient src clientip1/32  
acl safeclient src clientip2/32  
#safeend


iptables添加的防火墙规则

-A INPUT -s clientip1/32 -p tcp -m tcp --dport 22 -j ACCEPT
-A INPUT -s clientip2/32 -p tcp -m tcp --dport 22 -j ACCEPT
-A INPUT -s 192.168.0.0/24 -p tcp -m tcp --dport 22 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 22 -j DROP

不存在绝对安全,但是可以通过一些技巧增加系统复杂度,有效加强防护。