對URL進行安全驗證
雖然我們已經實現了重定向會上一個頁面的功能,但是安全問題不容忽視,鑒於referer和next容易被串篡改的特性,我們需要對這些值進行驗證,否則會形成開放重定向漏洞
以URL中的next參數為例,next變量以字符串的形式寫在url里,因此任何人都可以發給某個用戶一個包含next變量指向任何站點的連接,那么就會誤導用戶進入釣魚網站。
我們可以驗證next變量指向的url地址是否屬於我們的應用內,否則不允許重定向。
確保URL安全的關鍵是判斷URL是否屬於程序內部,可以通過判斷url的host、協議等信息是否和程序內部的url一致,如果一致則認識是可信的url
代碼中is_safe_url()方法接受目標URL作為參數,通過request.host_url獲取程序內部的主機URL,然后使用urljoin()函數將目標URL轉為絕對URL。接着,分別使用urlparse模塊提供的urlparse()解析兩個url,最后對目標url的url模式和主機地址進行驗證,確保只屬於程序內部的url才會被返回。
在執行重定向會上一個頁面的redirect_back()函數中,使用is_safe_url()驗證next和referer的值
from urlparse import urlparse, urljoin #python3需要從urllib.parse導入
from flask import request
@app.route('/bar')
def bar():
print "request.full_path:",request.full_path
return '<h1>Bar page</h1><a href="%s">Do something and redirect </a>' % url_for('do_something', next = request.full_path)
@app.route('/do_something_and_redirect')
def do_something():
return redirect_back()
def is_safe_url(target):
print "request.host_url:",request.host_url
ref_url = urlparse(request.host_url)
print "ref_url:",ref_url
print "target:",target
test_url = urlparse(urljoin(request.host_url, target))
print "test_url:",test_url
print "ref_url.netloc:",ref_url.netloc
print "test_url.netloc:",test_url.netloc
print "test_url.scheme:",test_url.scheme
return test_url.scheme in ('http', 'https') and ref_url.netloc ==test_url.netloc
def redirect_back(default = 'hello',**kwargs):
for target in request.args.get('next'),request.referrer:
if target:
if is_safe_url(target):
return redirect(target)
return redirect(url_for(default,**kwargs))
if __name__ == '__main__':
app.run(debug = True)
結果:
控制台輸出:
request.host_url: http://127.0.0.1:5000/
ref_url: ParseResult(scheme=u'http', netloc=u'127.0.0.1:5000', path=u'/', params='', query='', fragment='')
target: /bar?
test_url: ParseResult(scheme=u'http', netloc=u'127.0.0.1:5000', path=u'/bar', params='', query='', fragment='')
ref_url.netloc: 127.0.0.1:5000
test_url.netloc: 127.0.0.1:5000
test_url.scheme: http
request.full_path: /bar?
頁面: