没有 CSRF 的 Flask-Security 令牌登录 - 差不多了,但还不完全
Flask-Security token login without CSRF - Almost there but not quite
我在这方面投入了数小时,并且确信我有一个解决方案,考虑到许多未解决的问题,这对这里的许多人都有用 - 如果你帮助我完善它
我有一个 flask Web 应用程序,它也用作我的 android 应用程序的后端。
我想在不全局禁用 CSRF 保护的情况下使用令牌身份验证来保护我的 API 端点。
在所有选项 运行 出局后,我决定修改 Flask-security 以达到我的目的。
这是我的分支。 https://github.com/mnjenga/flask-security
简而言之,我创建了一个额外的视图 /api/login,它呈现一个 CSFR 被禁用的登录表单(仅该特定表单)。所有其他视图,包括 /login(在我的分支中,我已将其修改为 /account/login)保留其 CSRF 保护。现在,当我使用正确的凭据 post 到 /api/login 时,我得到了我的令牌而没有错误,我可以将其用于任何其他请求。登录 API post 到 /account/login return 出现预期错误,因为视图仍受保护。
我现在要实现的是确保 /api/login 视图无法从浏览器访问或接受任何基于会话的身份验证(或者它是否安全,因为它不 return cookie 只是一个标记,我可以禁用非 json posts?)
的处理
这是 /api/login 视图的样子
@anonymous_user_required
def api_login():
"""View function for api_login view"""
form_class = _security.api_login_form
if request.is_json:
form = form_class(MultiDict(request.get_json()))
else:
form = form_class(request.form)
if form.validate_on_submit():
login_user(form.user, remember=form.remember.data)
after_this_request(_commit)
if not request.is_json:
return redirect(get_post_login_redirect(form.next.data))
if request.is_json:
return _render_json(form, include_auth_token=True)
return _security.render_template(config_value('LOGIN_USER_TEMPLATE'),
login_user_form=form,
**_ctx('login'))
我目前的想法围绕着只制作视图过程 POST 方法,替换
else:
form = form_class(request.form)
(return这里有错误)
使浏览器表单不被处理,并去除表单渲染。
我现在睡的头都快炸了,希望醒来能听到好消息
这就是我最终完成的方式
@anonymous_user_required
def api_login():
"""View function for login view"""
form_class = _security.api_login_form
if request.is_json:
form = form_class(MultiDict(request.get_json()))
if form.validate_on_submit():
login_user(form.user, remember=form.remember.data)
after_this_request(_commit)
else:
return jsonify(*get_message('INVALID_LOGIN_ATTEMPT'))
if request.is_json:
return _render_json(form, include_auth_token=True)
return jsonify(*get_message('INVALID_LOGIN_ATTEMPT'))
这确保只处理 json 个帖子,网站中的所有其他内容都受到 CSRF 保护。
我可以拿到我的token了(这里我用过ipython)
In [6]: r = requests.post('http://127.0.0.1:5000/api/login', data=json
...: .dumps({'email':'me@mine.com', 'password':'goodpw'}), header
...: s={'content-type': 'application/json'})
In [7]: r.json()
Out[7]:
{'meta': {'code': 200},
'response': {'user': {'authentication_token':
'WyIyIiwiJDUkcm91bmRzPTUzNTAwMCRMUFBteW9sa0p0b0d3eWFBJGFZakdESE9ZeHBrVEJ1YUN4ZC52QVI4VmtPa0x4bEYzSEhwRGM3b1lqdzYi
XQ.DTDLqw.DtFvINasBL6SyT2w2xpyOkWnnIk',
'id': '2'}}}
在我的正常登录视图上尝试相同的操作return如预期的那样出错
In [8]: r = requests.post('http://127.0.0.1:5000/account/login', data=
...: json.dumps({'email':'me.mine.com', 'password':'goodpw'}), he
...: aders={'content-type': 'application/json'})
In [9]: r.json()
Out[9]:
{'meta': {'code': 400},
'response': {'errors': {'csrf_token': ['The CSRF token is missing.']}}}
我现在计划在某个时候做同样的注册。
如果你想测试这个分支,你可以通过 pip
安装它
pip install git+https://github.com/mnjenga/flask-security
我在这方面投入了数小时,并且确信我有一个解决方案,考虑到许多未解决的问题,这对这里的许多人都有用 - 如果你帮助我完善它
我有一个 flask Web 应用程序,它也用作我的 android 应用程序的后端。 我想在不全局禁用 CSRF 保护的情况下使用令牌身份验证来保护我的 API 端点。
在所有选项 运行 出局后,我决定修改 Flask-security 以达到我的目的。 这是我的分支。 https://github.com/mnjenga/flask-security
简而言之,我创建了一个额外的视图 /api/login,它呈现一个 CSFR 被禁用的登录表单(仅该特定表单)。所有其他视图,包括 /login(在我的分支中,我已将其修改为 /account/login)保留其 CSRF 保护。现在,当我使用正确的凭据 post 到 /api/login 时,我得到了我的令牌而没有错误,我可以将其用于任何其他请求。登录 API post 到 /account/login return 出现预期错误,因为视图仍受保护。
我现在要实现的是确保 /api/login 视图无法从浏览器访问或接受任何基于会话的身份验证(或者它是否安全,因为它不 return cookie 只是一个标记,我可以禁用非 json posts?)
的处理这是 /api/login 视图的样子
@anonymous_user_required
def api_login():
"""View function for api_login view"""
form_class = _security.api_login_form
if request.is_json:
form = form_class(MultiDict(request.get_json()))
else:
form = form_class(request.form)
if form.validate_on_submit():
login_user(form.user, remember=form.remember.data)
after_this_request(_commit)
if not request.is_json:
return redirect(get_post_login_redirect(form.next.data))
if request.is_json:
return _render_json(form, include_auth_token=True)
return _security.render_template(config_value('LOGIN_USER_TEMPLATE'),
login_user_form=form,
**_ctx('login'))
我目前的想法围绕着只制作视图过程 POST 方法,替换
else:
form = form_class(request.form)
(return这里有错误)
使浏览器表单不被处理,并去除表单渲染。
我现在睡的头都快炸了,希望醒来能听到好消息
这就是我最终完成的方式
@anonymous_user_required
def api_login():
"""View function for login view"""
form_class = _security.api_login_form
if request.is_json:
form = form_class(MultiDict(request.get_json()))
if form.validate_on_submit():
login_user(form.user, remember=form.remember.data)
after_this_request(_commit)
else:
return jsonify(*get_message('INVALID_LOGIN_ATTEMPT'))
if request.is_json:
return _render_json(form, include_auth_token=True)
return jsonify(*get_message('INVALID_LOGIN_ATTEMPT'))
这确保只处理 json 个帖子,网站中的所有其他内容都受到 CSRF 保护。
我可以拿到我的token了(这里我用过ipython)
In [6]: r = requests.post('http://127.0.0.1:5000/api/login', data=json
...: .dumps({'email':'me@mine.com', 'password':'goodpw'}), header
...: s={'content-type': 'application/json'})
In [7]: r.json()
Out[7]:
{'meta': {'code': 200},
'response': {'user': {'authentication_token':
'WyIyIiwiJDUkcm91bmRzPTUzNTAwMCRMUFBteW9sa0p0b0d3eWFBJGFZakdESE9ZeHBrVEJ1YUN4ZC52QVI4VmtPa0x4bEYzSEhwRGM3b1lqdzYi
XQ.DTDLqw.DtFvINasBL6SyT2w2xpyOkWnnIk',
'id': '2'}}}
在我的正常登录视图上尝试相同的操作return如预期的那样出错
In [8]: r = requests.post('http://127.0.0.1:5000/account/login', data=
...: json.dumps({'email':'me.mine.com', 'password':'goodpw'}), he
...: aders={'content-type': 'application/json'})
In [9]: r.json()
Out[9]:
{'meta': {'code': 400},
'response': {'errors': {'csrf_token': ['The CSRF token is missing.']}}}
我现在计划在某个时候做同样的注册。 如果你想测试这个分支,你可以通过 pip
安装它pip install git+https://github.com/mnjenga/flask-security