Research
Security News
Quasar RAT Disguised as an npm Package for Detecting Vulnerabilities in Ethereum Smart Contracts
Socket researchers uncover a malicious npm package posing as a tool for detecting vulnerabilities in Etherium smart contracts.
Much of the code here is borrowed from sanic_session.
I wanted to make some changes that would break a big part of sanic_session
's API, so I decided to create this repo instead.
Sanic cookies supports both client side and server side cookies.
Interfaces are only responsible for reading/writing the SessionDict
:
Session management logic is handled by the Session
object
No race conditions:
By using:
async with request['session']:
request['session']['foo'] = 'bar'
instead of:
request['session']['foo'] = 'bar'
It is still however possible to use the session_dict
without a context manager, but it will raise some warnings,
unless it's explicitly turned off (warn_lock=False)
Note:
The locking mechanism used here only keeps track of locks on a thread-level, which means, an application that is horizontally scaled or one that runs on more than one process won't fully benefit from the locking mechanism that sanic-cookies currently has in place and might encounter some race conditions. I have plans to introduce a distributed locking mechanism. Probably using something like: Aioredlock. But for now, you should know that the locking mechanism that is currently in place will not work in a multi-process environment.
A simpler implementation of SessionDict that helps me sleep in peace at night. (Probably less performant)
In memory interface schedules cleanup to avoid running out of memory
Encrypted client side cookie interface
Ability to add more than one interface to the same session
Authenticated Session implementation
$ pip install sanic_cookies
from sanic_cookies import Session, InMemory
from sanic import Sanic
app = Sanic()
Session(app, master_interface=InMemory())
@app.route('/')
async def handler(request):
async with request['session'] as sess:
sess['foo'] = 'bar'
from sanic_cookies import Session, InMemory, Aioredis
from sanic import Sanic
inmem = InMemory()
aioredis = AioRedis(aioredis_pool_instance)
app = Sanic()
sess = Session(app, master_interface=inmem, session_name='my_1st_sess')
sess.add_interface(aioredis)
@app.route('/')
async def index(request):
async with request['my_1st_session'] as sess:
sess['foo'] = 'bar'
# At this point 'foo' = 'bar' is written both to the inmemory
# interface and the aioredis interface
async with request['my_1st_session'] as sess:
# When reading, your session will always read from the "master_interface"
# In that case it's the inmem interface
assert sess['foo'] == 'bar'
# Such pattern can be useful in many cases
# e.g. you want to share your session information with an analytics team
from sanic_cookies import Session, AuthSession, InMemory, InCookieEncrypted, AioRedis
from sanic import Sanic
inmem = InMemory()
aioredis = Aioredis(aioredis_pool_instance)
incookie = InCookieEncrypted(b'fernetsecretkey')
app = Sanic()
incookie_session = Session(
app,
master_interface=incookie,
session_name='incookiesess',
cookie_name='INCOOKIE'
)
generic_session = Session(
app,
master_interface=inmem,
session_name='session',
cookie_name='SESSION'
)
auth_session = AuthSession(
app,
master_interface=aioredis,
session_name='auth_session',
cookie_name='SECURE_SESSION'
)
# for production (HTTPs) set `secure=True` in your auth_session,
# but this will fail in local development
@app.route('/')
async def index(request):
async with request['incookie_session'] as sess:
sess['foo'] = 'bar'
async with request['session'] as sess:
sess['bar'] = 'baz'
async with request['auth_session'] as sess:
sess['baz'] = 'foo'
Following up on the previous example:
from sanic_cookies import login_required
@app.route('/login')
async def login(request):
# 1. User verification logic
# both will work (Whatever is json serializble will)
# If you want to pickle an object simply change the default
# encoder&decoder in the interfaces plugged in to your AuthSession
authorized_user = 123
authorized_user = {'user_id': 123, 'email': 'foo@bar.baz'}
# 2. Login user
# Here we access the session object
# (not the session dict that is accessible from the request) from the app
await request.app.exts.auth_session.login_user(request, authorized_user)
# 3. Use the session dict safely and exclusively for the logged in user
async with request['auth_session'] as sess:
sess['foo'] = 'bar'
current_user = sess['current_user']
assert current_user == await request.app.exts.auth_session.current_user()
@app.route('/logout')
async def logout(request):
async with request['auth_session'] as sess:
assert sess['foo'] == 'bar' # From before
await request.app.exts.auth_session.logout_user(request) # Resets the session
async with request['auth_session'] as sess:
assert sess.get('foo') is None # should never fail
assert sess.get('current_user') is None # should never fail
@app.route('/protected')
@login_required()
async def protected(request):
assert await request.app.exts.auth_session.current_user() is not None # should never fail
In memory
from sanic_cookies import Session, InMemory
from sanic import Sanic
interface = InMemory()
app = Sanic()
Session(app, master_interface=interface)
# You can skip this part if you don't want scheduled interface cleanup
@app.listener('before_server_start')
def init_inmemory(app, loop):
interface.init()
@app.listener('after_server_stop')
def kill_inmemory(app, loop):
interface.kill()
@app.route('/')
async def handler(request):
async with request['session'] as sess:
sess['foo'] = 'bar'
Aioredis
from aioredis import Aioredis
from sanic_cookies import Aioredis as AioredisInterface
from sanic import Sanic
app = Sanic()
aioredis_pool_instance = Aioredis()
aioredis = AioredisInterface(aioredis_pool_instance)
Session(app, master_interface=interface)
@app.route('/')
async def handler(request):
async with request['session'] as sess:
sess['foo'] = 'bar'
Encrypted in-cookie (using the amazing cryptography.Fernet library)
i. Open a Python terminal and generate a new Fernet key:
>>> from cryptography.fernet import Fernet
>>> SESSION_KEY = Fernet.generate_key()
>>> print(SESSION_KEY)
b'copy me to your sanic app and keep me really secure'
ii. Write your app
from sanic import Sanic
from sanic_cookies import Session, InCookieEncrypted
app = Sanic()
app.config.SESSION_KEY = SESSION_KEY
Session(
app,
master_interface=InCookieEncrypted(app.config.SESSION_KEY),
)
@app.route('/')
async def handler(request):
async with request['session'] as sess:
sess['foo'] = 'bar'
Gino-AsyncPG (Postgres 9.5+):
i. Manually create a table:
CREATE TABLE IF NOT EXISTS sessions
(
created_at timestamp without time zone NOT NULL,
expires_at timestamp without time zone,
sid character varying,
val character varying,
CONSTRAINT sessions_pkey PRIMARY KEY (sid)
);
ii. Add the interface:
from sanic import Sanic
from gino.ext.sanic import Gino
from sanic_cookies import GinoAsyncPG
from something_secure import DB_SETTINGS
app = Sanic()
app.config.update(DB_SETTINGS)
db = Gino()
db.init_app(app)
interface = GinoAsyncPG(client=db)
auth_session = AuthSession(app, master_interface=interface)
if __name__ == '__main__':
app.run(host='127.0.0.1', port='8080')
I currently work as a freelance software devloper. Like my work and got a gig for me?
Want to hire me fulltime? Send me an email @ omarryhan@gmail.com
Bitcoin: 3NmywNKr1Lzo8gyNXFUnzvboziACpEa31z
Ethereum: 0x1E1400C31Cd813685FE0f6D29E0F91c1Da4675aE
Bitcoin Cash: qqzn7rsav6hr3zqcp4829s48hvsvjat4zq7j42wkxd
Litecoin: MB5M3cE3jE4E8NwGCWoFjLvGqjDqPyyEJp
Paypal: https://paypal.me/omarryhan
FAQs
Cookies and Session Management for Sanic
We found that sanic-cookies demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Security News
Socket researchers uncover a malicious npm package posing as a tool for detecting vulnerabilities in Etherium smart contracts.
Security News
Research
A supply chain attack on Rspack's npm packages injected cryptomining malware, potentially impacting thousands of developers.
Research
Security News
Socket researchers discovered a malware campaign on npm delivering the Skuld infostealer via typosquatted packages, exposing sensitive data.