如何从Flask-KVSession删除特定键(当前会话)?

时间:2015-08-14 17:17:31

标签: python session flask flask-login flask-kvsession

我正在使用Flask kvsession来避免重放攻击,因为Flask-login使用的客户端基于cookie的会话很容易受到攻击。 例如:如果在/ index页面上,您的标题中的Cookie是为您的应用标题设置的 myapp_session:' value1' 如果您导航到/重要页面,您将获得一个新标题 myapp_session:' value2'所以,如果一个黑客得到了“价值1”。他可以执行重播攻击并滥用它,因为它永远不会失效。

为了解决这个问题,我使用flask-kvsession,它将会话cookie头值存储在缓存或某些后端中。因此,当您注销时,基本上只生成一个myapp_session并使其无效。但问题是: -

__init__.py 

from simplekv.memory.redisstore import RedisStore
import redis

store = RedisStore(redis.StrictRedis())
#store = memcache.Client(['127.0.0.1:11211'], debug =0)
store.ttl_support = True
app = create_app(__name__)
current_kvsession = KVSessionExtension(store, app)

如果你看一下kv-session代码的cleanup_session部分 http://pythonhosted.org/Flask-KVSession/#flask_kvsession.KVSessionExtension.cleanup_sessions

它只删除过期的会话。但是如果我想在注销时为特定用户显式删除当前myapp_session的值,我该怎么做?

@app.before_request
def redirect_if_logout():
  if request.path == url_for('logout'):
      for key in app.kvsession_store.keys():
        logger.debug(key)
        m = current_kvsession.key_regex.match(key)
        logger.debug('found %s', m)
        app.kvsession_store.delete(key)

但这会删除所有密钥,因为我不知道当前会话的唯一密钥是什么。

Q2。另外,如何使用memcache而不是redis,因为它没有app.kvsession_store.keys()函数并且给出了i / o错误。

1 个答案:

答案 0 :(得分:2)

我想我刚刚想出了关于如何在注销时删除特定密钥的问题的第一部分。

如文档中所述:

  

在内部,Flask-KVSession存储序列化为的会话ID   KEY_CREATED,其中KEY是一个随机数(会话“真”id)和   创建了创建会话的UNIX时间戳。

在客户端创建的示例cookie值(您可以使用firefox的cookie管理器扩展来检查):

  

c823af88aedaf496_571b3fd5.4kv9X8UvyQqtCtNV87jTxy3Zcqc

并将会话ID存储在redis中作为密钥:

  

c823af88aedaf496_571b3fd5

因此,在logout处理程序中,您只需要读取cookie值,拆分它并使用字符串的第一部分:

示例代码对我有用:

import redis
from flask import Flask
from flask_kvsession import KVSessionExtension
from simplekv.memory.redisstore import RedisStore

store = RedisStore(redis.StrictRedis())

app = Flask(__name__)
KVSessionExtension(store, app)

#Logout Handler
@app.route('/logout', methods=['GET'])
def logout():
    #here you are reading the cookie 
    cookie_val = request.cookies.get('session').split(".")[0]
    store.delete(cookie_val)

并且因为您添加了ttl_support:

store.ttl_support = True

如果您在配置文件或app.py文件的开头设置了该值,它将匹配permanent_session_lifetime的TTL(秒)值。

例如,在我的应用程序中,我在app.py文件的开头设置为:

session.permanent = True
app.permanent_session_lifetime = timedelta(minutes=5)

现在,当我退出时,它会删除redis中的密钥,但是直到TTL for 300从300变为0(在permanent_session_lifetime值中提到5分钟)时才会被删除。

如果你想立即从redis中删除它,为此你可以手动将app.permanent_session_lifetime更改为1秒,这反过来会改变redis的TTL。

import redis
import os
from flask import Flask
from flask_kvsession import KVSessionExtension
from simplekv.memory.redisstore import RedisStore

store = RedisStore(redis.StrictRedis())

app = Flask(__name__)
KVSessionExtension(store, app)

#Logout Handler
@app.route('/logout', methods=['GET'])
def logout():
    cookie_val = request.cookies.get('session').split(".")[0]
    app.permanent_session_lifetime = timedelta(seconds=1)
    store.delete(cookie_val)

使用上面的代码,我能够阻止会话重播攻击。

并解决您的第二个问题:

我可以看到3个可能的错误:

1:在您创建的代码的开头:

store = RedisStore(redis.StrictRedis())

但是在循环中你将它用作kvsession_store而不仅仅是store:

app.kvsession_store.keys()
  1. 要在没有任何错误/异常的情况下使用它,您可以将其用作store.keys()而不是app.store.keys():

    from flask_kvsession import KVSessionExtension
    from simplekv.memory.redisstore import RedisStore
    store = RedisStore(redis.StrictRedis())
    
    for key in store.keys():
        print key
    
  2. store.delete(key)未删除所有密钥,您在循环内运行它,逐个删除所有密钥。