安全認證代理的透明接入
背景
之前在sina做一個移動辦公應用的安全對外發布代理(新浪口袋)時,是在openresty中的location中專門提供了認證的介面,app需要認證時將認證信息全部發給代理,在代理層進行動態口令與靜態口令的認證。
認證通過後,再由代理在header中附加了認證信息給後端。現在又接到了類似項目,就改為了透明接入的方式,現有的客戶端與伺服器端只需做很少的改動就能接入。
不方便多說,只簡單提一下:
- 安全代理層與後端共有2重的身份認證,訪問後端伺服器時,如果代理層的身份認證沒通過則返回一個特定的json串,客戶端app就知道該發起登錄認證的請求了。
- 認證的介面是在白名單中放行的,不做訪問控制,但是代理會劫持請求的響應信息,通過後端伺服器的返回結果,代理便可判斷用戶是否登錄成功,是否頒發有實效的token。
openresty中的配置
openresty的配置大致如下:
upstream proxy_app.xsec.io {n server 1.1.1.1:443;n }nn server {n listen 443;n server_name app.xsec.io;n client_max_body_size 100m;n charset utf-8;n access_log /var/log/nginx/app.xsec.io-access.log Merpproxy;n error_log /var/log/nginx/app.xsec.io-debug.log debug;nn location ~* ^/(login/CheckPhone|login/checkCode|APP) {n proxy_connect_timeout 360s;n proxy_read_timeout 5400s;n proxy_send_timeout 5400s;n proxy_pass_header Server;n proxy_set_header Host $http_host;n proxy_redirect off;n proxy_set_header X-Real-IP $remote_addr;n proxy_set_header X-Scheme $scheme;n proxy_pass http://proxy_app.xsec.io;n }nn location ~* ^/login/CheckLdap {nn content_by_lua n helper.get_post_info()n ;nn header_filter_by_lua n local result, username, device_info = helper.chk_login()n local timestamp = ngx.time()n local secure_key = config.access_key.keyn local sign = access_key.make_sign(secure_key, timestamp)nn if result thenn local resp = access_key.create_key(username, device_info, key, sign, timestamp, 0)n -- ngx.log(ngx.DEBUG, string.format("resp:%s, resp.text:%s, type:%s", resp, resp.text, type(resp.text)))n -- helper.make_resp(resp)n ngx.ctx.resp = resp or {}n helper.make_cookies(resp)n endn ;nn body_filter_by_lua n local body = helper.get_resp_body()n ngx.log(ngx.DEBUG, string.format("body:%s, type of body:%s", body, type(body)))n local resp = ngx.ctx.resp or {}n ngx.log(ngx.DEBUG, string.format("resp:%s, resp.text:%s, type:%s", resp, resp.text, type(resp.text)))n helper.make_resp(body, resp)n ;nn proxy_set_header authorization xsec_security;n proxy_pass_header Server;n # proxy_set_header Host $http_host;n proxy_set_header Host proxy_app.xsec.io;n proxy_redirect off;n proxy_set_header X-Real-IP $remote_addr;n proxy_set_header X-Scheme $scheme;n proxy_pass $scheme://proxy_app.xsec.io;n }n error_page 404 /index.html;n error_page 500 502 503 504 /index.html;n }nn# http protocolnserver {n listen 80;n ssl off;n server_name app.xsec.io;n rewrite ^(.*) https://proxy_app.xsec.io/$1 permanent;n }n
代碼解讀
- location ~* ^/(login/CheckPhone|login/checkCode|APP)是設備激活階段需要的簡訊驗證碼獲取及輸入階段,不做攔截
location ~* ^/login/CheckLdap是輸入加密的ldap密碼階段,我們在透明接入就實現在這部分:
- content_by_lua階段中獲取了用戶的登錄信息,比如用戶名、設備信息等
- header_filter_by_lua階段判斷了用戶是否登錄成功(成功的話伺服器會set-cookie,否則不會set-cookie),也可以放在body_filter_by_lua階段,根據伺服器返回的json判斷
- 登錄成功的話,代理伺服器會生成與賬戶、設備唯一綁定的認證key,並設備cookies
- 將認證key保存到ctx中,方便在body_filter_by_lua階段中使用
- body_filter_by_lua階段中攔截了伺服器返回的json,反序列化後將代理的認證信息插入後再以json的方式發給客戶端
客戶端激活成功後,不再使用ldap(ldap一旦泄漏,所有內網的系統都可以登錄了),只使用代理維護的key與totp進行雙因素認證。
推薦閱讀:
※黑產拿下萬台IoT設備許可權,用來群發垃圾郵件
※使用超聲波「無聲」劫持語音助理系統:以Siri、Google Now為例
※Github 安全軍火庫(二)
※周鴻禕講的「大安全」到底是啥?