虽然咱们已经实现了重定向会上一个页面的功能,可是安全问题不容忽视,鉴于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)
结果:python
控制台输出:flask
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='')app
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:5000url
test_url.netloc: 127.0.0.1:5000.net
test_url.scheme: httpdebug
request.full_path: /bar?3d
页面: