1

I am using Flask kvsession to avoid replay attacks, as the client side cookie based session used by Flask-login are prone to it. Eg: If on /index page your cookie in the header is set for your app header like myapp_session : 'value1' and if you navigate to /important page you will get a new header like myapp_session : 'value2' so if a hacker gets 'value1' he can perform replay attacks and misuse it, as it is never invalidated.

To solve this I am using flask-kvsession which stores the session cookie header value in a cache or some backend. SO basically only one myapp_session is generated and invalidated when you logout. But the problem is :-

__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)

If you look at the cleanup_session part of the code for kv-session http://pythonhosted.org/Flask-KVSession/#flask_kvsession.KVSessionExtension.cleanup_sessions

It only deletes the expired sessions. But If I want to explicitly delete the value for the current myapp_session for a particular user on logout, how do I do that?

@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)

But this deletes all the keys as I don`t know what the unique key for the current session is.

Q2. Also, how to use memcache instead of redis as it doesn`t have the app.kvsession_store.keys() function and gives i/o error.

wodow
  • 3,871
  • 5
  • 33
  • 45
ramu
  • 1,325
  • 2
  • 17
  • 25

1 Answers1

3

I think I just figured the 1st part of your question on how you can delete the specific key on logout.

As mentioned in the docs:

Internally, Flask-KVSession stores session ids that are serialized as KEY_CREATED, where KEY is a random number (the sessions “true” id) and CREATED a UNIX-timestamp of when the session was created.

Sample cookie value that gets created on client side (you can check with that cookie manager extenion for firefox):

c823af88aedaf496_571b3fd5.4kv9X8UvyQqtCtNV87jTxy3Zcqc

and session id stored in redis as key:

c823af88aedaf496_571b3fd5

So on logout handler, you just need to read the cookie value, split it and use the first part of the string:

Sample Code which worked for me:

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)

and since you have added ttl_support:

store.ttl_support = True

It will match the TTL(seconds) value from permanent_session_lifetime, if you have set that in config file or in the beginning of your app.py file.

For example, in my application I have set in the beginning of app.py file as:

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

now, when I logout, it deletes the key in redis but it will not be removed until TTL for that turns to 0 from 300 (5 Min as mentioned in permanent_session_lifetime value ).

If you want to remove it from redis immediately, for that you can manually change the app.permanent_session_lifetime to 1 second, which will in turn change TTL for redis.

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)

Using the above code, I was able to thwart session replay attacks.

and solution to your 2nd question:

3 possible mistakes that I can see are:

1: In the beginning of your code you have created:

store = RedisStore(redis.StrictRedis())

but in the loop you are using it as kvsession_store instead of just store:

app.kvsession_store.keys()
  1. To use it without any errors/exceptions you can use it as store.keys() instead of 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) is not deleting the all keys, you are running it inside the loop which is one by one deleting all keys.